Write executable plan
Skill Kanevry/session-orchestrator/skills/write-executable-plan
Loop engineering for AI coding agents — turn ad-hoc sessions into a repeatable research → plan → wave-execute → close loop with verification gates. Runs on Claude Code, Codex CLI, Cursor, and Pi. MIT community plugin.
npx -y skills add Kanevry/session-orchestrator --skill write-executable-planAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Use when you have a PRD or design spec and need a bite-sized, executable implementation plan that any agent can follow without re-deriving structure. Produces `docs/plans/YYYY-MM-DD-<feature>.md` with per-task Files block, complete code per step (no placeholders), and exact verification commands. Rejects "TBD", "TODO", "add error handling", "similar to Task N".
SKILL.md
12.1 KB, ~3.0k tokens by cl100k_base, as published. Nobody here has run it
Write Executable Plan
Bite-sized plans for parallel agents. No placeholders. No vague steps.
When to use
- A PRD from
/plan featureexists but you need a step-by-step implementation plan - A
/brainstormdesign is approved and you want to skip the PRD layer - Multiple agents will execute the plan in parallel and need conflict-free task boundaries
- The work is complex enough that describing it to an agent loses fidelity
When NOT to use
- Trivial 1-file changes (just do them; no plan needed)
- Pure exploration (use
/brainstorminstead) - Bug investigation (use
/debuginstead) - The source PRD is vague or unapproved (get PRD approval before planning execution)
Phase 0: Bootstrap Gate
Read skills/_shared/bootstrap-gate.md and execute the gate check. If the gate is CLOSED, invoke skills/bootstrap/SKILL.md and wait for completion before proceeding. If the gate is OPEN, continue to Phase 1.
Phase 1: Source Selection
Accept ONE of the following inputs (in order of preference):
- PRD path —
docs/prd/YYYY-MM-DD-<feature>.mdproduced by/plan feature - Design spec path —
docs/specs/YYYY-MM-DD-<slug>-design.mdproduced by/brainstorm - Inline description — user provides a free-text description; prompt for elaboration via AUQ before proceeding
If no source is provided and $ARGUMENTS is empty, ask via AUQ:
AskUserQuestion({
questions: [{
question: "Which source should this plan be based on?",
header: "Plan Source",
options: [
{ label: "Existing PRD (Recommended)", description: "Point me to docs/prd/YYYY-MM-DD-<feature>.md — most precise decomposition." },
{ label: "Design spec from /brainstorm", description: "Point me to docs/specs/YYYY-MM-DD-<slug>-design.md — skips formal PRD." },
{ label: "Describe inline", description: "Paste or describe the feature — I will ask follow-up questions before planning." }
],
multiSelect: false
}]
})
Read the source file and extract:
- Feature title (for filename slug and plan header)
- Acceptance criteria or equivalent (drives Task decomposition)
- Explicit out-of-scope items (excludes from plan)
- File inventory if present (seeds the whole-plan Files block)
Phase 2: Decomposition
Break the source into Tasks. Each Task MUST satisfy all of these constraints:
- Single owner — one agent role (e.g.,
code-implementer,test-writer), not "the team" - Bounded file set — lists every file it creates, modifies, or tests; no file appears in two Tasks
- Independently testable — after Step 4 the task stands on its own; no cross-task dependencies in the test command
- 2-5 minute wall-clock estimate — if the estimate exceeds 5 minutes, split the Task; if two Tasks share a file, merge or re-scope
Before writing Tasks, output a brief decomposition plan in plain text:
## Decomposition (draft)
- Task 1: <title> — <owner> — ~<N> min — Files: <list>
- Task 2: <title> — <owner> — ~<N> min — Files: <list>
...
If any task's file set overlaps another, surface the conflict and resolve it before writing Steps.
Phase 3: Step Authoring (per Task)
Each Task gets exactly 5 steps in this order. All 5 steps are mandatory.
Step 1: Write the failing test
EARS seam: If the source PRD/spec carries an ## Acceptance Criteria (EARS) (or ## 3.A) section, apply the EARS→vitest 1:1 mapping below to emit per-clause test stubs. If no EARS section is present, fall back to manual derivation from prose.
EARS → vitest mapping (1:1)
| EARS pattern | vitest construct | example skeleton |
|---|---|---|
| Ubiquitous ("The S shall R.") | invariant it() — no setup branching | it('S shall R', () => { /* assert invariant */ }) |
| State-driven ("While P, the S shall R.") | describe() for state context, nested it() for assertion | describe('while P', () => { it('S shall R', () => { /* enter P; expect R */ }) }) |
| Event-driven ("When T, the S shall R.") | arrange/trigger/expect inside it() | it('when T, S shall R', () => { /* arrange; trigger T; expect R */ }) |
| Optional feature ("Where F, the S shall R.") | it.skipIf(!F) (vitest conditional) | it.skipIf(!F)('where F, S shall R', () => { /* expect R */ }) |
| Unwanted behaviour ("If C, then the S shall R.") | error-path it() with negative assertion or toThrow() | it('if C, then S shall R', () => { /* induce C; expect R */ }) |
Reference test exemplifying this pattern: tests/lib/wave-executor/persona-gate-hook.test.mjs (shipped at #481).
Follow .claude/rules/testing.md § "Test Quality — False-Positive Prevention": one meaningful assertion per it, behaviour not implementation, no branching, hardcoded expected values.
Provide:
- Exact file path (absolute from project root)
- Complete, runnable test code — no
// ..., no placeholders, no// implement later - One sentence explaining why this test verifies the intended behavior
The test MUST fail before Step 3 is applied. If the behavior already exists and cannot fail, pick a harder assertion or a new edge case.
Step 2: Run the test to confirm it fails
Provide:
- Exact command (e.g.,
npm test -- tests/unit/my-module.test.mjs) - Expected terminal output — the specific assertion failure line that proves the test exercises missing code (not a generic "FAIL" — copy the actual error shape)
Step 3: Implement the minimal code
Provide:
- Exact file paths labeled
Create:orModify: - Complete code — every function, every import, every export. No
// add appropriate logic, no// similar to above, no... - DRY constraint: reuse existing utilities; do not duplicate logic that already exists in the codebase
- YAGNI constraint: implement exactly what makes Step 2's test pass; no speculative features
Step 4: Run the test to verify it passes
Provide:
- Same command as Step 2 (copy verbatim)
- Expected terminal output showing the test suite PASS line with the test name visible
Step 5: Commit
Provide:
- Exact commit message in Conventional Commits format:
type(scope): subject - Scope: the primary module or directory affected by this Task
- Subject: imperative mood, max 72 characters, no period
- Files staged: only this Task's files (list them)
Phase 4: Placeholder Linter
Before writing the plan to disk, scan every Step in every Task for forbidden strings. Any match is a rejection — fix before writing.
Forbidden strings (case-insensitive):
| Pattern | Why forbidden |
|---|---|
TBD, TODO, FIXME, XXX | Deferred decisions defeat the plan's purpose |
add appropriate error handling | Vague — specify the exact error type and handling code |
add error handling | Same — write the catch block |
similar to Task N, same as above, like Task N | Forces the executor to cross-reference; defeats file-disjoint execution |
etc. | Incomplete enumeration — list every item |
[fill in], <placeholder>, <YOUR_VALUE> | Template leftovers — fill them in |
... inside a code block | Ellipsis in implementation code means incomplete code |
Prose ellipsis (e.g., "Phase 1... Phase 2...") is acceptable. Only code-block ellipsis is forbidden.
Any hit → surface to user via AUQ:
AskUserQuestion({
questions: [{
question: "The placeholder linter found forbidden strings in the draft plan:\n\n[list each hit with Task number, Step number, and matched text]\n\nHow do you want to proceed?",
header: "Placeholder Linter",
options: [
{ label: "Fix automatically (Recommended)", description: "I will resolve each hit by filling in the missing specifics before writing the plan." },
{ label: "Show me each hit interactively", description: "Walk me through each one so I can provide the missing detail." }
],
multiSelect: false
}]
})
Fix all hits before Phase 5.
Phase 5: Write Plan
Ensure the target directory exists:
mkdir -p docs/plans
Generate today's date via date +%Y-%m-%d. Derive <feature-slug> from the feature title (lowercase, hyphens, no special characters, max 40 characters).
Write to: docs/plans/YYYY-MM-DD-<feature-slug>.md
Use the template in plan-template.md (same directory as this SKILL.md) as the structural guide. Fill every slot. The written plan must:
- Open with
# Plan: <feature title>and aSource:/Created:/Status: draftheader block. TheSource:line MUST carry the tracking Issue/Epic reference inline as#NNN(e.g.Source: docs/prd/2026-07-09-foo.md (#786)). This#NNNis load-bearing: it is the anchor thearchive-closed-planscustom-phase reads (viascripts/archive-closed-prds.mjs) to detect that a plan's feature/Epic is closed and archive the plan into the Meta-Vault. A plan with no#NNNin its header is never archived (fail-closedno-epic-ref) — it lingers indocs/plans/indefinitely. - Include a whole-plan
## Filessection listing all Create / Modify / Test paths across all Tasks - Contain one
## Task N: <title>section per Task, each with its per-task### Filesblock and Steps 1-5 - Pass the Phase 4 linter with zero hits
Phase 6: Hand-off
Present the plan path and task count to the user via AUQ:
AskUserQuestion({
questions: [{
question: "Executable plan written to docs/plans/YYYY-MM-DD-<slug>.md ([N] tasks, ~[total] min estimated).\n\nHow do you want to execute it?",
header: "Plan Hand-off",
options: [
{ label: "Dispatch via wave-executor (Recommended)", description: "Parallel agents execute all tasks simultaneously. Fastest for file-disjoint tasks." },
{ label: "Execute coordinator-direct", description: "One task at a time in this session. Safer for tasks with shared state." },
{ label: "Revise the plan first", description: "I have feedback — describe what to change and I will update the plan." },
{ label: "Done for now", description: "Keep the plan as a reference; no immediate execution." }
],
multiSelect: false
}]
})
If the user selects "Revise the plan first", incorporate the feedback, update the plan file, re-run the Phase 4 linter, and re-present Phase 6.
If the user selects "Dispatch via wave-executor", hand off to skills/wave-executor/SKILL.md with the plan path as input.
Anti-Patterns
- Steps that say "implement the feature" without exact file paths and complete code — this is the most common failure mode; reject it at Phase 4
- Tasks with overlapping file scopes — agents executing in parallel will conflict; the decomposition must be file-disjoint
- Plans without a per-Task Files block — forces agents to grep the codebase to discover their scope, which loses the speed advantage of planning
- Skipping Phase 4 — placeholders in a plan silently cascade into every agent that executes it; one "TBD" can stall an entire wave
- Estimating tasks at >5 minutes — if a task is that large, it contains multiple logical changes; split it
- Vague commit messages in Step 5 —
feat(core): update thingsis not acceptable; the scope and subject must be derivable from the Task's file set without reading the diff
See Also
skills/plan/SKILL.md— produces the PRD this skill consumesskills/brainstorm/SKILL.md— alternative source (design spec)skills/wave-executor/SKILL.md— consumes the plan for parallel execution.claude/rules/testing.md§ "Test Quality — False-Positive Prevention" — test conventions to follow in Step 1skills/write-executable-plan/plan-template.md— structural template used in Phase 5