planning-loop — how a rough note becomes filed, dispatchable work
Mirrored from the fleet knowledge base: wi/components/planning-loop.md
Updated
Mirrored verbatim from
utopia-models/knowledgewi/components/planning-loop.mdby the allowlisted publish pipeline. Edit it there, not here.
component: planning-loop
serves: all
runs-on: novaserver (the Architect, unix user `architect`)
adrs: [6798, 7781, 6925, 6926, 6929, 6932, 6933, 7126]
owns:
- _process/steps/
- _process/the-loop.mdplanning-loop — how a rough note becomes filed, dispatchable work
WHAT IT IS
The five-step process Tyler and the Architect run together, and the vocabulary the whole fleet uses to talk about work: PLAN above the board, Feature and issue on it. Stop it and masters keep executing whatever is already filed, then run dry — nothing else in the fleet turns an intention into a board issue.
Its one structural property is that no step is reported. Every step is derived from the Plan issue and the board: 3-5 from its Features on every render, planning (steps 1-2) from the issue being open with none filed. That is why a plan cannot lie about where it is: there is no field to lie in. The plan registry that used to carry step-1/2 events was retired (ADR-10109).
HOW IT WORKS TODAY
1 BRIEF · 2 LOOP⟳ ‖ 3 FILE · 4 DISPATCHED · 5 DONE
↑ planning ends, execution begins| # | step | derived from |
|---|---|---|
| 1 | BRIEF — Tyler's rough note, restated. No research yet | Plan issue open (label planning), no Feature linked, no ▶ comment |
| 2 | LOOP ⟳ — research ⇄ questions, repeating | the same; 1 and 2 are not told apart since the registry's brief:/agent: events were dropped |
| 3 | FILE — ≥1 issue exists for this plan | ≥1 Feature linked to the Plan issue (a sub-issue, or a Features: body line) |
| 4 | DISPATCHED — a master is executing | ≥1 referenced issue OPEN |
| 5 | DONE | every referenced issue CLOSED |
Planning is step < 3 — the OCC's Planning and Execution sections partition on that one number.
flowchart TD
N["Tyler's rough note"] --> Z["STEP ZERO — Q1 mode · Q2 portfolio · Q3 subprocess"]
Z --> B["1 BRIEF — the note, restated"]
B --> L["2 LOOP ⟳ — research ⇄ AskUserQuestion"]
L -->|"'research more'"| L
L -->|"click 'file it' · or the typed sentence"| F["file-issue.sh --chain or --wave<br/>--plan PLAN-N"]
F --> G["3 FILE — a Feature lands under the Plan issue"]
G --> D["4 DISPATCHED — sweeper starts a master"]
D --> M{"planning mode (Q1)"}
M -- "dispatch" --> S{"bound subprocess<br/>monitor: field"}
S -- "monitor: no · general · none" --> DP["DISPATCHED — involvement ends at dispatch"]
S -- "monitor: yes" --> DW["DISPATCHED — Architect holds the chain to n/n"]
M -- "interactive" --> IX["EXECUTING (interactive)"]
DP --> O["5 DONE — every referenced issue CLOSED"]
DW --> O
IX --> O
L -.->|"plan-stamp.sh · Last active"| E[("Plan issue")]
G -.-> EStep zero asks three ORDERED questions (ADR-6798): mode → portfolio → subprocess. Mode decides which
section of a catalogue exists at all; portfolio decides which catalogue. The two modes are dispatch ·
interactive (ADR-7781), and interactive is the whole name — never blocked, needs-tyler or
manual. Whether a dispatch chain is watched is not a mode and not a question: it is the bound
subprocess's monitor: yes|no frontmatter, and general / none are unwatched.
Two things end LOOP, and both are read by a mechanism rather than remembered (#6932). Every step-2
turn ends in an AskUserQuestion whose last two options are, in order, research more and
file it, move to step 3. Tyler either clicks the second — a click returns as a tool result, which
the per-turn injector structurally cannot see, so plan-loop.sh reads
tool_response.answers and only answers — or types "Plan is good, proceed with step 3, file it."
Either side matches "step 3", "file it" or "proceed" (plan_step.is_exit, #10772). An approving
remark is neither. Neither exit advances the step: filing does — and once the Plan issue has filed
anything, plan-loop.sh and the per-turn injector stay silent (planning steps only, #10772).
The Plan issue is the only record of a planning session (PLAN-405 P4, ADR-9839). /plan-start opens it
after its three answers (plan-open.sh open): label planning, the board's Portfolio · Mode · Recipe ·
Last active set, a <project>/work/specs/<issue#>-<slug>/ skeleton published, and the issue written into
the session's state file ~/.claude/state/plan-issue/<sid>. plan-stamp.sh keeps Last active at most
180 s stale; /plan-continue resumes from the issue alone (plan-open.sh resume [N]). Parked = label
parked; archived = closed as not planned. The plan registry that ran beside it was retired (ADR-10109).
/plan-close (plan-open.sh close [N] [--check], Feature #10062) closes it: a dispatch plan needs every
Feature filed and dispatched and lists what still runs in one <!-- plan-close --> comment; an
interactive plan refuses (exit 3) while a sub-issue is open; a closed issue is left untouched.
/plan-park (plan-open.sh park --unparks "<condition>") adds parked and writes the condition into the body.
Filing is one command, and its shape is a real choice. --chain LINEARIZES (task k blocked_by
k-1); --wave files parallel groups where each group waits on the whole of the previous one. A plan
whose design is five waves filed as a --chain has exactly one dispatchable issue. file-issue.sh now
REFUSES a --chain of ≥3 tasks whose bodies name no file in common and prints the --wave rewrite;
--allow-serial supplies the missing reason.
The loop ends at dispatch — unless the bound subprocess says monitor: yes, in which case the
Architect holds the chain to completion with a Monitor that exits at n/n. Steps 1-2 of the next plan
run concurrently with the execution of the last; the sweeper, the reaper and the announcer carry the tail. Watching a master is indistinguishable
from not trusting it.
🔴 The step-4 MODE is not the planning mode, and the two words collide. The planning mode is Q1 of step zero and decides which subprocesses exist; the step-4 MODE is what the board shows. The mapping is one table in the doctrine file this component owns.
BOUND VALUES
Re-derived from the repo by docs-cog.sh --check on every PR.
- ✅
_process/steps/— directory - ✅
_process/the-loop.md - ✅
plan-loop.sh— still called by_process/steps/ - ✅
file-issue.sh— still called by_process/steps/ - ✅
--wave— still called by_process/steps/ - ✅
--chain— still called by_process/steps/ - ✅
3— still live in_infra/scripts/file-issue.sh(\[ "\$SHAPE_N" -ge (\d+) \])
DETERMINE CURRENT STATE
| question | command |
|---|---|
| where is plan N, really | gh issue view <plan#> --repo utopia-models/knowledge (its sub-issues + Features: line) |
| every open plan | gh issue list --repo utopia-models/knowledge --label planning --state open |
| what shape would this filing take | bash _infra/scripts/file-issue.sh --help |
| do the hooks that derive steps 1-2 exist on this box | ls ~/.claude/plugins/cache/fleet-doctrine/fleet-doctrine/*/scripts/ | grep -E 'plan-loop|plan-stamp|plan-open|project-session' |
| which plugin version is installed here | jq -r '.plugins["fleet-doctrine@fleet-doctrine"][0].version' ~/.claude/plugins/installed_plugins.json |
is every box on main's payload | bash _infra/scripts/plugin-deploy-check.sh |
The planning hooks (project-session.sh, plan-loop.sh, userpromptsubmit-plan-issue.sh) and the
Plan-issue scripts (plan-open.sh, plan-stamp.sh) ship in the fleet-doctrine plugin,
not in this repo — a different repo with its own version gate. Nothing about their content is stated
here; the probes above read them where they actually are.
KNOWN BROKEN
- ⚠ Nothing binds the two doctrine files to each other.
planning-vocab.mdis the master-facing compaction ofplanning-loop.md, and a rule changed in one is not checked against the other — the~/.claude/rules/planning-loop.mdsymlink resolves to a different file per class, by design (#5341). A contradiction between them is invisible to CI and shows up as a master doing the Architect's job or vice versa. - ⚠ The loop's own machinery is not gradable from this repo. Everything that derives steps 1-2 is in
utopia-models/fleet-plugins, version-gated per box, sodocs-cog.shcan bind the doctrine and never the mechanism.plugin-deploy-check.shis the only thing that reads the population, and it is run by hand.