The planning loop
Five steps take a rough note to filed, dispatchable work, and nobody reports any of them. Each step is derived from an event or from the board, so a plan has no field that could hold a wrong value.
Updated
in-flux
Learn the derived five-step loop
Reads this page and its vocabulary twin, explains why no step can be reported, and walks one hypothetical plan through the derivation. Writes nothing.
PROMPT 1 of 2 — learn what this module teaches. You write nothing anywhere in this prompt.
ASK EVERY QUESTION WITH the `AskUserQuestion` tool, with a RECOMMENDED option first. Not prose.
Fetch and read both, in this order:
curl -s https://docs.utopiamodels.ai/docs/operating/planning-loop.md
curl -s https://docs.utopiamodels.ai/docs/operating/work.md
The second has the vocabulary (PLAN, Feature, issue); the first has the mechanism. If either fetch fails, say so and stop.
1 — EXPLAIN IT BACK, UNDER THESE HEADINGS
DERIVED, NOT REPORTED The five steps and, for each, the exact thing it is derived from. Why that means "a plan
has no field it could lie in", and why `step < 3` is the entire definition of planning.
STEP ZERO The three ordered questions — mode, portfolio, subprocess — and why the ORDER is load-bearing.
The mode literals, and why `interactive` must never become a synonym for blocked.
THE TWO EXITS The only two things that end the loop, why an approving remark is neither, and why a click
is invisible to anything that reads only what the human typed.
FILING ADVANCES Why neither exit advances the step, and what does.
WEAKEST POINTS The three weaknesses the page publishes about itself, one line each.
Quote the page where you lean on it.
2 — RUN THE DERIVATION ON A HYPOTHETICAL
Invent one plan and give it a list of events: a brief at 09:00, two planning turns, three issues filed, two of them closed. At each event, state which step the plan is at and WHICH FACT you derived it from. Then add a fourth event — the human says "looks great, ship it" — and show that the step does not move, and why.
3 — QUIZ ME
Three questions with the `AskUserQuestion` tool, one at a time, four options each, correct answer not always first. Draw from: what step 4 is derived from, why the click needs a separate hook, why the planner does not stay to watch a dispatched run, and why a count written into doctrine prose drifted twice. After each answer, quote the line that settles it.
If `AskUserQuestion` is unavailable in this session, ask the same questions as plain numbered text in one message instead.
Then say exactly this:
"Module learned. Paste prompt 2 and I will find the planning state your own system is guessing at."
Then stop.Replace typed planning status with derived status
Finds every status field in your planning artifacts, measures the drift already there, and proposes the event that should set each one. Writes only after you confirm.
PROMPT 2 of 2 — integrate this module into my own setup. Survey read-only first; propose; write only what I confirm.
HOW LONG THIS TAKES: a multi-step audit (5 steps, about 4 questions, writes only what you approve) — expect roughly 10–25 minutes across several turns. Running headless with a timeout? Budget for that, or start with a shorter prompt first. Cut off partway? Paste this prompt again — it resumes from its checklist rather than starting over.
ASK EVERY QUESTION WITH the `AskUserQuestion` tool, each with a RECOMMENDED option first and one line of why.
Reference, read it first:
curl -s https://docs.utopiamodels.ai/docs/operating/planning-loop.md
The property being adopted: every step of a plan is derived from an event or from the tracker, so nobody can type a status that is wrong.
FIRST — WRITE YOUR CHECKLIST TO A FILE
RESUMING? Before you write anything, check whether ~/PLANNING-INTEGRATE-CHECKLIST.md already exists. If it does, this prompt was interrupted: read it, tell me which steps are already ticked, and continue from the first unchecked step. Do not overwrite it, do not redo a ticked step, and do not re-ask a question whose answer it already records — the scope answer under ## Rules included, if it's there. If ## Rules has no Scope field, this checklist predates the scope question: say so plainly in your first output line and ask it now, before anything else. Only if the file does not exist, write it fresh as below.
Write ~/PLANNING-INTEGRATE-CHECKLIST.md and work from it:
# Planning loop module — integrate
- [ ] 1. Find every planning artifact
- [ ] 2. Find each status field's oracle
- [ ] 3. Measure the drift that already exists
- [ ] 4. Propose the derivation
- [ ] 5. Write only what I confirmed
## Rules
- Read only until step 5, in the repository AND in the tracker.
- Every drift finding carries the command and its raw output, so I can reproduce it.
SCOPE — ASK ME BEFORE YOU SURVEY ANYTHING OF MINE
Before step 1, ask me this with the `AskUserQuestion` tool, with both options exactly as written:
"Should I treat any path as off-limits, or do you want me to have full access to survey and propose changes anywhere in this environment?"
A — Exclude .env*, credentials and CI/deploy config (.github/workflows/, deploy keys) from anything I read or propose touching. [RECOMMENDED for most readers]
B — No exclusions. Full access to survey and propose anywhere, including secrets and CI files.
This is my preference, not a policy: some people want their agent to reach everything, some do not, and neither answer is the correct one. Never assume it and never pick for me. My answer governs every read and every proposal for the rest of this prompt. Write my answer under ## Rules in the checklist as "Scope: A" or "Scope: B", so it survives compaction. It governs the SURVEY and PROPOSE steps only — nothing gets written until step 5, and there only what I confirm.
Before you ask, decide whether an answer can reach me at all. It cannot in a one-shot non-interactive run — `claude -p`, `codex exec`, `gemini -p`, a scripted or CI invocation — and you can tell without guessing: the `AskUserQuestion` tool is missing from your tool list there, while an interactive session has it. It also cannot if the question comes back immediately with no real answer. In either case do not ask, do not wait and do not re-ask: a question asked as plain text in a one-shot run ends the run with nothing done. This is the one case where you pick for me: treat A as my answer, record and hold it exactly as above, and make the first line of your output exactly: "No interactive scope answer available — defaulted to A (excluded .env*, credentials and CI/deploy config). To choose B, re-run this prompt in an interactive session and answer the scope question."
Only if the `AskUserQuestion` tool is in your tool list but fails when you call it, ask the same question as plain numbered text in one message instead.
1 — FIND EVERY PLANNING ARTIFACT
ROADMAP / PLAN / TODO / BACKLOG / MILESTONE files · an RFC or design directory and whether its documents carry a status · issue templates and which fields they ask a human to fill · project board config in the repo · the changelog, generated or hand-written. For each: path, and how it is maintained (hand-edited, generated, unknown).
2 — FIND EACH STATUS FIELD'S ORACLE
For every checkbox, Status:, phase marker, Done column or percentage:
What event would make it FALSE? (a merged pull request, a deleted file, a deploy)
Is anything watching for that event? Quote the hook or workflow if it exists.
If nothing is — how would anyone find out? "Someone would notice in review" means the field is decorative.
3 — MEASURE THE DRIFT, DO NOT THEORIZE
For at least ten items: compare the recorded status against git history. For any document carrying a date, compare it to `git log -1 --format=%ci -- <path>`. For any COUNT written into prose ("our 5 services"), go count the thing and show both numbers side by side — the page's own doctrine drifted exactly this way, twice.
4 — PROPOSE THE DERIVATION
A table: field · where it lives · what falsifies it · what watches for that · DERIVED or TYPED.
Then map my process onto the five steps — BRIEF, LOOP, FILE, DISPATCHED, DONE — and for each say which event in MY system would derive it (an issue opened with a label, a PR merged with a closing keyword, all child issues closed). Where my system has no such event, say so; that gap is the finding.
Recommend the ONE typed field whose switch to derived buys the most, and the concrete mechanism: which event, watched by what, writing where. Ask me with the `AskUserQuestion` tool whether to build it, RECOMMENDED: yes, as a check that reports drift before it is allowed to rewrite anything.
5 — WRITE ONLY WHAT I CONFIRMED
Create only accepted files. Never edit an existing planning document without asking first, and never change tracker state in this session. If something does not work, say so and stop.
When the writes are done, tell me in one line, filled in with the real paths:
"To undo, delete `~/PLANNING-INTEGRATE-CHECKLIST.md` and <each file created in step 5, by path> — nothing else on your system was touched."
If I approved an edit to a file you did not create, name that file in the same line with the command that reverts it (`git checkout -- <path>` if uncommitted) instead of claiming nothing else was touched.
FINISH
Every file created with its path, the drift you measured with its reproducing commands, and the one field that is now derived. For the board side of this (which fields an agent should write at all) see https://docs.utopiamodels.ai/docs/operating/board.md.This page comes from the fleet's own component document for planning-loop. It is marked in-flux, not
stable, for three reasons. It has collected seven decision records. Its own doctrine file states a count
that the files on disk have already outgrown. And the hooks that derive its first two steps ship in a
separately versioned package that nothing in the repository can check.
This is the process that a human and the planning agent run together, and its vocabulary is the one the rest of the fleet uses to talk about work. If you stopped it, every agent would keep executing whatever is already filed and then run out of work, because nothing else in the organization turns an intention into a board issue.
What the five steps mean is on How work flows. This page is about the one structural property that makes them trustworthy.
No step is reported. Every step is derived
1 BRIEF · 2 LOOP ⟳ ‖ 3 FILE · 4 DISPATCHED · 5 DONE
↑ planning ends, execution begins| # | Step | Derived from |
|---|---|---|
| 1 | BRIEF | a brief event, with its timestamp, on the plan's registry entry |
| 2 | LOOP ⟳ | at least one recorded planning-agent turn on that entry |
| 3 | FILE | an issue reference on that entry |
| 4 | DISPATCHED | at least one referenced issue still open |
| 5 | DONE | every referenced issue closed |
So a plan cannot report the wrong step, because it has no field where anyone records the step. The command center reads steps 3 through 5 off the board every time it renders. Steps 1 and 2 come from events that a hook writes as they happen, not from a summary written afterwards.
step < 3 is the whole definition of planning. The command center splits its planning and execution
sections on that single number. So the line between "still thinking" and "being built" is one comparison,
not a judgement anyone makes.
Step zero asks three ordered questions, and the order is load-bearing
Before step 1 there is a step zero. It asks for the mode, then the portfolio, then the subprocess. The order matters because each answer narrows the next. The mode decides which section of a catalogue exists at all, and the portfolio decides which catalogue.
There are exactly two modes, and their names are fixed literals, not descriptions:
| Mode | What it means |
|---|---|
dispatch | agents execute the work, and the planning agent stops being involved at dispatch unless the chosen subprocess says otherwise |
interactive | the human and the planning agent work it in session, with the human in it |
Nobody is asked whether a dispatched chain is watched. The answer is read from a monitor: yes|no field on
the subprocess chosen at the third question. There used to be two dispatch modes, one monitored and one
not. We merged them because the monitored mode repeated a fact the subprocess already held, and the two
could contradict each other.
interactive is the whole name. It is not needs-human, not blocked and not manual, and above all it
does not mean blocked. It is a mode for work that is running with a person in it. Work that really cannot
run unattended is filed as interactive. It is never filed as unattended work that later reports itself
stuck.
That distinction sounds pedantic, but it is not. Once "interactive" and "blocked" mean the same thing, you can no longer tell a queue of work that is running fine with a human in it from a queue of work that is stopped, and no dashboard can separate them afterwards.
Two things end the loop, and both are read rather than remembered
Every turn in step 2 ends with a question to the human. Its last two options are, in this order, research more and file it, move to step 3. The loop ends when one of exactly two things happens:
- The human clicks the second option.
- The human types the sentence that means the same thing.
An approving remark does not end the loop, and neither does enthusiasm about the artifact.
The click is the more interesting half, because it is nearly invisible. A click comes back as a tool result, not as a message, so a per-turn injector that reads what the human said cannot see it at all. A separate hook reads the answers field of the tool response, and only that field. That hook observes the exit directly instead of guessing it from the human's tone.
Neither exit advances the step, though. Filing does. The click ends a conversation, and the step changes only when an issue exists.
Filing is one command, and its shape is a real decision
Filing either chains the work or groups it into waves, and the difference matters. A plan designed as parallel groups but filed as a chain has exactly one dispatchable issue. The mechanics, the refusal rule and the case that led to the rule are on The board.
The loop ends at dispatch
Steps 1 and 2 of the next plan run at the same time as the last plan executes. The scheduler, the reaper and the announcer handle the rest of the last plan, and the planner does not.
Watching an agent work looks exactly like not trusting it. If the only reason to stay is to see whether the run succeeds, the run already announces that on the issue. Staying only means the planner works on one plan at a time.
The step-4 mode is not the planning mode, even though they use the same words. The planning mode is the step zero question above, and it decides which subprocesses exist. The step-4 mode is what the board shows for work already dispatched. They are separate vocabularies that happen to share words. One table in doctrine maps one to the other, so nobody has to work out the mapping at the keyboard.
Where this loop is currently weakest
- A doctrine file states a subprocess count that the files on disk have outgrown. The file puts a count at the top of its own table, and a directory walk returns one more than that. The same section already has a note saying the count drifted once before, telling the reader to re-derive it instead of editing the cell. It drifted again anyway. A number in prose is a claim about the filesystem, and nothing was re-checking it.
- Nothing ties the two doctrine files to each other. One holds the full loop. The other is the shorter version that the executing agents read, and by design the same path resolves to a different file depending on the agent's class. Nothing checks a rule changed in one against the other. Continuous integration cannot see a contradiction between them. It shows up as an agent doing the planner's job, or the reverse.
- The repository that documents the loop cannot check the loop's own machinery. Everything that derives steps 1 and 2 lives in a separate package with its own version gate. So the repository's assertion checker can check the doctrine but never the mechanism. One script reads the real state across boxes, and someone has to run it by hand.
Publishing that third weakness matters more than it looks. When a process's enforcement ships on a different release schedule from its documentation, the two drift apart, and neither side can see the drift.
The board
One GitHub project board is the only tracker. An agent writes two fields, a job on a runner computes every other field, and status changes only when a merged pull request closes an issue.
The dispatch runtime
Two shell scripts and systemd make up the entire agent runtime. There is no daemon, queue or watchdog. Starting a run is the assignment, and the close-out comment is the only sign that a run is alive.