name: execute-issue-plan
description: Implement the approved plan for a GitHub issue. Run from inside the feature worktree. Usage: /pipeline:execute-issue-plan
disable-model-invocation: false
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Skill, mcp__playwright_*
Boot
Subagent invocations run in fresh shells, so source pipeline.config first:
source "$(pwd)/pipeline.config" 2>/dev/null || source ./pipeline.config
# Self-resolve CLAUDE_PLUGIN_ROOT in case the env var is unset in the Bash subshell.
# Anchor via the plugin cache glob (var-independent — no chicken-and-egg dependence on
# CLAUDE_PLUGIN_ROOT to FIND the resolver). _cpr_dir is the dir prefix; literal source line.
_cpr_dir="${CLAUDE_PLUGIN_ROOT:+${CLAUDE_PLUGIN_ROOT}/}"
_cpr_dir="${_cpr_dir:-$(ls -d ${HOME}/.claude/plugins/cache/claude-pipeline-local/pipeline/*/ 2>/dev/null | sort -V | tail -1)}"
_cpr_dir="${_cpr_dir:-$(ls -d ${HOME}/.claude/plugins/cache/claude-pipeline/pipeline/*/ 2>/dev/null | sort -V | tail -1)}"
source "${_cpr_dir}scripts/_resolve-plugin-root.sh" 2>/dev/null || true
State (slate, base branch, repo) is inherited from /pipeline:fullsend; if these variables fail to resolve, STOP — preconditions live in skills/fullsend/SKILL.md.
Lifecycle
worktree spawn → inline orchestrator-owned Agent(tdd-implementer) fan-out (PATH C, DEFAULT; spawn-claude tdd-implementer only under `--spawn`) | inline Agent (PATH A/B, PATH D tdd) → push → PR
Invocation mode
Every step below behaves identically across modes — only the working-directory setup differs:
| # | Mode | CWD setup | Used by |
|---|---|---|---|
| 1 | Inline Agent(...) dispatch |
cd <worktree-absolute-path> (prompt provides it) |
PATH A (docs-only), PATH B (standard) |
| 2 | Inline orchestrator-owned Agent(tdd-implementer) fan-out (DEFAULT); spawn-claude.sh / claude -p dispatch only under fullsend --spawn |
each leaf cds into its OWN per-leaf worktree (path-c-split-worktree.sh setup); orchestrator reassembles into the feature worktree via cherry-pick (#896) |
PATH C (multi-task) |
| 3 | PATH D inline tdd-implementer | cd <worktree-absolute-path> (same as mode 1) |
PATH D (quick-fix) |
Collapsed inline D contract
When dispatched as the collapsed PATH D agent (mode 3), this agent is the PRODUCER of the classify + plan stages, not a downstream consumer of upstream-posted comments. It RUNS classify and plan inline FIRST — emitting the two stage records as inline side-effect checkpoints (see below) — and THEN carries that context straight into execution. So this agent carries the classify+plan context forward within its own single session and does NOT re-read the plan comment from GitHub: there is no separate plan-comment fetch (step 1's gh issue view ... ## Implementation Plan read is skipped on PATH D, and because the plan is already in-context the STOP-on-empty guard never fires). The two inline side-effect checkpoints, byte-shaped exactly as the standalone classify/plan stages would have posted them, are:
- a
## Classificationcheckpoint carrying the recommended path label (quick-fix/ PATH D); - a
## Implementation Plancheckpoint with theplan-pendingmarker.
Escalation backstop. The collapsed D agent runs inside D's small envelope (the ## Affected areas prediction: one file, ≤ ~20 LOC, single precedent). If mid-run it discovers the change exceeds D's envelope — it touches more files than ## Affected areas predicted, needs a real plan, or hits unforeseen coupling — it does NOT force a too-large change through the D lane. It aborts up / escalates to a full PATH B run: real planning plus a full execute session (per #748 PATH B execute now runs as an inline Agent, not a spawned claude -p worker). This is what makes a wrong B→D down-route cheap and recoverable — the backstop reverses it rather than shipping a too-large diff through D.
Execution Agent
You will receive an issue number as the argument. Ensure CWD is the feature worktree (per the table above), then perform these steps:
Steps
0b. CI-fix mode. If $PIPELINE_CI_FIX_CONTEXT is non-empty, you were dispatched to fix a red CI run on an existing PR — not to implement a new plan. Skip steps 1–4 and step 9. Read the failure log at $PIPELINE_CI_FIX_CONTEXT and run gh pr diff to see the PR so far. Diagnose the failure, apply red→green→commit TDD discipline for the fix, run step 6 (Validate) once, then push the follow-up commit to the existing branch with git push. Do NOT call gh pr create. Do NOT change the pr-open label. Report the new commit SHA back to the orchestrator.
Fetch the approved plan — find the latest comment containing
## Implementation Plan(latest wins, supports revisions). PATH D skip: the collapsed inline D agent carries the classify+plan context forward and does NOT re-read the plan comment (see the Collapsed inline D contract above) — skip this fetch on PATH D and use the in-context plan.gh issue view <N> --repo $PIPELINE_REPO --json comments \ --jq '[.comments[] | select(.body | contains("## Implementation Plan"))] | last | .body'If empty/
null, STOP: "No implementation plan found on issue #N. Run/pipeline:plan-issue Nfirst."Then list every file under
.claude/scratch/issue-<N>/— screenshots/binary evidence the planner saw, mirrored into this worktree bysetup-worktree.sh/sync-worktrees.sh(this skill does NOT re-fetch):ls -1 .claude/scratch/issue-<N>/ 2>/dev/null || echo "(no attachments)"For each file printed by
ls -1, invoke theReadtool exactly once before implementing. If the directory is empty or absent, continue.Read project conventions: Read
CLAUDE.mdin the worktree root.Dependency check — issue #5 only: If this is issue #5 (project-numbers), verify
feature/schema-cleanuphas merged:gh pr list --repo $PIPELINE_REPO --state merged --json headRefName --jq '[.[].headRefName]'If absent, STOP: "Issue #5 is blocked — feature/schema-cleanup has not been merged yet."
Mark as in-progress:
gh issue edit <N> --repo $PIPELINE_REPO --add-label "in-progress" --remove-label "plan-approved"Implement the approved plan. Follow the plan's
**Tasks (ordered):**section exactly — it carries the path-specific Task 0 directive (PATH A: flat edits; PATH B: invokesuperpowers:test-driven-development; PATH C: dispatchtdd-implementersubagents withtarget=<dir>sentinels).PATH B split-role two-phase execute (#881 —
PIPELINE_PATH_B_SPLIT_ROLE=true). When split-role is enabled, PATH B execute splits the red→green discipline across two roles in this same worktree:- Phase (i) — Opus test-author authors+commits the locked suite. The Opus test-author writes the full failing suite per the approved plan, confirms each test is red-for-the-right-reason, and makes a single commit carrying the literal
[split-role-red]substring in the commit subject. Pre-existing-test updates (golden refresh, changed contract) belong IN that commit — never in a later commit. - Phase (ii) — implementer greens additive-only. The implementer must complete ALL approved-plan tasks — including non-test deliverables (docs, fixtures, example artifacts) the locked suite does not exercise — not merely green the locked suite. Greening the locked suite is necessary but NOT sufficient for plan completeness. The implementer greens the suite test-by-test. It may ADD new tests but must never modify or delete a locked
[split-role-red]test (the W7 eval-time gate,scripts/split-role-gate.sh, blocks the PR onlocked-test-modified/locked-test-deleted). Shared-test carve-out (#1089): the green implementer may modify a test file ONLY if the approved plan explicitly lists it under**Shared tests (split-role):**— otherwise green touches NOTHING undertests/. The eval stage threads the plan's listed paths into the gate asPIPELINE_SPLIT_ROLE_SHARED_TESTS(exact-path, default-deny; deletions of a listed file still block). Before committing/pushing andgh pr create, the implementer MUST run the FULL local suite green ($PIPELINE_TEST_CMDvia Step 6b — not just the locked[split-role-red]files): a green-introduced break in any non-locked test (e.g. a contract test the locked suite does not exercise) must be caught locally, not in CI (mirrors thecheck-branch-cruft.shpre-PR guard shape, #1108). - Escalation valve. If the implementer concludes a locked test is WRONG, it does NOT silently contort the implementation to satisfy it — it STOPs and reports (same shape as the PATH D envelope-escalation backstop above). The orchestrator then returns that test to Opus, which amends the
[split-role-red]suite; the implementer resumes greening.
PATH C (
multi-task) — inline orchestrator-owned fan-out with per-leaf worktrees (DEFAULT). On PATH C the orchestrator itself reads the## Implementation Planand, for eachtarget=<dir>in the plan, dispatches one leafAgent(subagent_type='tdd-implementer', description='target=<dir>/ ...', prompt='cd <leaf-worktree>; target=<dir>/ ...'), then handles push +gh pr create+ label flip itself (Steps 9–10). The orchestrator MUST NOTEdit/Writeimpl files directly: theenforce-path-c-delegationhook blocks direct orchestrator Edit/Write and authorizes only files under a dispatchedtarget=<dir>sentinel.tdd-implementerstays a hard leaf executor (theAgenttool is removed from its toolset) dispatched from the top level — no grandchild dispatch. Each dispatch carries a real-subdirectorytarget=<dir>/sentinel (target=././//are rejected by the hook) and applies red→green→commit autonomously.Per-leaf worktrees (the #896 fix — eliminates the shared-index race). Each leaf gets its OWN worktree+branch off the feature-branch worktree HEAD, so concurrent leaves never share a git index. Without this, leaves committing in the same worktree race: transient
index.lockcollisions and one leaf's files swept into another leaf's commit (the #894 c+d collision), breaking per-target commit isolation and the per-PR CHANGELOG granularity contract. Drive it withscripts/path-c-split-worktree.sh:- Setup — for each
target=<dir>:LEAF=$(bash "${CLAUDE_PLUGIN_ROOT}/scripts/path-c-split-worktree.sh" setup <feature-worktree> <target>); dispatch that target's leaf withcd $LEAFin its prompt. - Reassemble — after ALL leaves report committed:
bash "${CLAUDE_PLUGIN_ROOT}/scripts/path-c-split-worktree.sh" reassemble <feature-worktree> <target> [<target> ...]cherry-picks each leaf's commits onto the feature branch (disjoint targets ⇒ conflict-free; cherry-pick is a git op so it does NOT tripenforce-path-c-delegation). A conflict means the targets were not actually disjoint — the helper aborts and errors; re-plan the overlap rather than forcing it. - Teardown —
bash "${CLAUDE_PLUGIN_ROOT}/scripts/path-c-split-worktree.sh" teardown <feature-worktree> <target> [<target> ...]removes the leaf worktrees + branches before push.
Because each leaf has an isolated index, concurrency is bounded only by orchestrator context, not by a git-index cap — the live branch test (#894/#896) confirmed leaf returns are ~one line each with negligible context cost, so non-overlapping targets may fan out fully concurrently (keep leaf returns terse). Under
fullsend --spawn, PATH C reverts to the legacyspawn-claude.sh→tdd-implementerfan-out (the reversible escape hatch, #750) — same per-target sentinel + TDD discipline, different transport; the spawned path already isolates per worker so it needs no split-worktree step.On PATH D (label
quick-fix), you ARE tdd-implementer — apply red→green→commit directly inline in a single pass: single failing test → impl → pass → commit, once. No subagent dispatch, no skill invocations beyond this one. This is single-pass discipline, not ceremony: the failing-test gate (red→green→commit) is mandatory and is NOT skipped — what PATH D drops is the redundant pre-PR review double-check (Step 8, see the PATH D early-return contract below), sinceevaluate-issue-pris D's sole external review gate. (And if the change turns out to exceed D's envelope mid-run, escalate per the Collapsed inline D contract above rather than forcing it through.)On
needs-browserissues, eachtdd-implementerdispatch (PATH C) or inline TDD task (PATH B/D) treats the predicates section as the test specification.spawn-claude.sh's--append-system-promptmay inject path-specific skill invocations viaPIPELINE_PATH_<X>_SKILLS_EXECUTE+PIPELINE_PATH_<X>_SKILL_ARGS_EXECUTE_*. Step 8 below owns the review flow explicitly, so leavePIPELINE_PATH_<X>_REVIEWER_EXECUTEunset; if set, the end-of-session dispatch becomes a harmless redundancy.When a test inits a temp git repo (
mktemp+git init) and commits, stamp an identity — callgit_init_sandboxfromtests/_lib/git-sandbox.sh, or use inlinegit -c user.email=… -c user.name=… commit. A baregit commitin a temp repo passes locally but fails CI with exit 128 (no global identity).In all cases: implement ONLY what the plan specifies (no scope creep); never commit to main; never use
--no-verifyor--force. If the plan/issue references a GH Actions CI-blocking marker (bracketed forms ofskip ci,ci skip,skip-ci,ci-skip,no ci,no-ci, plus***NO_CI***), do NOT propagate the literal marker into anygit commit -m,gh pr create --title, or--body— substitute a safe form: backticked`skip ci`, hyphenatedskip-ci, orskip CI(no brackets). Thecheck-ci-skip-markersPreToolUse hook blocks the literal form.- Phase (i) — Opus test-author authors+commits the locked suite. The Opus test-author writes the full failing suite per the approved plan, confirms each test is red-for-the-right-reason, and makes a single commit carrying the literal
Validate — types, tests, server, and UI. Fix any failures at each sub-step before proceeding.
6a. Type check:
$PIPELINE_TYPECHECK_CMD6b. Run tests (single sequential pass, stdin-guarded). Run the configured
$PIPELINE_TEST_CMD— the targeted/relevant test command for this project. Do NOT improvise an unboundedfor t in tests/test*.sh; do bash "$t"; donesweep over unrelated tests: it pulls in tests this issue did not touch, any one of which may block on an interactiveread. Always redirect stdin from/dev/nulland bound each run withtimeoutso a single interactive or hanging test cannot wedge the executor:timeout 600 bash -c "$PIPELINE_TEST_CMD" </dev/nullRun exactly ONE verification pass at a time — never launch concurrent full-suite invocations. Concurrent runs of stub/temp-file-sharing tests collide and report spurious failures, driving wasteful retry spins (issue #677). Before reaching this phase, the issue's OWN targeted test MUST already be green: a source edit that leaves the targeted test red is a red→green→commit violation — fix it (red→green→commit) before verification. Never commit past a red targeted test.
Run the suite SYNCHRONOUSLY in the foreground and read its exit code directly (the
timeout 600 bash -c ...line above runs in the foreground; its exit code is the result). Do NOT background a test monitor and thenReadits/tmp/...output to learn the result: the dogfood boundary hook (restrict_paths.py) blocks reads under/tmp(outside the project boundary), so theReadfails and the agent narrate-and-yields — narrating an intention to "wait" ends the turn and strands committed-but-unpushed work (the #752 / #759 / #750 drop-out that the #764 dispatch-prompt band-aid did NOT durably fix). Never narrate "I'll wait for the suite" and stop; the suite has already finished synchronously when the Bash call returns. If async monitoring is ever genuinely required, write monitor output INSIDE the project boundary (.claude/logs/or.claude/scratch/, both allow-listed), never/tmp. Monitor-yield ban (#912): an agent must NEVER yield on a backgroundMonitorit cannot resume across a turn boundary. The #912 recurrence (#838/#904) was exactly this — the agent narrated "...Waiting for the sweep Monitor..." and ended its turn; a dispatched Agent's turn ends the moment it stops emitting tool calls, so this strands committed-but-unpushed work. The suite runs SYNCHRONOUSLY in the foreground and its exit code is read directly (the contract above); if async monitoring is genuinely required, the agent MUST instead block via a boundedBashOutputpoll to a terminal sentinel inside the project boundary — never narrate-and-yield on an un-awaitable backgroundMonitor. 6c. Visual validation with Playwright (Linux only, UI changes only): use Playwright MCP tools (configured in.mcp.json) to navigate to the frontend URL, screenshot affected views, and checkbrowser_console_messagesfor JS errors. Fix and re-validate any visual issues. Backend-only changes do not require this step. (When clicking, prefer theref=frombrowser_snapshotover CSS selectors with embedded quotes like[type="submit"]— the MCP server rejects the latter on the literal string; as of 2026-05-26.)6d. Visual proof loop (needs-browser issues only): If the issue carries the needs-browser label, after each plan section invoke
Skill(skill: "pipeline:visual-proof-from-plan")passing the plan comment body. Iterate code→proof→code per section until the sub-skill reportsunsatisfied = []. Commit the section. Proceed to the next section. This is the executor-side TDD loop with browser predicates standing in for unit tests; it does NOT replace 6a/6b which still run.6e. Config-drift check. Run the config-drift lint to catch any new
PIPELINE_*variable introduced in this branch that is not yet documented inpipeline.config.example(and vice-versa):bash scripts/check-config-drift.shAssert exit 0. If it exits 1 with an
UNDOCUMENTEDfinding, add the new variable topipeline.config.example(with a comment describing its purpose) or add it totests/config-drift-allowlist.txtwith a justification comment if it is intentionally undocumented. If it exits 1 with anORPHANfinding, remove the dead knob frompipeline.config.exampleor add it to the allowlist. Fix the finding and re-run until exit 0. This catches config drift in-leaf so CI is not the first to surface it.Self-review checkpoint before opening PR. Re-read the plan from step 1 and verify every item was implemented; run
git diff --statto check no unintended files were modified; grep for leftover debug code (console.log,print(,debugger,TODO,FIXME); verify no scope creep. Fix any issues found before proceeding.Pre-PR code review loop.
PATH D early-return contract. If labels contain
quick-fix(PATH D), SKIP Step 8 in its entirety (8a–8e) and proceed to Step 9. What is skipped: the pre-PR code review loop — author self-check, independent reviewer dispatch, triage, fix commits, re-validate. Why: PATH D issues delegate review entirely toevaluate-issue-prto keep the lane fast (one external review gate, not two). This is the contractclassify-issuedepends on when applying thequick-fixlabel — seeskills/classify-issue/SKILL.md(PATH D row).For all other paths, Step 8 runs BEFORE
gh pr createto catch plan-compliance gaps and real bugs while the branch is still local-only.8a. Author self-check. Invoke
superpowers:requesting-code-reviewwith the plan comment body (from step 1) as context. The skill verifies plan requirements are met, tests pass, and CI-equivalent checks are green locally. Fix any gaps and re-run step 6 before continuing.Skill(skill: "superpowers:requesting-code-review")8b. Independent reviewer dispatch. Dispatch a separate code-reviewer subagent (returns a list of findings or "LGTM"):
Agent( subagent_type: "superpowers:code-reviewer", description: "Independent review of the implementation for issue #<N> against the approved plan", prompt: "<full plan comment body + git diff $PIPELINE_BASE_BRANCH..HEAD — flag plan-compliance gaps and real bugs; do not refactor>" )Step 8's review flow is synchronous —
Skill(...)andAgent(...)calls block until they return, so there is no poll loop to bound here. If a future revision adds background-task coordination, it MUST wait viascripts/wait-for-sentinel.sh(bounded timeout), never an inlineuntil grep ...; do sleep N; donepoll (see Constraints).8c. Triage findings. Invoke
superpowers:receiving-code-reviewwith the reviewer's output. The skill classifies each finding as must-fix (plan-compliance gap, test gap, real bug → fix), nice-to-have (style, rename → skip unless trivial), or incorrect (reviewer misread → reject with a one-line rationale in the follow-up commit message).Skill(skill: "superpowers:receiving-code-review")Path-specific constraints when applying must-fixes:
- PATH C (
multi-task): any must-fix touching impl code MUST go through a fresh inlineAgent(tdd-implementer)dispatch (or a spawned worker under--spawn) — theenforce-path-c-delegationhook blocks direct orchestratorEdit/Writeon impl files regardless of transport. - PATH B (standard): must-fix code edits follow red→green→commit discipline.
- PATH A (
docs-only): must-fix edits are direct. - PATH D (quick-fix): step 8 is skipped entirely (see early-return contract above); this row only applies on forced re-entry.
8d. Commit fixes. Commit each must-fix as its own
fix(review): ...commit (skip if zero must-fixes).8e. Re-validate. Re-run step 6 once more to confirm the review fixes did not regress anything.
- PATH C (
Open a pull request.
Before opening the PR, run the
check-branch-cruft.shguard (wired below, between 9a and 9b) — a mechanical backstop for the explicit-staging Constraint; it fails the open if any cruft path reached a commit on this branch (#1028).9a. Derive the PR title from the issue. The PR title must be a strict Conventional-Commits string (
feat|fix|chore|refactor|docs|ci|perf|test|build|style|revert(<scope>)?: <summary>) so release-please can drive versioning + CHANGELOG. Issue titles are intentionally expressive (bug(...),epic(...),skill: ...) and must NOT pass through verbatim. Run the helper:PR_TITLE=$("${CLAUDE_PLUGIN_ROOT}/scripts/derive-pr-title.sh" <N>) rc=$? if [ "$rc" -eq 2 ]; then # exit 2 = tracker (epic title or `tracker` label) — these never get PRs. echo "ABORT: Issue #<N> is a tracker (epic title); trackers don't get PRs. Close the issue or rename it." >&2 exit 1 elif [ "$rc" -ne 0 ]; then echo "ABORT: derive-pr-title.sh failed with exit $rc for issue #<N>" >&2 exit 1 fiRule table (source of truth:
scripts/derive-pr-title.sh):Order Condition Action 1 Labels include trackerexit 2 (refusal) 2 Title matches ^epic\(exit 2 (refusal) 3 Title is already Conventional Commits passthrough 4 Title matches ^bug\(<scope>\):rewrite to fix(<scope>): <rest>5 Labels include bugfix(<scope-or-general>): <summary>6 Labels include enhancementfeat(<scope-or-general>): <summary>7 default chore(general): <summary>Pre-PR cruft guard (#1028). Before
gh pr create, run the guard against the committed branch-vs-base diff — this is the defense-in-depth backstop for the explicit-staging Constraint above (mirrors the base-branch-enforcement layering: prose directive → mechanical guard). It fails the open if any committed path on this branch is denylisted cruft (e.g..claude/migration-cleanup-*):# Pre-PR cruft guard (#1028): fail if any committed path on this branch is denylisted cruft. bash "${CLAUDE_PLUGIN_ROOT:-.}/scripts/check-branch-cruft.sh" \ || { echo "ABORT: branch-vs-base diff contains cruft paths (see above); drop them from the branch before opening the PR." >&2; exit 1; }Pre-PR config-drift guard (#1102). After the cruft guard and before
gh pr create, run the whole-tree config-drift lint — the same check CI runs — so undocumentedPIPELINE_*vars are caught in-session rather than as a CI-fail → evaluator-re-watch loop:# Pre-PR config-drift guard (#1102): fail if any PIPELINE_* var is undocumented. bash "${CLAUDE_PLUGIN_ROOT:-.}/scripts/check-config-drift.sh" \ || { echo "ABORT: undocumented PIPELINE_* drift detected (see above); add the allowlist entry or document in pipeline.config.example before opening the PR." >&2; exit 1; }9b. Open the PR. Quote the
--basevalue and guard against an unsetPIPELINE_BASE_BRANCH: even whenenforce-base-branch.pyis absent or unregistered, the executor must pass--basequoted and non-empty so the eval-timebaseRefNameassertion inevaluate-issue-prStep 11 has a meaningful base to compare against. This is the second of three defense-in-depth layers (PreToolUse hook → this guard → eval-time check).if [ -z "$PIPELINE_BASE_BRANCH" ]; then echo "FATAL: PIPELINE_BASE_BRANCH unset; refusing to call gh pr create" >&2; exit 1; fi gh pr create \ --repo $PIPELINE_REPO \ --title "$PR_TITLE" \ --base "$PIPELINE_BASE_BRANCH" \ --body "$(cat <<'EOF' Closes #<N> ## Summary <bullet points summarising what changed> ## Test plan - [ ] `PIPELINE_TEST_CMD` — all tests pass - [ ] Feature works end to end EOF )"$PR_TITLEis normalized byscripts/derive-pr-title.sh: any literal../substring is rewritten to..⁄(U+2044) before reaching this site — defense-in-depth against any PreToolUse hook that scans for path-escape substrings. Both--titleand--bodyare also scanned by thecheck-ci-skip-markershook; to describe a marker in the PR body, wrap it in backticks (e.g.`[skip ci]`) so GH Actions does not honor it.Mark as pr-open:
gh issue edit <N> --repo $PIPELINE_REPO --add-label "pr-open" --remove-label "in-progress"Report: "PR opened for #N:
" Terminal state — STOP (Step 12). Once Step 10 has applied the
pr-openlabel and Step 11 has emitted the report line, the executor's work is DONE: the PR is confirmed open and all commits are pushed. This is the agent's terminal state — STOP here. Do NOT run any post-PR self-verification, "confirm PR opened" re-check, cleanup, or wait/poll loop: once thepr-openlabel is applied and the PR is confirmed open, the worktree handoff toevaluate-issue-pris the orchestrator's job, and any lingering session holds the worktree + a concurrency slot and BLOCKS PR evaluation (a secondclaudesession cannot safely run in the same worktree — issue #631). There is nothing left to wait for; emit the report line and end the session. (CI-fix mode (Step 0b) has its own terminal contract — report the new commit SHA and stop — and never reaches Step 10/11, so it is unaffected.)
Handling evaluation feedback
If evaluate-issue-pr flags the PR while the executor session is still active, invoke superpowers:receiving-code-review with the evaluation comment as context: Skill(skill: "superpowers:receiving-code-review").
Constraints
- Implement ONLY what the approved plan says.
- Stage ONLY the explicit plan-related paths with
git add <path> [<path>...]. NEVER usegit add -A,git add ., orgit add -u— these sweep pre-existing untracked repo-root cruft (e.g..claude/migration-cleanup-*advisory-scanner output) into the branch (#1015/#1028). Enumerate the paths the plan changed and stage exactly those. Thescripts/check-branch-cruft.shpre-PR guard (Step 9) backstops this against the committed branch diff. - Git-anchoring + branch-assert (#1106 root-cause fix). All git commands MUST be anchored with
git -C <worktree-abs-path>— do NOT rely on cwd persisting across Bash calls (the Bash tool resets to the project root on each fresh invocation; the #1106 RED commit landed onstagingbecause its initialcd <worktree>did not hold for the latergit commit). AND: before ANY commit, ASSERTgit -C <worktree-abs-path> symbolic-ref --short HEADequals the feature branch — if it does not, STOP and report (do not commit). This applies to PATH B split-role RED/GREEN phases, the collapsed-D inline path, and PATH C per-leaf dispatches. The dispatch-site prompts (skills/fullsend/SKILL.mdStep 6) carry this same directive so a dispatchedgeneral-purpose/tdd-implementersubagent that never loads this skill body still receives it. Worktree-index staging precondition (#1122 — mirror of dispatch-site contract). Before ANYgit add, stage only into this worktree's OWN index — everygit addMUST be anchoredgit -C <worktree-abs-path> add <paths>, NEVER a baregit add(cwd may resolve to the main checkout) and NEVERgit -C <main-repo> add. Linked worktrees have separate index files; a correctly-anchoredgit addcannot leak into the main checkout index (the #1122 leak: a split-role subagent's baregit addhit the MAIN checkout index instead of the worktree index, leaving staged edits that blocked the inter-leggit pull --ff-only). ThefullsendStep 6a clean-main guard (verify-execute-completion.sh --clean-main) detects and auto-recovers from such leaks (auto-stash before base advance), but the positive precondition here is the preventive layer — defense-in-depth: dispatch-site prompt + skill body carry the same directive. - Never commit to main.
- All PRs target
PIPELINE_BASE_BRANCH(the configured base), nevermain. Always pass--base "$PIPELINE_BASE_BRANCH"(quoted) togh pr create. - Never use
--no-verifyor--force. - Never skip build verification (
PIPELINE_TEST_CMDfrom the sourced config). - Verification (Step 6b) is a single sequential
$PIPELINE_TEST_CMDpass wrapped with</dev/null+timeout; never improvise an unboundedfor t in tests/test*.shsweep over unrelated tests, and never launch concurrent full-suite runs (concurrent self-colliding suite runs report spurious failures — issue #677). - Never inline unbounded sentinel-file polls (e.g.
until grep -q TOKEN file; do sleep N; done). Usescripts/wait-for-sentinel.sh <file> <token> [--timeout N](default 600s) — on timeout it exits non-zero with an actionable error so the Bash tool surfaces failure instead of wedging. Thecheck-unbounded-sentinel-pollslint enforces this in CI. - Executor does NOT merge PRs. All merging is handled by the pipeline orchestrator.
- Terminal after
pr-open: once thepr-openlabel is applied and the PR is confirmed open, STOP. Never run a post-pr-openself-verification, "confirm PR opened" re-check, or wait/poll loop — a lingering executor holds the worktree + concurrency slot and blocksevaluate-issue-pr(issue #631).