name: uexecute
description: Use to implement an approved plan. When the plan declares ### Interface graph, derives waves by topo-sort over [blocks] IF edges only — non-blocking IF edges (the default) put producer and consumer in the same wave, since the IF declaration is sufficient context. Edits inline when only one implementer would fire (single phase or serial fallback). Runs plan-diff check and consistency sweep after each commit. Forbids silent fallbacks and mutation of external spec/design docs. Dispatches the planner skill when deviations invalidate the plan.
Execute
Implement the approved ## Plan from docs/tasks/<slug>.md. You are the dispatcher — each phase is handed to a fresh implementer subagent (up:implementer by default; up:implementer-sonnet for trivial phases — see "Choosing the implementer agent" below). After each phase returns, you run the plan-diff check and consistency pass before moving on. The goal is a working change that honors Design and Plan.
Before starting
Brevity
Branch / worktree correctness
pwdmatches the task file's**Worktree:**(or the main repo ifnone)git branch --show-currentmatches**Branch:**
When you dispatch a subagent (up:explorer, up:researcher), pass the intended working directory explicitly in the prompt. Subagents do not inherit your cwd reliably across harnesses.
Per-wave loop
If the plan contains a ### Interface graph subsection (declared by up:uplan), derive execution waves via topo-sort over [blocks] edges only:
- An IF declared with
[blocks]in### Interfacesis a blocking dependency — its consumer must wait for the producer's actual output (e.g. a generated file, an applied migration), or the planner has marked the producer as large/critical enough that downstream work should not start until it lands. - An IF without
[blocks]is non-blocking — the IF declaration is sufficient context for the consumer to be implemented in parallel with the producer. - Wave 1: phases with no blocking Consumes. Wave N+1: phases whose every blocking Consumes IF is produced by phases in waves 1..N. Non-blocking IF edges are ignored when computing waves.
Mismatches between an implementer's actual output and the IF declaration surface in the wiring check (post-wave) and are reconciled there. Otherwise fall back to the serial one-phase-at-a-time loop (IV6).
Serial fallback (no ### Interface graph): execute phases in order, one at a time, inline — never dispatch a single implementer (see "When to skip dispatch and do it inline").
Wave preparation:
For each phase (serial fallback) or wave (parallel):
Parallelism comes only from the Plan's ### Interface graph via the wave scheduler; the scheduler ignores non-blocking IF edges and respects [blocks] ones; never infer ordering at runtime (IV4, PC5).
Dispatch per phase
Applies only when two or more phases fire concurrently in a wave. Each phase runs in a fresh implementer subagent. You (the dispatcher, on Opus) coordinate. For single-implementer cases (single-phase plan, serial fallback, or a wave that reduced to one phase), do the work inline — see "When to skip dispatch and do it inline" below.
Choosing the implementer agent
up:implementer(Opus) — default. Use for any phase requiring judgment: multi-file changes, new logic, TDD, introducing or changing an interface, anything where reading multiple files informs the implementation.up:implementer-sonnet(Sonnet) — trivial phases only. Use when the phase is unambiguously mechanical and well-localized: single-file typo or copy fix, mechanical rename, import/lint cleanup, version/changelog bump, doc edit with no behavioral claims.
Default to up:implementer. Pick up:implementer-sonnet only when every criterion is met. If unsure, pick up:implementer.
If up:implementer-sonnet returns NEEDS_CONTEXT with escalate: up:implementer, re-dispatch the same phase to up:implementer — its scope check correctly bounced a non-trivial phase.
Do not pass:
- Session history or prior-phase chatter
- The full task file (pass only the sections above)
- Later phases (keep the implementer scoped to one phase)
- Rationale behind design decisions — the plan is the contract
Dispatch prompt skeleton (guidance — fill the fields, skip sections that don't apply):
Phase: <verbatim PHN text from ## Plan>
Invariants: <IV1, IV2, ...>
Principles: <PC1, PC2, ...>
Assumptions: <AS1, AS2, ...>
TDD: <yes | no (reason)>
Working directory: <absolute path>
Branch: <expected branch from task file header>
Commit mode: defer
Owns: <comma-separated paths from the graph's @>
Implements: <IF<n>, ...> (if this phase produces any)
Consumes: <IF<n>, ...> (if this phase consumes any)
When to skip dispatch and do it inline:
- Only one implementer would fire — single-phase plan, serial-fallback step, or a wave that reduced to one phase. Implementer subagents exist to enable parallelism; with one implementer there is no parallelism to enable, so the dispatcher does the work directly. Plan-diff and consistency steps still run.
- Phase needs mid-work interactive user input
- A phase-N-and-N+1 fix follows from review findings, small enough to just edit
Wave dispatch
Used when the Plan declares ### Interface graph (written by up:uplan) and a wave contains two or more phases. Waves are derived by topo-sort over [blocks] edges only — never hand-declared (PC5). If a wave reduces to one phase, do it inline instead.
Reading the graph:
Parse each line of the form PH<N> <consumes-CSV> -> <produces-CSV> @ <paths-CSV>. Empty left of -> = source (no consumed IFs). Empty right = sink. Collect Owns (@), Consumes (left), Produces (right) per phase. For each IF in Consumes, look up its kind in ### Interfaces: [blocks] = blocking edge (creates wave boundary), bare = non-blocking (ignored by topo-sort).
Wave derivation:
- Wave 1: phases with no blocking Consumes (their consumed IFs are all non-blocking, or they consume nothing).
- Wave N+1: phases whose every blocking Consumes IF is produced by phases in waves 1..N.
- Repeat until all phases are assigned.
Disjointness check:
Before dispatching a wave, verify the @ sets of all phases in that wave are pairwise disjoint. On overlap: halt, log the conflicting paths under ### Deferred (needs user input), do not dispatch.
Dispatching the wave:
Do NOT dispatch one implementer, wait for its result, then dispatch the next — that is sequential, not parallel, regardless of how the preamble reads. If you announce "Wave: PH2 + PH3 in parallel" and your next message contains exactly one Agent call, you have lied to the user. Stop and re-dispatch all wave phases together.
Choose up:implementer or up:implementer-sonnet per phase using "Choosing the implementer agent" above. Pass commit: defer to each (AS3 — only the dispatcher touches git in defer mode). Include Owns, Implements, Consumes from the graph line (IF3). A consumer is dispatched in parallel with its producer; the IF declaration in ### Interfaces is the consumer's ground truth for signatures it depends on.
Serialized commit protocol:
After all Agent calls in the response return, process successful implementers in ascending PH order:
Only after all successful phases are committed, handle failures.
Failure handling:
- On
BLOCKEDorNEEDS_CONTEXTfrom one phase: do not abort sibling phases mid-work. Wait for all siblings to return, commit their successful results per the protocol above, then diagnose the failure — re-dispatch with corrected context, invokeup:uplanif the plan is wrong, or stop and log under### Deferred (needs user input)(PC4). - A failure in one phase never rolls back a sibling's already-committed work.
Wiring check
Runs once, after the final wave's phases commit (IF6). For non-blocking IFs, consumers were dispatched in parallel against the IF declaration rather than against the producer's actual output — this check is the reconciliation step, catching every place a producer drifted from the declared signature.
TDD
If Design recorded TDD: yes, invoke up:test-driven-development for each unit under test:
- Write the failing test, watch it fail for the right reason
- Write the minimal implementation to pass
- Refactor with tests green
- Commit
If TDD: no, skip the test-first loop; verification happens in up:uverify.
When to dispatch up:explorer
- The implementer reported
NEEDS_CONTEXTand a code map would unblock them - You need a call graph or execution path beyond what a quick Grep gives
- You need a ranked list of essential files for a feature
Dispatch with tight scope and pass the working directory explicitly. Don't over-use — inline Grep/Read beats a subagent for one-shot lookups.
Dispatch prompt skeleton:
Scope: <what to trace — feature name, entry point, or specific question>
Working directory: <absolute path>
When to dispatch up:researcher
- You need external info: library docs beyond a quick Context7 lookup, how other projects solve a problem, SOTA landscape, cross-source tradeoffs
- The question spans web + library docs + current codebase and needs synthesis
If the question is purely about the current codebase, prefer up:explorer. If it's a single doc lookup, inline Context7 is enough.
Dispatch prompt skeleton:
Question: <the research question, in the shape you want the answer to take>
Sub-questions: <optional — pre-decomposed bullets if you already know the shape>
Working directory: <absolute path, if codebase context is relevant>
Scope hints: <optional — preferred sources, depth, time budget>
Consistency pass — when changing a pattern, sweep for others
Incidental code smells
Implementers and up:explorer report smells they pass; you also hit them while reading code to coordinate. For each: fix it in the same commit when it's in task scope or an easy, low-risk win (Boy-Scout); otherwise append it to the task file's ## Code smells section — file:line — one-line smell — and leave it for review's Future-work call. Don't let out-of-scope smells balloon the change. See _principles.md → Incidental code smells.
Don't modify upstream specs or external design docs
Never edit the plan inline to hide a deviation. Never silently edit an external spec. Deviations live in the task file's ## Conclusion → Deviations from plan section.
Forbidden: inventing fallbacks, defaults, or best-effort behavior
Never add try: ... except: pass. Never catch a broad exception to "keep going". Never substitute a placeholder value so the code "works for now".
If the plan is silent on what to do when X is missing, the answer is: let it raise. Then tell the user this is a potential failure point and add it to the task file's ## Conclusion as a known risk.
This hides real bugs. "anonymous" user_ids leak into downstream systems. 30s timeouts mask misconfigured services.
Then append to the task file's ## Conclusion under "Known risks":
- config["timeout"] will KeyError if config is partial. Plan didn't specify a default; recommend either adding one with user approval, or validating config at load time.
Raise these potential failure points with the user immediately, not after execute completes.
Deviations from plan
A deviation is any structural change from what the plan says. File moved to a different location, method signature different, phase ordering swapped, a phase cut, a phase added.
- Do not edit the Plan inline. The plan is the contract that was approved; it stays as-is for the review.
- Record the deviation in the task file's
## Conclusionunder a### Deviations from plansubsection (create if missing). Format:- <what changed> — <why>. If no deviation happens, do not create the subsection at all — per_brevity.md, empty subsections are deleted, not written. - If the deviation is minor (renamed a helper, swapped two steps) — continue execution.
- If the deviation is structural enough that later phases in the plan no longer apply — stop executing. Invoke
up:uplanwith enough context (what was done, what no longer applies, what new reality is). Let the planner skill update the plan before resuming.
Appended to ## Conclusion:
- Phase 3: used existing
cache.backend.CacheBackendinstead of creating a new one.
Continuing to phase 4 — later phases are unaffected."
When to stop and ask
- A plan instruction is ambiguous or self-contradictory
- A dependency the plan assumes is missing
- A test fails in a way that suggests the plan is wrong (not just the implementation)
- Verify would obviously fail even after you finish
- You're about to invent a fallback / default / catch-all
Don't force through. Ask. This list applies in both interactive and hands-off modes — it defines the "genuinely impossible without user input" exception. Log each such stop under ## Conclusion → ### Deferred (needs user input) in hands-off mode.
Hands-off mode
See up:handsoff for the full contract, including the safety principles (worktree-first, no destructive git ops, no push to remote, additive-over-subtractive edits). Stage-specific delta: execute's own behavior is unchanged — the existing fail-fast rules and "when to stop and ask" list above are the hands-off handling. Each such stop is logged under ### Deferred (needs user input) with enough context for the user to resume.
Never invent a default to keep moving. Conservative = fewer assumptions = stop and log.
Never
- Start on
main/masterwithout explicit user consent if the plan specified a branch - Skip the commit between phases
- Claim complete without running what you built
- Push to remote without explicit user consent
- Edit the Plan section to hide a deviation
- Edit an upstream spec file during execute (flag issues, don't mutate)
- Invent a silent fallback to avoid stopping
- Commit without running the plan-diff check and consistency pass
Terminal state
All phases done and committed → invoke up:uverify. Do not skip to review. Do not finish the branch yourself.