The planner
orch.py plan (implemented in planner.py) generates ralph_orchestrator/tickets.yaml
from ralph_orchestrator/SPEC.md (or --spec PATH) using the llm.planner model. If the
output file exists, --force is required to overwrite it. The planner is optional: the
identical file can be written by hand (see templates/tickets.example.yaml), in which case
orch.py check validates it directly.
Inputs
-
The spec — the text of
SPEC.md. The shipped template is a directive skeleton (Goal, Context to reuse, Acceptance criteria, Constraints, Out of scope) with the instruction to write what must be true when the work is finished. -
The repository overview — built by
planner.overview(root): the count of git-tracked files plus the first 300 (the kit’s ownralph_orchestrator/and.ralph/are excluded), and the head (2500 chars) of the first existing manifest amongREADME.md,README.rst,pyproject.toml,package.json. -
The project’s test command —
project.test_cmd(or "(none configured)"), injected so the planner can align acceptance commands with the real suite.
The prompt
prompts/planner.md casts the model as a senior software architect and requires one JSON
object {"tickets": […]} where each ticket has exactly the fields documented in
data-models.adoc#tickets-yaml. Its rules: 8–20 small tickets, each completable in one
agent session; honest depends_on (maximise parallelism, never depend on code that does not
exist yet); parallel tickets must have disjoint scopes; accept must be one real shell
command that exits 0 only when the work is done — never true or echo; first ticket is
design/analysis when the spec needs it; last ticket is regression + adversarial review;
reuse existing code, framework, style.
The repair loop
with spec + overview + repair notes] --> B[extract JSON tickets] B --> C{graph.validate:
duplicate ids, empty accept/scope,
unknown/self deps, cycles,
complexity ∈ S/M/L} C -->|valid| D[dump tickets.yaml
'REVIEW AND EDIT before running'] C -->|invalid| E{rounds < 3?} E -->|yes| F[append the error list
as 'repair' to the prompt] F --> A E -->|no| G[RuntimeError: planner
could not produce a valid plan]
Each round the model receives the previous round’s validation errors verbatim and must return
the full JSON again. Extraction strips think blocks and takes the outermost JSON object.
Output
graph.dump_tickets writes tickets.yaml with a header comment:
# Generated by orch.py plan - REVIEW AND EDIT before running.
The plan is a suggestion with teeth: orch.py check re-validates it, orch.py graph
prints it as Mermaid, and the run refuses an invalid file (INVALID tickets.yaml: with the
error list).