Implement a written plan (from write-plan or interview-plan). Use when the user says execute or implement the plan. Runs the review gate itself. Do not use while still interviewing or writing the plan.
Installs into .claude/skills of the current project.
Are you the author of Execute Plan?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/ayberkcansever-execute-plan)
---
name: execute-plan
description: >-
Implement a written plan (from write-plan or interview-plan). Use when the
user says execute or implement the plan. Runs the review gate itself. Do
not use while still interviewing or writing the plan.
disable-model-invocation: true
icon: rocket
color: green
---
# Execute Plan
## Overview
Load plan, review critically, execute ready tasks in waves in the ticket
venue (this checkout if already on the ticket branch, else a worktree),
run the verifications the plan specifies, report when complete.
**Announce at start:** "I'm using the execute-plan skill to implement this plan."
## Invariants — read first, re-read after any context compaction
- Review the plan critically first.
- Follow plan steps exactly; don't skip verifications.
- Commit with explicit paths only (or the repo's commit helper); never `git add .`.
- Stop when blocked — don't guess.
- Execute in this checkout when already on the ticket branch; otherwise in
the ticket worktree. The venue's plan copy is the live one.
- Dispatch every legal task in a wave; fan in serially — commit, sync docs,
tick, one task at a time.
- This skill runs the review gate as Step 4.4. Do not also invoke
`/thermo-nuclear-code-quality-review` unless the user edited code after
`Verdict: ship`. `/graph-retro` is post-merge, not the next implement step.
- Long runs get compacted; this file and the plan live on disk. If the
conversation was summarized, or you cannot recall a rule verbatim, re-read
this file and the plan header's `For agentic workers` block before the next
action — never act from a summary of them.
## The Process
### Step 1: Load and Review Plan
1. Read the plan file (the one produced by **write-plan** or **interview-plan**).
Infer `<TICKET-ID>` from the plan path first, then an existing ticket
worktree, then the current branch, then ask once — the user's checkout
may be on `main` or another ticket.
If the user did not say which file, search in this order:
- already-listed worktree for this ticket (it is live — prefer it)
- `docs/features/<TICKET-ID>/` (tracked)
- `docs/plans/<TICKET-ID>/` (gitignored WIP)
- Legacy flat `docs/plans/*.md` or `docs/PLAN_*.md`
If both tracked and WIP copies exist in the same checkout, diff them; if
they diverge, ask which is active — never silently prefer the promoted
copy over newer WIP.
Record the **absolute path of the user's checkout** — Step 2 copies from
there only when the worktree does not already have the WIP docs.
2. Review it critically — identify any questions, gaps, or concerns before
touching code. A plan whose header links a spec but carries no
`**Audit:** clean` line: if an interview spec exists for this ticket, the
Audit Pass was interrupted — confirm before executing. If there was no
interview (standalone write-plan), missing audit is expected — still
confirm once, then proceed. Do not treat both cases as "interrupted
interview".
3. If concerns: raise them with the user before starting. Resume / stash /
TodoWrite wait until Step 2 has the live plan.
### Step 2: Open the execution venue
**Already on this ticket's branch** (`git branch --show-current` contains
`<TICKET-ID>`): this checkout is the venue. Skip git-worktrees. Skip the
WIP copy below. Git will not attach the same branch in a second worktree —
stay here instead of deadlocking.
**Otherwise** execution happens in a dedicated worktree for this
`<TICKET-ID>`. The user's checkout is theirs — it may be dirty, on another
branch, running a dev server. One worktree per ticket also lets several
tickets execute in parallel on the same repo. Do not ask which branch to
use, do not offer to switch branches, and do not gate on the user's tree
being clean.
1. **Worktree path only.** Run the **git-worktrees** skill with the ticket
ID. It detects existing isolation, reuses or creates the worktree at
`.worktrees/<branch>` (branch `<TICKET-ID>-<slug>`, per that skill's
naming), and runs the project's install + baseline check. Consent is
implied by `/execute-plan` — it does not re-ask. Already inside a linked
worktree for this ticket → it reports and continues; nothing is created.
2. **Live plan (worktree path only).** The WIP tiers (`docs/plans/`,
`docs/specs/`) are gitignored, so a *fresh* worktree does not contain the
plan or spec. Run this **from inside the worktree**. Copy only when the
destination does not already exist — a prior run's worktree copy is live;
overwriting it from the origin checkout destroys ticks, drift notes,
blockers, and review entries:
```bash
for d in docs/plans/<TICKET-ID> docs/specs/<TICKET-ID>; do
if [ -d "<origin-checkout>/$d" ] && [ ! -d "$d" ]; then
mkdir -p "$(dirname "$d")" && cp -R "<origin-checkout>/$d" "$d"
fi
done
```
The worktree copy (or the tracked `docs/features/<TICKET-ID>/` already on
the branch) is now the live plan. Never write the origin checkout's copy
mid-run. In-place: the files are already here; this copy does not run.
3. **Resume on the live plan, in this venue.** Reconcile checkboxes
against `git log` here (this is the ticket branch): a ticked task with no
`[T<N>]` commit → untick and redo; a `[T<N>]` commit with its task
unticked → re-run the gate and tick without redoing. If `## Blockers`
holds an unresolved stash OID, `git stash apply <OID>` **here**, then
mark it resolved. Checkboxes are the source of truth; TodoWrite is a
session mirror. Every task ticked but no `## Review` with `Verdict: ship`
at current HEAD → jump to Step 4. Stale `reviewed @` SHA (code commits
after it, docs-only excepted) → re-run Step 4.
4. Confirm the venue is clean (`git status --porcelain` empty) aside from
gitignored WIP docs. A reused worktree that is dirty is leftover work —
reconcile against `## Blockers` before Task 1.
5. Create a TodoWrite list from the live plan and proceed.
Report the venue path (this checkout, or the worktree) before Task 1 so the
user knows where the work is landing.
### Step 3: Execute Tasks
**Tasks run in waves: every task that legally can run now is dispatched as a
fresh subagent in one message; this session acts as orchestrator.** Waves are
the default, not an optimization to opt into — a plan whose tasks are
independent should finish in as many rounds as its dependency graph is deep,
not as many rounds as it has tasks. All subagents in a wave share the Step 2
venue; isolation between them comes from the disjoint-files rule below, not
from separate directories.
Inline execution is fine for small or tightly coupled plans where one context
comfortably holds the work — task count alone is not the trigger.
#### Wave scheduling
Each round, first re-read the plan header's `For agentic workers` block (it
carries the orchestrator invariants and is the recency copy that survives
compaction), then build the **ready set** from the unticked tasks. A task joins the
current wave only if all four hold:
1. **`Depends on:` satisfied** — every named task is already ticked. A task
declaring `none` is ready immediately. **If every task omits `Depends on:`**,
treat each as depending on the one before it and run sequentially — an
absent declaration is unknown, not independent. **If some tasks declare
`Depends on:` and one omits it, stop and ask** — do not treat the omit as
`none` (vacuously ready) and do not silently serialize the whole plan.
2. **`Files:` disjoint** from every other task already in this wave. Compare
**paths only** — strip a trailing `:line-range` (e.g. `src/foo.py:123-145`
→ `src/foo.py`) before the check. Two tasks on the same file at different
lines still collide. Two subagents editing one file in one venue overwrite
each other; there is no merge step to catch it. A task with no `Files:`
list does not join a wave with others — unknown overlap. (The Review gate
has no `Files:` and is excluded by rule 4 anyway.)
3. **Gate commands do not contend** — tasks whose verifications write the same
build output, coverage file, fixture database, or bind the same port go in
different waves even when their `Files:` are disjoint. Shared *read-only*
test infrastructure is fine, but a gate whose scope is the whole repo
(typecheck, compile, lint, full-suite) reads a sibling's half-written files
and contends the same way: scope it to the task's own paths, or schedule the
task in a later wave.
4. **Not the Review gate task** — see the exception below.
Dispatch the whole ready set in a single message (parallel tool calls), then
wait for all of them before fanning in. Do not start the next wave early:
a later task's `Depends on:` is only satisfied once its predecessor is
**ticked**, which happens in fan-in after the orchestrator's own gate run.
Width is whatever the ready set allows — there is no cap beyond rules 2 and 3.
Record the wave composition in your progress notes (`wave 1: T1, T3, T5`) so a
resumed session can tell which tasks were in flight together.
**Subagent contract — the prompt MUST contain all of:**
- the **absolute venue path** from Step 2, and the instruction to work only
inside it — a subagent given a repo-relative path can resolve it against
the wrong checkout and silently edit the other tree;
- the plan file path and the task number (the plan's **Architecture
constraints** section is the subagent's conventions source — it sees nothing
else);
- the spec file path from the plan header (so decisions are checkable, not
hearsay);
- the repo quirks doc path when it exists (e.g. `docs/quirks.md`);
- the task's gate/verification command(s) verbatim;
- the 5-attempt cap and the instruction to report a blocker instead of
grinding — an attempt ends at a gate run; ~30 tool calls without one → stop,
report a blocker;
- the Plan Drift Protocol below. **Dispatched subagents return a proposed
`> Drift:` line; they do not write the plan.** The orchestrator applies it
at fan-in. Only inline execution amends the plan in place;
- **edit and test only — never commit, never write the plan file** (git index
and plan md are orchestrator-owned state, sequential or parallel): skip the
task's commit step and return changed paths, drift notes, and the red and
green gate output verbatim instead — the orchestrator commits after its own
checks (substeps 5–7).
**Trust but verify:** subagents overclaim. Before ticking a task's checkbox,
the orchestrator **re-runs the task's gate command itself** and confirms the
expected output. A subagent "done" summary is a claim, not evidence.
**Exception — the Review gate task:** the plan's final Review gate task is
NEVER dispatched to a task subagent (a task subagent cannot spawn the
read-only reviewer, and an implementer must not review its own diff). Skip
it when building the ready set. **When it is the only remaining unticked
task, leave Step 3 and go to Step 4** — do not stall on an empty ready set.
The orchestrator runs the gate as Step 4.4 (after data-path trace, full-suite,
and spec promotion) and ticks its checkboxes when `## Review` records
`Verdict: ship`.
#### Per task
Substeps 1–3 are the task work — done by the subagent in dispatch mode, by
this session inline. Substeps 4–8 are **always the orchestrator's**, and in a
wave they run **serially, in task-number order, after every subagent in that
wave has returned**: the git index and the plan file are single-writer state
no matter how wide the wave was.
1. Mark the todo `in_progress`.
2. Follow each step exactly — the plan has bite-sized steps (write failing test
→ run red → minimal impl → run green → commit). When reality contradicts a
step, apply the Plan Drift Protocol — do not silently diverge and do not
stop for trivial mismatches.
3. Run the verifications the step specifies. Do not skip them. Do not invent your
own success criteria when the plan gave one.
4. **Before the task's commit step, run substeps 5–6 first** — the commit
must be able to include synced doc paths, and gate findings are cheaper to
fix pre-commit than post-commit. Apply each returned `> Drift:` note to the
plan here too; subagents never write it.
5. **Per-task check (orchestrator, cheap):** re-run the gate command (see
above), then skim the task's diff against the plan's Architecture
constraints — layering respected, canonical helpers used, no hardcoded
test-expected values. For a task that changes a **contract or persisted
data** (API/event shape, schema, migration), have a fresh read-only
subagent do this skim instead — the implementer must not check its own
contract change. Findings → fix now, before the next task builds on it.
6. **Feature-docs sync:** if your repo has a feature-docs sync flow and
`docs/features/<TICKET-ID>/` exists, run it when the task changed
decisions, contracts, deploy, or QA; skip for behavior-preserving fixes.
The edited doc paths join the task's commit below.
7. When the plan step says "commit", commit code + synced doc paths together —
stage explicit paths (or use the repo's commit helper); never `git add .`.
Keep the plan's `[T<N>]` task tag in the message.
8. **Tick the task's checkboxes (`- [x]`) in the plan file** after the
orchestrator's own gate run passes, and append
`> Gate: <cmd> | exit <n> | attempt <k>/5 | <one-line result>` under the task — the plan
file tracks progress and evidence, not the session. If the plan file is tracked (`docs/features/` tier), tick before
the step-7 commit and include the plan path in it — uncommitted checkbox
edits dirty the tree and block the review gate. Then mark the todo
`completed`.
**When one task in a wave fails.** A blocked or failing subagent does not void
its siblings. Fan in the tasks that passed their gate normally — commit and
tick each one — then handle the failure on its own terms: retry within the
5-attempt cap, or append a `## Blockers` entry and stop. Do not open the next
wave while a blocker is unresolved; its tasks may depend on the failed one, and
resuming from a half-applied wave is exactly what the plan file's checkboxes
exist to prevent.
### Plan Drift Protocol (plan meets reality)
Plan code was written before implementation; minor mismatch is normal, not a
blocker. When a step's code or command doesn't match reality (renamed symbol,
different signature, moved file, API mismatch):
1. **Adapt** — implement what the step *intends* against the real code.
2. **Record the drift** — dispatched: return `> Drift: <what differed and why>`
to the orchestrator (do not write the plan). Inline: amend the step in place
and append that line under it. The plan file stays the as-built source of
truth; a plan that lies about what was built is worse than no plan.
3. **Escalate instead** when the drift changes a spec **decision**, a
contract, invalidates a later task, or would make you delete, narrow, or
invert an assertion covering behavior the plan never set out to change —
that is a plan gap or a regression, not drift. Flipping such an assertion
makes the test match the bug.
Stop and ask (see below). If the user approves the change, update the spec
**immediately** — record the new decision with `supersedes D<n>` and strike
the old one — before continuing. The review gate reads the spec and must
not judge the diff against a stale decision.
### Step 4: Complete
After all tasks are done and verified:
1. **Trace the data path to its real sink.** If the change persists or transmits a
field, follow the value from its source to where it lands (DB write, queue
publish, HTTP response). Open the actual writer — the repository insert /
`build(...)` / publish payload — and confirm the new field is listed there, not
just on the domain type. Green unit tests that mock the writer do NOT prove
this; confirm at least one test reaches the sink without mocking it (in-memory
DB round-trip or emitted-payload assertion), or flag it to the user. A field set
on a domain object but missing from the writer ships schema defaults (`0`/`null`)
to production — a silent failure that looks deployed.
2. Run the full relevant test/lint suite for the touched code. The plan's
`## E2E` block is not run here (see substep 7).
3. **Promote the spec before the review:** copy
`docs/specs/<TICKET-ID>/spec.md` to
`docs/features/<TICKET-ID>/design.md` (or merge into an existing one) and
commit — in a multi-repo setup where another repo owns the shared
`design.md`, merge there instead and record that path. The read-only
reviewer may run from a context that cannot see gitignored WIP paths, and
a missing spec caps its verdict at `fix-first`.
Then confirm the tree is clean (`git status --porcelain` empty): the
review's Step 0 refuses a dirty tree because uncommitted changes silently
escape the diff.
4. **Run the review gate:** invoke **thermo-nuclear-code-quality-review** as a
read-only subagent **with this venue as its working directory** (or
equivalent `git -C <venue>`) on the branch diff, passing the spec and
plan **absolute** paths in the prompt. A reviewer launched from a
different checkout than the venue diffs the wrong branch. A fresh-context
reviewer cannot find gitignored WIP paths on its own. This step IS the
plan's final Review gate
task (write-plan appends one to every plan) — tick that task's checkboxes
here; never run the review once in the Step 3 loop and again here.
- **Pinned review model:** launch the reviewer subagent with the model
named in thermo-nuclear-code-quality-review's "Pinned review model"
section — that skill is the single source of truth for the slug; do not
hardcode it here. The session's own model is allowed — independence
comes from the reviewer's fresh read-only context, not a different
model. If a pinned slug is unavailable, stop and ask the user — never
silently substitute.
- **Open the entry first:** *before* launching the reviewer, append to
the plan's `## Review` section one line —
`cycle <c> | reviewed @ <HEAD SHA> | base @ <base SHA> | suite: <cmd> → <result>`
— using the full-suite result from substep 2 (or its re-run after the
last fix; the SHA must match the current HEAD). This line is the
reviewer's `ship` evidence; the review skill caps at `fix-first`
without it, so writing it afterwards costs a wasted cycle.
- **Close the entry after:** complete that same entry with the reviewer's
3-line rollup (Verdict / Top issue / Net), the model used, and the
subagent link — one entry per review cycle, never a second entry for
the same cycle. This is what the Step 2 resume check looks for; an
entry with no `Verdict:` line is an in-flight cycle, not a review.
- **Verify the mechanism before accepting a finding:** reproduce what the
finding says happens (run the test, hit the branch, read the value) at
the reviewed SHA. A finding whose conclusion is right but whose stated
mechanism is wrong gets fixed for the *real* mechanism, and the
correction is reported back to the reviewer in the next cycle's prompt.
The reviewer is a second opinion, not an oracle.
- **Remediation task template** — accepted findings enter the plan as
full tasks, never bare checkboxes (bare checkboxes lose files, gates,
and the commit trace). **Insert them immediately before the review gate
task**, numbered `N.1`, `N.2`, … so the gate keeps its number and stays
last — the gate depends on the fixes, never the reverse (a fix that
depends on the gate deadlocks the plan). **This block is the single
source of truth for the shape** — write-plan and
thermo-nuclear-code-quality-review reference it instead of restating
it; when the shape changes, update it here only:
````markdown
### Task N.k: Fix review finding <n>
**Implements:** review finding <n>, cycle <c> (from `## Review`)
**Depends on:** <the task that introduced the finding, or the previous remediation task>
**Files:**
- Modify: `<path from the finding>`
- [ ] **Step 1: Fix** — <the finding's fix, restated concretely>
- [ ] **Step 2: Verify** — re-run the owning task's gate command; expected PASS
- [ ] **Step 3: Commit** — `git add <paths> && git commit -m "fix(<scope>): <finding summary> [T<N.k>]"` (or your repo's commit helper)
````
Fix them via the same Step 3 loop, then have the reviewer
re-check the changed areas. **Before
accepting a `ship` verdict after any fix cycle, re-run the full test
suite at the final HEAD** — targeted gate commands alone do not qualify.
Repeat until the verdict is `ship` (the review skill caps cycles at 3,
then escalates).
5. **As-built reconciliation:** re-read the plan file end to end — every
checkbox ticked or explained, every `> Drift:` note in place, the
`## Review` section's last entry reads `Verdict: ship` at the current HEAD,
`## Blockers` entries resolved or still-open-and-flagged (`## Deferred
suggestions` stays for the user — it does not block); confirm
superseded spec decisions were marked at escalation time (Drift Protocol
step 3). Then promote the plan to `docs/features/<TICKET-ID>/` (the spec
was already promoted in substep 3) and commit, or ask the user if
promotion is premature. Docs-only commits after the reviewed SHA that
leave spec decisions unchanged do not invalidate the ship verdict.
6. Report what was implemented, which verifications passed, and anything
skipped — and state the **venue path and branch** so the user knows
where to look.
7. Hand back to the user for manual testing. If the plan has an `## E2E` block,
list its steps — they run now, together with the user, never in Step 3 or
substep 2. Do not open a PR or merge unless the
user asks. If the venue is a worktree, **leave it in place**: it holds
the branch, the as-built plan, and any still-gitignored WIP docs.
Removing it is git-worktrees Step 4, run only after merge or on explicit
user say-so.
## When to Stop and Ask for Help
**STOP executing immediately when:**
- You hit a blocker (missing dependency, failing test you can't trivially fix,
unclear instruction).
- The plan has a critical gap that prevents starting a task.
- You don't understand a step.
- **A verification fails 5 times (hard cap).** On the 5th failure: STOP, append
the blocker to a `## Blockers` section at the end of the plan file (task number,
what fails, what was tried), and escalate to the user. Never grind past the cap.
- **A verification cannot be run as written** — it hangs, it is already red for
unrelated reasons, or it needs access you cannot obtain. Append a `## Blockers`
entry and ask what counts as ship evidence. Never tick the step, and never
silently substitute a narrower command — a gate downgraded inside a `> Drift:`
note is invisible to the reviewer.
**Leave a clean tree when blocked.** Before escalating, park the partial work so
resume doesn't inherit a dirty workspace:
`git stash push -u -m "T<N>-blocked" -- <task's changed paths>` (default) —
scoped to the task's paths so the user's unrelated work is never swept up,
`-u` so untracked new files are not left behind. Record the stash OID
(`git rev-parse stash@{0}`) in the `## Blockers` entry. Alternative: a wip
commit on the feature branch if the user prefers history — record which was
done.
Ask for clarification rather than guessing.
## When to Revisit the Plan
Return to Step 1 (review) when:
- The user updates the plan based on your feedback.
- The fundamental approach needs rethinking.
Don't force through blockers — stop and ask.
## Subagent-driven execution
Subagent-per-task, dispatched in **waves** of everything currently legal to
run, is the default (see Step 3). Each task gets a fresh context, which
prevents context rot on long plans; the plan file (checkboxes + `## Blockers`)
carries all state between tasks, so any session — or a replacement session —
can resume from it. Because state lives in the plan and the git index, both
single-writer and both orchestrator-owned, widening a wave never widens the
blast radius.
A subagent that hits the 5-attempt cap reports the blocker back; the
orchestrator writes it to the plan file and stops. Inline execution remains
fine for small or tightly coupled plans where one context comfortably holds
the work.