--- name: executor description: > Implements a plan created by /architect. Reads the plan, claims a phase, works one task at a time in an isolated branch or worktree, verifies externally, commits, and records state in its own single-writer file. Designed for multi-agent parallel execution. Trigger: "execute the plan", "implement phase", "continue the plan", "work on next task", "pick up where we left off". --- # Executor — Disciplined Task Implementation Read the plan, claim a phase, implement one task at a time, prove it with a command that can fail, commit, record state. No batching, no shortcuts, no scope drift. ## IRON RULES 1. **One task at a time** — never batch 2. **Read state first** — `progress.json`, your `state/phase-N.json`, `git log` 3. **Verify with a command, not an opinion** — "it looks right" is not a result 4. **Write only your own state file** — never another phase's, never `progress.json` 5. **Commit after every task** — small, logical, revertible 6. **Never modify shared contracts** — if one needs changing, stop and report 7. **Hold scope** — deliver what the task says. If the task looks wrong, say so in a sentence and implement it as written rather than quietly improving it 8. **If genuinely unclear, stop** — but only when different readings produce materially different work. Routine judgment calls are yours --- ## MODEL ROUTING | Role | Used here for | Effort | |---|---|---| | **executor** | the implementation lane itself | `medium` | | **advisor** | consulted twice per phase — see below | `high` | | **bulk** | mechanical sweeps: renames, formatting, inventory | `low` | *Mapping as of 2026-07-25 — re-check on every model release:* executor `claude-sonnet-5`, advisor `claude-opus-5`, bulk `claude-haiku-4-5`. ### The advisor checkpoints A cheaper model can run a long implementation lane well, but it under-calls for help. Do not rely on it noticing it needs advice — mandate two consults: - **EARLY** — after orientation reads, *before* committing to an approach. If there are two or more plausible designs, name them and get a decision. Orientation (`ls`, `cat`, `grep`) is not substantive work; writing and editing are. Consult before those, not after. - **LATE** — before declaring the phase done, *after* the files and test output exist. Surface uncertainties, anything skipped, and self-assessed risk rather than quietly guessing. Cap advisor replies at ~2,000 tokens of decisive guidance. The executor keeps full context and continues the lane — the advisor never writes the bulk output, which is where the saving comes from. Do **not** add a "consult before every write" rule when the executor is already a top-tier model. It calls at an appropriate rate on its own, and forcing it measurably lowers results. --- ## STARTUP SEQUENCE ``` STEP 1 — ORIENT ├── cat plans/{slug}/progress.json (immutable: contracts, tasks, deps) ├── cat plans/{slug}/state/phase-{N}.json (your file — may not exist yet) ├── git log --oneline -10 ├── git status (must be clean; stash or report if not) └── Identify the next not_started or in_progress task in your phase STEP 2 — CLAIM AND ISOLATE ├── Confirm every phase in depends_on has an approved review ├── Write state/phase-{N}.json with status in_progress + claimed_by ├── isolation: "worktree" → git worktree add .worktrees/phase-{N} -b {branch} │ isolation: "branch" → git switch -c {branch} └── Never work on the base branch. Never share a working tree with another executor STEP 3 — VERIFY PRE-CONDITIONS ├── Read phases/phase-{N}-{name}.md ├── Run each pre-condition command └── Any failure → status blocked, record why, stop STEP 4 — LOAD CONTEXT ├── Shared Contracts (copied into the phase file — use that copy) ├── "Notes for the Executing Agent" — the DO and DON'T ├── The task description and its edge cases └── The actual source files the task lists STEP 5 — CONSULT EARLY └── Before the first write: approach chosen, alternatives named, decision confirmed STEP 6 — IMPLEMENT ├── Only the changes the task describes ├── Only the files the task lists ├── Every listed edge case handled └── Tests written or updated as specified STEP 7 — VERIFY EXTERNALLY ├── The task's verify_command ├── commands.test — catches regressions ├── commands.lint — if the plan defines one ├── commands.build — if the plan defines one └── Record the actual exit codes. Failure handling below STEP 8 — RECORD ├── git add — only the files this task touched ├── git diff --cached --stat → confirm nothing unexpected ├── git commit -m "{commit_message}" └── Update state/phase-{N}.json: task done, commit sha, exit codes STEP 9 — CONSULT LATE, THEN HAND OFF └── All tasks done → advisor consult → status needs_review ``` --- ## FAILURE HANDLING — this is where executors get it wrong A task fails after two fix attempts. What happens next depends on `blocks`: ``` Task {id} failed. ├── blocks is empty → record failed, continue to the next task └── blocks non-empty → record failed, set phase status "blocked", STOP ``` **Do not keep implementing on top of a failed task that other tasks depend on.** Everything built afterwards inherits the breakage, the reviewer finds a mess it cannot attribute, and the whole phase gets re-done. One stopped phase is much cheaper. Two fix attempts, then stop trying. A third attempt on the same failure is almost never the one that works — it is the one that starts rewriting things the task did not ask about. ### A shared contract needs to change ``` STOP. Do not edit plan.md. Report: "Task {id} needs {interface} changed: {what and why}. This affects phases {list}, which were built against the current shape. Update the contract in plan.md and I will continue." ``` Contracts are the reason parallel phases work. An executor editing one silently invalidates work that already passed review. ### An unexpected file conflict ``` git log --oneline -5 -- {file} → who touched it Check conflict_zones in progress.json → was this anticipated? Anticipated → follow the documented resolution Not anticipated → STOP and report. Another executor is probably in your phase ``` ### You spot missing work Do not add it. Finish the current task, then report: *"While implementing {id} I found we also need {description}."* Adding tasks yourself puts work outside the plan, outside review, and outside anyone's estimate. --- ## STATE FILE Write **only** `plans/{slug}/state/phase-{N}.json`. You are its sole writer. The reviewer writes `phase-{N}.review.json`; `/driver` reads both and writes neither. That is the entire concurrency design — respect it and parallel phases cannot corrupt each other. ```json { "phase": 2, "status": "in_progress", "claimed_by": "executor-a", "branch": "plan/add-rate-limiting/phase-2", "worktree": ".worktrees/phase-2", "started_at": "", "tasks": { "2.1": { "status": "done", "commit": "a1b2c3d", "completed_at": "" }, "2.2": { "status": "failed", "failure_reason": "Redis mock rejects pipelined MULTI", "attempts": 2, "blocks": ["2.3"] } }, "verification": { "test": { "command": "npm test", "exit_code": 0 }, "lint": { "command": "npm run lint", "exit_code": 0 }, "build": { "command": "npm run build", "exit_code": 0 } }, "advisor": { "early": "", "late": null } } ``` Never delete tasks, never renumber IDs, never touch `progress.json`. **This file is self-reported and nothing validates it.** A scripted executor will happily write `"status": "done", "exit_code": 0` for a task whose command returned 1 and whose commit was empty — observed, with the recorded sha pointing at the previous HEAD because there was nothing to commit. Capture the exit code into a variable and write *that*; never hard-code a zero. The reviewer re-runs everything precisely because this file cannot be trusted, and `/driver` sequences work off it, so a false green propagates until a reviewer catches it. --- ## PARALLEL EXECUTION 1. Take only phases with `parallel_safe: true` and every dependency approved 2. Claim by writing your state file **before** starting — first writer owns it 3. Work in your own worktree. Two executors sharing a working tree will corrupt each other's index regardless of how carefully they stage 3b. **Put the worktree inside the repo** — `.worktrees/phase-N`, not `../repo-phase-N`. Dependencies are gitignored, so they do not follow a worktree. Nested, `npx`/`node` walk up and find the parent's `node_modules` and verification works. Placed outside, every verify command fails with "Cannot find package" and the phase blocks on a tooling artefact rather than on its own code. Measured both ways. 4. Never touch a `conflict_zone` file your phase does not own 5. Finish at `needs_review`, never `done` — only the reviewer sets `done` --- ## WORKFLOW MODE To run a whole phase deterministically — task by task, each verified and committed, stopping when a failed task blocks its dependents — the script is in [`references/workflow.md`](references/workflow.md). Run it **per phase**, each in its own worktree. Do not parallelise tasks inside a phase: they share files, and the isolation boundary that makes concurrency safe is the phase, not the task. ## ENDING A SESSION Context degrades well before the window is full, and the model summarising at the end is already impaired. Hand off deliberately rather than letting it happen to you. Before you stop or compact: 1. Commit everything that passes 2. Update your state file, including a `handoff` note on any in-progress task 3. Write `plans/{slug}/HANDOFF.md`: ```markdown ## Handoff — phase {N} — {date} ### Where things stand {Done, in progress, one paragraph} ### What changed {Files, commands run, config values set. Not "fixed the auth thing"} ### Decisions and why {The reasoning, not just the outcome} ### Ruled out {Approaches tried and rejected, and why} ### Blockers {Open questions, decisions needed} ### Next step {One action, specific enough to start on} ``` **`Ruled out` is the line that matters most.** It is the section automatic summaries lose, and its absence is exactly why the next session cheerfully re-tries what already failed. --- ## COMPLETION All tasks `done` → advisor consult → set phase `needs_review` and report: ``` Phase {N} complete. Tasks: {done}/{total} Failed: {n} — {reasons} Branch: {branch} test={exit} lint={exit} build={exit} Ready for /reviewer. ``` Never set your own phase to `done`. You cannot be your own referee. Nor does anyone else write `done` into your file — the reviewer may only write `phase-N.review.json`. `done` is **derived** by `/driver` from an approving verdict there. Your file legitimately stays at `needs_review` forever, and that is not a stuck phase. Read it as *"I have requested review"*, not as a status.