spec: plan-recon subagent for planner

This commit is contained in:
2026-05-11 12:12:17 +02:00
parent 5f4a75eb60
commit c680c91f5b
@@ -0,0 +1,324 @@
# Plan-recon subagent — Design Spec
**Date:** 2026-05-11
**Status:** Draft — awaiting user spec review
**Authors:** Brummel (orchestrator) + Claude
## Goal
Reduce Boss-context cost in the `planner` skill by moving the
read-heavy file-structure-mapping phase out of the Boss and into a
dedicated read-only subagent. Leave design judgement (task
decomposition, step granularity, cross-task consistency) in the
Boss. Brainstorm remains dialog-driven and gets no dedicated agent;
it can dispatch the same recon agent ad-hoc when needed.
The orchestrator-refactor milestone (`or.1`, 2026-05-11) showed that
splitting the per-task review loop into a sub-context pays back in
Boss-token budget. The same principle applies here, but more
narrowly: only the recon phase is delegated, because that is the
only phase whose output collapses cleanly into a small structured
summary.
## Architecture
Today, both `brainstorm` and `planner` run entirely in the Boss
context. Reading the per-skill SKILL.md files makes the breakdown
explicit:
- `brainstorm` is dialog-driven across nine steps. Steps 1 (project
context), 6 (write spec), and 7 (self-review) carry Read/Write
volume; everything else is user Q&A or trivial.
- `planner` is dialog-light but read- and write-heavy. Step 2 (file
structure mapping) and Step 3 (write tasks) carry the volume.
Of those phases, only one has the right shape for a subagent:
| Phase | Why it does (not) delegate |
|---|---|
| brainstorm Step 1 — project context | Read volume is moderate; what is relevant becomes clear only mid-dialogue. A subagent dispatched once-and-for-all operates on a partial picture and re-reads what the Boss must read anyway to lead Q&A. |
| brainstorm Step 6 — write spec | Spec writing is dialog kondensation. The Boss has the live conversation; handing it to a subagent means handing over the transcript, not saving tokens. |
| planner Step 2 — file structure mapping | Read-heavy (515k Boss tokens on a typical milestone), produces a compact structured summary (~500 tokens). High delegation ratio. Decomposition-independent: the Boss can run Steps 38 on the recon's output. |
| planner Step 3 — write tasks | Task decomposition IS the design work. Not delegable; the Boss must hold the cross-task picture to keep types, paths, and step granularity consistent. |
This spec ships one new subagent — `ailang-plan-recon` — and one
SKILL.md edit (`planner` Step 2). Nothing about `brainstorm` ships.
## Components
### `skills/planner/agents/ailang-plan-recon.md` (NEW)
Read-only code-and-doc-recon agent. The agent's job is: take the
parent spec and an iteration scope, walk the codebase, and return a
file-map that names every existing path, line range, function, and
type the iteration will touch, plus any anchors that DO NOT yet
exist but the spec implies.
| Field | Value |
|---|---|
| Tools | `Read, Glob, Grep, Bash` (Bash for read-only inspection — `git log`, `git grep`; never to edit) |
| Dispatched by | `planner` (primary); `brainstorm` ad-hoc when a milestone enters unfamiliar code territory |
| Carrier | `spec_path` (mandatory), `iteration_scope` (mandatory — which sections of the spec this dispatch covers), `focus_hint` (optional — e.g. "trace ctor lookup", "find all `Pattern::Lit` sites") |
| Output | Structured Markdown block, ≤1500 tokens (see "Output format" below) |
| Status protocol | `DONE` / `DONE_WITH_CONCERNS` / `NEEDS_CONTEXT` / `BLOCKED` |
#### Iron Law
```
NO PLAN WRITING. NO TASK DECOMPOSITION. NO STEP TEXT.
NAMES PATHS, LINES, FUNCTIONS, AND ANCHORS — NOT THE FIX.
NO EDITS. NOT TO CODE, NOT TO DOCS.
```
The boundary mirrors `ailang-architect`: the agent diagnoses where
work lands, the controller decides what to do with it.
#### Standing reading list
1. `CLAUDE.md` — orchestrator framing.
2. `docs/DESIGN.md` — invariants the iteration must preserve.
3. `docs/journals/INDEX.md` and the latest entries — what just
shipped, so the recon doesn't double-count fresh work.
4. `skills/planner/SKILL.md` — the role the recon serves.
The agent does NOT open `docs/plans/`; plan files are the
*output* downstream of recon, not its input.
#### Output format
```markdown
## Files
### Create
- `<path>` — <one-line responsibility>
### Modify
- `<path>:<line range>` — <one-line site description>
- relevant function: `<fn name>` at `<path>:<line>`
- cross-reference: `<other path>:<line>` (lockstep partner)
### Anchors not yet present
- `<path>` — <what the spec implies must be added but does not exist today>
## Cross-references
Any lockstep-invariant pairs (e.g. `Pattern::Lit::*` typecheck ↔
pre-desugar walker) that the iteration is likely to touch. Walk
the pairs listed in `ailang-architect`'s reading list as a starting
point.
## Open questions
Things the spec implies but the code state cannot answer alone —
flag for Boss judgement, do not invent an answer.
## Status
`DONE` | `DONE_WITH_CONCERNS` | `NEEDS_CONTEXT` | `BLOCKED` (with one-line reason)
```
#### Common Rationalisations
| Excuse | Reality |
|---|---|
| "While I'm here, let me sketch what the task would look like" | That is plan writing. Stop at the file-map; the Boss decomposes. |
| "I'll just suggest the fix in the cross-references" | A suggestion biases the Boss's design space. Name the site, not the fix. |
| "The spec is ambiguous on this point, I'll pick the obvious reading" | `NEEDS_CONTEXT` with a one-line carrier-clarification request. The Boss decides. |
| "Code search returns nothing for X, so X isn't in scope" | List X under "Anchors not yet present" with a one-line note. Absence is signal. |
#### Red Flags — STOP
- About to write a numbered task list
- About to suggest a fix in the cross-references column
- About to skip reading DESIGN.md because "I know that part"
- About to return a file-map without line ranges
- About to invent a line number you did not verify
### `skills/planner/SKILL.md` (MODIFIED)
Step 2 is replaced. The new Step 2 reads:
> ### Step 2 — Map file structure
>
> Dispatch `ailang-plan-recon` with the spec path and iteration
> scope. Read the returned file-map. Lift the relevant entries
> into the plan's "Files this plan creates or modifies" section;
> the Boss may add or amend entries that recon missed.
>
> Recon does NOT decide decomposition. Two recon dispatches per
> planner run is unusual but legitimate (e.g. one for the main spec
> sections, one with a sharper `focus_hint` for a tricky subsystem).
> Three or more is a smell — re-read the spec; the iteration scope
> is probably too broad.
The rest of the SKILL.md (Steps 1, 36, Iron Law, Handoff Contract,
Common Rationalisations) is unchanged in scope, but the "No private
agents" line in Cross-references is replaced with a one-line
reference to the new agent.
### `skills/brainstorm/SKILL.md` (MODIFIED, one paragraph)
A note in the "Cross-references" section: although `brainstorm`
itself has no private agents, the Boss may ad-hoc dispatch
`ailang-plan-recon` during Step 1 (project context) when the
milestone enters code territory the Boss has not recently read.
This is opt-in, not part of the standard process, and is documented
under "Cross-references" rather than as a step.
### `skills/README.md` (MODIFIED)
One new row in the agent roster:
```
| ailang-plan-recon | planner/agents/ | planner (primary); brainstorm (ad-hoc) |
```
The "Agents do not call other agents — one named exception" line
remains: ad-hoc dispatch from `brainstorm` is the Boss dispatching
the agent, not an agent calling another agent.
### `.claude/agents/planner` (NEW symlink)
```
.claude/agents/planner -> skills/planner/agents
```
Mirrors the existing `.claude/agents/{implement,audit,fieldtest,debug}`
pattern. Required so `subagent_type: ailang-plan-recon` resolves
during dispatch.
## Data flow
```
planner Step 1: Boss reads spec
|
v
planner Step 2: Boss dispatches ailang-plan-recon
with { spec_path, iteration_scope, focus_hint? }
|
v (file-map, <=1500 tokens)
planner Step 2: Boss lifts file-map into plan's
"Files this plan creates or modifies"
section, augments if needed
|
v
planner Steps 3-8: unchanged (task writing, header,
self-review, commit, handoff)
```
For ad-hoc dispatch from `brainstorm`, the Boss reads the file-map
into the Q&A flow but never writes a plan; the file-map informs
the design dialog and is discarded at hand-off to `planner`.
## Error handling
The agent's BLOCKED conditions:
| Condition | Carrier-level resolution |
|---|---|
| `spec_path` does not resolve | Boss fixes the path and re-dispatches. |
| `iteration_scope` is ambiguous (names a section the spec doesn't have) | Boss reframes the carrier with a precise section reference. |
| Code search returns zero candidates for a feature the spec describes | Recon returns `DONE_WITH_CONCERNS` with the absence flagged under "Anchors not yet present". Boss decides: (a) spec gap → bounce to `brainstorm`, or (b) feature is genuinely new and the spec is correct. |
| Required reading list is unreadable (DESIGN.md missing) | Recon returns `infra_blocked`. Boss fixes the working directory. |
The Boss never papers over a `BLOCKED`/`NEEDS_CONTEXT` recon by
hand-coding the file-map. That collapses the discipline.
## Testing strategy
This is a skill-system change, not a language change, so testing is
the verification-ladder pattern used by the `or.1` orchestrator-agent
spec: the first dispatches in real use are the test.
1. **First planner dispatch.** A next-iter planner run (e.g. one of
the P2 roadmap items) is executed with the new agent in place.
Confirm: the file-map produced by recon names every path the
final plan ends up creating or modifying.
2. **Token-budget delta.** End-of-session Boss-context size compared
informally against the previous planner sessions (`ct.1`, `ct.4`,
`or.1`). Goal: visible reduction, not a precise number.
3. **Plan-quality preservation.** The plan that comes out of the
first dispatch passes `implement` spec-review on Task 1 without
raising a `non_compliant` on missing paths or stale line numbers.
4. **BLOCKED handling exercise.** When a recon dispatch organically
blocks (spec gap, ambiguous scope), the Boss handles it via
carrier-clarification rather than papering over.
5. **Ad-hoc brainstorm dispatch.** First brainstorm session in
unfamiliar territory after this lands tries the ad-hoc dispatch;
confirm the agent works untouched in that context.
Steps 13 should land within the next 23 planner runs. Steps 45
get checked off when those conditions arise organically.
## Acceptance criteria
- `skills/planner/agents/ailang-plan-recon.md` exists with the
template specified in **Components**.
- `skills/planner/SKILL.md` Step 2 dispatches the new agent.
- `skills/brainstorm/SKILL.md` Cross-references section names the
ad-hoc dispatch option.
- `skills/README.md` agent roster lists the new agent.
- `.claude/agents/planner` symlink exists.
- A real planner dispatch using the agent has run, and the
verification-ladder steps 13 are recorded in the iter journal.
## Out of scope
- **Brainstorm subagents.** Rationale: dialog-driven, recon is
interwoven with Q&A. Revisit only if the ad-hoc dispatch pattern
proves insufficient.
- **Plan-writer subagent.** Rationale: task decomposition is the
design work; delegating it would defeat the point of the planner
skill. The Boss writes tasks.
- **Plan-reviewer subagent.** Rationale: today's inline self-review
(Step 5 of `planner`) works. The implement-side spec-reviewer is
the downstream gate. Adding a third reviewer would be
defensive-programming for a problem we don't have. Revisit if a
shipped plan ever passes self-review but fails implement
spec-review on Task 1 paths.
- **Recon-writeup subagent for `brainstorm` Step 6.** Rationale:
Step 6 is dialog kondensation; the Boss has the live transcript.
## Rationale: why brainstorm doesn't get its own dedicated agent
Three substantive reasons, in order of weight:
1. **Recon and dialogue are interwoven.** brainstorm Step 1 names
the project state in advance, but Step 2's Q&A reshapes which
parts of that state matter. A subagent dispatched at Step 1
reads the surface; the Boss then has to re-read the parts the
user's answers focused on. Net: more total reads, not fewer.
2. **The Boss must hold the project state to lead Q&A.** Even if a
subagent pre-digested DESIGN.md, the Boss cannot ask informed
follow-up questions without holding the same context. Delegation
here doubles the read budget rather than replacing it.
3. **Spec writing is dialog kondensation.** Step 6 produces the
spec from the live dialogue. A subagent would need the full
transcript handed to it — the very token volume we are trying
to keep out of the Boss context. The Boss is the natural
condenser because the Boss is the dialogue partner.
The asymmetry with `planner`: the planner has a phase where the
input (spec) is fixed and the output (file-map) is small and
structured. `brainstorm` has no such phase. The recon agent's
shape fits the former and not the latter.
## Naming + home
The agent lives at `skills/planner/agents/ailang-plan-recon.md`
because `planner` is the primary dispatcher. Ad-hoc dispatch from
`brainstorm` is the Boss's call, not a skill→agent transition; it
does NOT violate the "no orphan agents" rule, since `planner` is the
formal owner.
The name `ailang-plan-recon` is preferred over `ailang-code-recon`
because:
- It anchors the agent to its primary skill, matching the rest of
the roster (`ailang-implementer`, `ailang-architect`, etc.).
- It signals "for a planner dispatch" — which informs the carrier
format and the output shape.
- "code-recon" would suggest a general-purpose code-reading utility
that other agents might call; that direction is explicitly out of
scope (see "Agents do not call other agents" in `skills/README.md`).