/workflow-feature — full task lifecycle in a single workflow
Inputs
- The user's request (the current message) — or an existing contract path.
- The request may be a Linear issue URL or bare key instead of a description (see below).
- READ
${CLAUDE_PLUGIN_ROOT}/harness/HARNESS.md first.
Actions (in order)
- Run
git status --short (respect in-flight changes — do not touch them).
- If the argument is a Linear reference — a
https://linear.app/<workspace>/issue/APL-1/... URL or a
bare key like APL-12 — resolve it before invoking the workflow:
- Read it with
"${CLAUDE_PLUGIN_ROOT}/poller/lin" issue view <KEY> — one Bash call, no tool schema to load. Prefer this
over the Linear MCP: ToolSearch + get_issue costs a schema load and a tool round-trip, and the
MCP server is not always connected (in dispatched sessions the Linear MCP never finished connecting, so the
follow-up-filing step there was unsatisfiable by construction).
lin is linear-cli reading the OAuth token the Linear poller keeps refreshed. Do not use a
pinned LINEAR_API_KEY or .linear.toml: Linear access tokens expire every 24h, so a copied one
works for a day and then fails with a 401 that reads like a network fault.
- Pass the issue's title + full description as
task (e.g.
task: 'APL-1 — <title>\n\n<description>'). The description is the spec: the issues in this
workspace are written with Goal / Evidence / Acceptance sections, which map almost directly onto the
contract template. Do not paraphrase or summarise the acceptance criteria — pass them through.
- Pass the key as
issueId. It drives the branch (claude/APL-1), the contract filename
(apl-1-<slug>.md), the commit subject, and the PR body's Closes APL-1.
- If
lin fails (no token, revoked app), pass the reference through as-is: the workflow's CONTRACT AUTHOR
resolves a reference-only request itself as a fallback. Say which path you took.
- A non-Linear argument is unaffected — pass the request verbatim exactly as before.
- Post a start comment before invoking the workflow (Linear reference only):
"${CLAUDE_PLUGIN_ROOT}/poller/lin" issue comment list <KEY> | grep -q 'harness:<KEY>:dispatched' \
|| "${CLAUDE_PLUGIN_ROOT}/poller/lin" issue comment add <KEY> --body '<!-- harness:<KEY>:dispatched -->
🔧 Harness run started — contract → implement → audit → gate → PR → review. Next comment lands when the PR opens.'
Every other Linear write in this skill happens in step 5, after the workflow returns — which is 20-40
minutes later. Without this one the board shows nothing at all for the whole run, and a delegated issue
sitting silent is indistinguishable from a dispatch that never fired. That ambiguity is what the poller's
own failure comment exists to remove; the run itself needs the same. The marker makes it idempotent, and
a failure here is never a reason not to start the workflow.
- Read the cycler config first, so the run uses this repo's settings rather than defaults:
node "${CLAUDE_PLUGIN_ROOT}/harness/read-config.mjs" repo.base main
node "${CLAUDE_PLUGIN_ROOT}/harness/read-config.mjs" repo.branch_prefix claude/
node "${CLAUDE_PLUGIN_ROOT}/harness/read-config.mjs" repo.path ""
node "${CLAUDE_PLUGIN_ROOT}/harness/read-config.mjs" --json
echo "${CLAUDE_PLUGIN_ROOT}"
Pass those as prBase, branchPrefix, cwd, config and pluginRoot below. A repo with no
config gets the defaults, which are the values shown in those commands — nothing breaks,
nothing is silently shaped like somebody else's repo.
cwd and pluginRoot are not optional. The Workflow runtime exposes args, agent,
parallel, pipeline, log, phase and budget — there is no process, so the workflow has
nothing to fall back on and throws immediately if either is missing. It used to fall back to
process.cwd(), which is a ReferenceError in that runtime: the script died on its first line
and every unattended dispatch left no branch and no PR.
The workflow's audit and review stages are subagents, and you must let them run. A repo may carry a
rule against spawning subagents to work an issue — that rule is about not spawning a local agent
instead of delegating a separate issue, and it is never about your own run's auditor, review lenses
or refuters. Those are the only readers in the run that did not write the diff.
If any of them genuinely could not run, the run is not complete: say so in the PR body and in the
Linear comment, in those words — "review self-performed, not independent" — so nobody reads an
unreviewed diff as a reviewed one. Do not quietly substitute your own judgement for the lenses and
report it as a clean review.
- Call the single workflow:
Workflow({ scriptPath: '.claude/workflows/task-orchestration.js', args: {
task: '<the user request verbatim — or, for a Linear reference, the resolved issue title + description>',
cwd: '<repo.path from the cycler config — REQUIRED, the workflow throws without it>',
pluginRoot: '<the ${CLAUDE_PLUGIN_ROOT} you echoed above — REQUIRED, the workflow throws without it>',
config: <the parsed --json output above; omit only when there is no config file>,
executorModel: '<lower Claude model id like "sonnet"/"haiku", or omit to inherit>',
noCommit: <true if the user wants to review before commit; omit for full automation>,
stopAtContract: <true when plan mode is active; omit otherwise>,
prBase: '<repo.base from the cycler config, default "main"; pass the previous task's branch when stacking tasks>',
branchPrefix: '<repo.branch_prefix from the cycler config, default "claude/">',
issueId: '<the tracker issue key when the task is driven from one, e.g. "APL-10" — sets the branch name>',
branch: '<explicit branch override; omit unless you need to force a specific name>',
models: <per-stage overrides, e.g. { verify: 'haiku' }; omit to use the defaults below>,
worktree: <true to run in a dedicated git worktree — REQUIRED when launching runs in parallel>
}})
- If a contract already exists and the user wants to use it, pass
contractPath instead of task.
- When the user invokes
/workflow-feature <ISSUE-KEY> (e.g. /workflow-feature APL-10), pass that key as issueId. The
workflow also parses an uppercase ABC-123 key out of the task text, so this is belt-and-braces —
but pass it explicitly whenever you know it. It determines the branch name (<branchPrefix><ISSUE_ID>).
- Perform the Linear writes the workflow planned. The result carries
linearWrites[] — the
workflow no longer performs these itself (it used to spend 3-4 subagents per run on writes that
failed against an unauthenticated MCP; see HARNESS.md -> Linear round-trip). You hold a working
Linear connector, so you do them:
- Walk the array in order. Each entry has
kind, issue, marker, stateType,
statePreference, assignSelf, links[], body.
- Use
${CLAUDE_PLUGIN_ROOT}/poller/lin, not the Linear MCP (see step 2 for why): lin issue comment list <KEY> to
check, lin issue comment add <KEY> --body '...' to write, lin issue update <KEY> --state '<name-or-type>' to move state.
- Idempotency: list the comments first and skip a write whose
marker is already present with
identical text. body always leads with marker. A resumed or re-run workflow must not spam.
- States by TYPE:
lin issue update takes a state by name or type, so pass statePreference
when set and fall back to stateType (started/unstarted/completed). Never hardcode a name
that only exists in one team.
- Never move the issue to Done — the harness does not merge, so only the human who merges can
honestly close it. Never reassign an issue that already has an assignee.
- Never fail the task over Linear. If a write errors, report it and move on; the task's own
outcome is unaffected. Entries with
skipped: true need no action — the note says why.
- Tell the user which writes you performed, and which failed.
- Read the returned structured result:
{ status, stage, branch, branchCreated, worktree, lockHeld, cleanupNote, contractPath, changedFiles[], summary, commandJournal[], audit, report, confirmed[], notes, fixLog[], commit, commits[], pr, linearWrites[] }.
worktree is null once removed, or a path still on disk. lockHeld: true means the shared-tree
lock could NOT be released — remove it by hand (path in cleanupNote) or the next shared-tree run
refuses to start.
Note: the workflow self-corrects — audit/verify/review failures loop back to the implementer with the
exact issues, up to args.fixMax (default 2). A blocked result means the loop gave up at the failing
stage (fixLog + lastFailure), or the implementer/contract stage failed. On done, pr.prUrl is the
opened pull request (never merged by the harness).
Plan mode: contract-as-plan
Detect plan mode from your own context: a "Plan mode is active" reminder is present and the ExitPlanMode
tool is available. (No env var exists — detection is reading your context; a deterministic alternative via
a hook's permission_mode is documented in HARNESS.md.) When active, pass stopAtContract: true.
The workflow then returns { status: 'plan', stage: 'contract', contractPath, openQuestions } instead of
implementing. Present the contract as the plan:
- Read the
contractPath file; append any openQuestions.
- Write it to the plan file path from your plan-mode reminder — that file is the ONLY file you may write
in plan mode.
- Call
ExitPlanMode — the user reviews the contract as the plan.
- Approved → re-invoke the SAME workflow with
contractPath: <path> and WITHOUT stopAtContract; the
implement → audit → verify → review → commit stages run normally.
- Rejected → do not re-invoke. The user edits the contract file (or re-runs
/workflow-feature); they may then pass
contractPath to continue.
If you set stopAtContract but ExitPlanMode is unavailable (not actually in plan mode), present the
contract in a normal message and ask for approval before re-invoking.
Output
- Relay to the user: stage reached, status (
done / blocked), the gate report, the review verdict
(when a review ran), any fix rounds (fixLog), the commit hash(es), and the opened PR url if one was
created.
Stop conditions
status === 'plan' → present the contract as a plan and re-invoke with contractPath on approval
(see Plan mode section). Do NOT start implementing without that approval.
status === 'blocked' → relay the blockers verbatim (with the stage: contract / implement / audit /
verify / review). Do NOT auto-retry in a loop. The user fixes or re-runs.
status === 'done' → show the summary + commit hash + PR url (if opened). Then save memory: only
decision / constraint / failure records — never chat history.
Notes
- Models are routed per stage, not one model for the whole run.
contract runs on opus (one agent,
but every later stage reads it, and its Non-goals are what let the auditor catch scope creep); the
mechanical stages branch/commit/pr run on haiku (fixed command sequences whose success the
workflow re-checks itself); review:test-gaps and followups run on haiku. Everything else inherits
executorModel. verify, audit and refute are deliberately NOT downgraded — verify plans the
gate before running it, audit is what catches leaked secrets, and a refuter defaults to isReal:false
when unsure, so a weak one silently drops real findings. Override any stage with args.models
({ verify: 'haiku' }), or pass null for a stage to force it back to executorModel.
- The contract author answers its own questions (APL-47).
openQuestions blocks the run and waits
for a human, so it is reserved for genuine PREFERENCE decisions — a product stance, a trade-off only
the user can price. Anything OBSERVABLE (how the code is structured, what copy the feature already
uses, what the current screen looks like) the author resolves itself: by reading, or for macOS UI
questions by building and running the app and taking a screenshot. Resolved-by-looking decisions are
recorded in the contract's Risks & assumptions so a reviewer can challenge the observation. This is
what keeps stopOnOpenQuestions: true (the default) affordable — before it, a well-specified UI issue
still cost two round-trips.
- Parallel runs need
worktree: true (APL-45). Without it a run works in the shared checkout and
takes an exclusive lock; a second concurrent run is refused outright, naming the branch that holds the
lock — loud, not interleaved. With it, the run gets its own worktree under .claude/worktrees/ and
every stage is pointed there, so several /workflow-feature runs on different branches are safe at once. Two runs
on the SAME branch are still impossible: git refuses to check one branch out in two worktrees, and the
harness will not --force past that. A clean run removes its worktree; a blocked run keeps it and
reports the path in result.worktree — inspect it, then
git worktree remove --force <path>. Two things worktrees do NOT fix: the token budget is shared
across concurrent workflows (pass an explicit budget when batching, or each run's guard sees a pool the
others are also spending), and each run still costs up to ~70 agents.
- A Branch stage runs before the implementer: it creates or reuses
claude/<ISSUE_ID> off an
up-to-date prBase, and refuses to run if that branch would equal prBase. The harness therefore never
commits onto the base branch. See ${CLAUDE_PLUGIN_ROOT}/harness/PIPELINE.md for the naming convention (and why it
differs from Linear's suggested feature/apl-N).
- A
blocked result carrying fatal: true means a gate stage did not run (an agent returned no
result — usually a terminal API error), not that the diff failed. Never re-read it as a pass; re-run.
- The workflow commits the gated diff, pushes the branch, and opens a PR to
prBase (default main). It
NEVER merges — merging is the user's call. Review-fix rounds add commits to the same PR.
- The workflow cannot take user input mid-run by design (single-shot). To keep sign-off control, either
pass
noCommit: true (review the diff, commit/push/PR later manually), or author a contract first and
pass contractPath.
- Full automation is the default: it commits, opens the PR, and pushes review fixes to it.
1---2name: workflow-feature3description: Workflow Feature4---56# /workflow-feature — full task lifecycle in a single workflow78## Inputs910- The user's request (the current message) — or an existing contract path.11- The request may be **a Linear issue URL or bare key instead of a description** (see below).12- READ `${CLAUDE_PLUGIN_ROOT}/harness/HARNESS.md` first.1314## Actions (in order)15161. Run `git status --short` (respect in-flight changes — do not touch them).172. **If the argument is a Linear reference** — a `https://linear.app/<workspace>/issue/APL-1/...` URL or a18 bare key like `APL-12` — resolve it before invoking the workflow:19 - Read it with `"${CLAUDE_PLUGIN_ROOT}/poller/lin" issue view <KEY>` — one Bash call, no tool schema to load. Prefer this20 over the Linear MCP: `ToolSearch` + `get_issue` costs a schema load and a tool round-trip, and the21 MCP server is not always connected (in dispatched sessions the Linear MCP never finished connecting, so the22 follow-up-filing step there was unsatisfiable by construction).23 - `lin` is `linear-cli` reading the OAuth token the Linear poller keeps refreshed. Do not use a24 pinned `LINEAR_API_KEY` or `.linear.toml`: Linear access tokens expire every 24h, so a copied one25 works for a day and then fails with a 401 that reads like a network fault.26 - Pass the issue's **title + full description** as `task` (e.g.27 `task: 'APL-1 — <title>\n\n<description>'`). The description is the spec: the issues in this28 workspace are written with Goal / Evidence / Acceptance sections, which map almost directly onto the29 contract template. Do not paraphrase or summarise the acceptance criteria — pass them through.30 - Pass the key as `issueId`. It drives the branch (`claude/APL-1`), the contract filename31 (`apl-1-<slug>.md`), the commit subject, and the PR body's `Closes APL-1.`32 - If `lin` fails (no token, revoked app), pass the reference through as-is: the workflow's CONTRACT AUTHOR33 resolves a reference-only request itself as a fallback. Say which path you took.34 - A **non-Linear argument is unaffected** — pass the request verbatim exactly as before.353. **Post a start comment before invoking the workflow** (Linear reference only):3637```bash38"${CLAUDE_PLUGIN_ROOT}/poller/lin" issue comment list <KEY> | grep -q 'harness:<KEY>:dispatched' \39 || "${CLAUDE_PLUGIN_ROOT}/poller/lin" issue comment add <KEY> --body '<!-- harness:<KEY>:dispatched -->40🔧 Harness run started — contract → implement → audit → gate → PR → review. Next comment lands when the PR opens.'41```4243 Every other Linear write in this skill happens in step 5, *after* the workflow returns — which is 20-4044 minutes later. Without this one the board shows nothing at all for the whole run, and a delegated issue45 sitting silent is indistinguishable from a dispatch that never fired. That ambiguity is what the poller's46 own failure comment exists to remove; the run itself needs the same. The marker makes it idempotent, and47 a failure here is never a reason not to start the workflow.48494. **Read the cycler config first**, so the run uses this repo's settings rather than defaults:5051```bash52node "${CLAUDE_PLUGIN_ROOT}/harness/read-config.mjs" repo.base main53node "${CLAUDE_PLUGIN_ROOT}/harness/read-config.mjs" repo.branch_prefix claude/54node "${CLAUDE_PLUGIN_ROOT}/harness/read-config.mjs" repo.path ""55node "${CLAUDE_PLUGIN_ROOT}/harness/read-config.mjs" --json56echo "${CLAUDE_PLUGIN_ROOT}"57```5859 Pass those as `prBase`, `branchPrefix`, `cwd`, `config` and `pluginRoot` below. A repo with no60 config gets the defaults, which are the values shown in those commands — nothing breaks,61 nothing is silently shaped like somebody else's repo.6263 **`cwd` and `pluginRoot` are not optional.** The Workflow runtime exposes `args`, `agent`,64 `parallel`, `pipeline`, `log`, `phase` and `budget` — there is no `process`, so the workflow has65 nothing to fall back on and throws immediately if either is missing. It used to fall back to66 `process.cwd()`, which is a `ReferenceError` in that runtime: the script died on its first line67 and every unattended dispatch left no branch and no PR.6869**The workflow's audit and review stages are subagents, and you must let them run.** A repo may carry a70rule against spawning subagents to work an issue — that rule is about not spawning a local agent71*instead of delegating a separate issue*, and it is never about your own run's auditor, review lenses72or refuters. Those are the only readers in the run that did not write the diff.7374If any of them genuinely could not run, the run is **not** complete: say so in the PR body and in the75Linear comment, in those words — "review self-performed, not independent" — so nobody reads an76unreviewed diff as a reviewed one. Do not quietly substitute your own judgement for the lenses and77report it as a clean review.78795. Call the single workflow:8081```js82Workflow({ scriptPath: '.claude/workflows/task-orchestration.js', args: {83 task: '<the user request verbatim — or, for a Linear reference, the resolved issue title + description>',84 cwd: '<repo.path from the cycler config — REQUIRED, the workflow throws without it>',85 pluginRoot: '<the ${CLAUDE_PLUGIN_ROOT} you echoed above — REQUIRED, the workflow throws without it>',86 config: <the parsed --json output above; omit only when there is no config file>,87 executorModel: '<lower Claude model id like "sonnet"/"haiku", or omit to inherit>',88 noCommit: <true if the user wants to review before commit; omit for full automation>,89 stopAtContract: <true when plan mode is active; omit otherwise>,90 prBase: '<repo.base from the cycler config, default "main"; pass the previous task's branch when stacking tasks>',91 branchPrefix: '<repo.branch_prefix from the cycler config, default "claude/">',92 issueId: '<the tracker issue key when the task is driven from one, e.g. "APL-10" — sets the branch name>',93 branch: '<explicit branch override; omit unless you need to force a specific name>',94 models: <per-stage overrides, e.g. { verify: 'haiku' }; omit to use the defaults below>,95 worktree: <true to run in a dedicated git worktree — REQUIRED when launching runs in parallel>96}})97```9899 - If a contract already exists and the user wants to use it, pass `contractPath` instead of `task`.100 - When the user invokes `/workflow-feature <ISSUE-KEY>` (e.g. `/workflow-feature APL-10`), pass that key as `issueId`. The101 workflow also parses an uppercase `ABC-123` key out of the task text, so this is belt-and-braces —102 but pass it explicitly whenever you know it. It determines the branch name (`<branchPrefix><ISSUE_ID>`).1036. **Perform the Linear writes the workflow planned.** The result carries `linearWrites[]` — the104 workflow no longer performs these itself (it used to spend 3-4 subagents per run on writes that105 failed against an unauthenticated MCP; see HARNESS.md -> Linear round-trip). You hold a working106 Linear connector, so you do them:107 - Walk the array in order. Each entry has `kind`, `issue`, `marker`, `stateType`,108 `statePreference`, `assignSelf`, `links[]`, `body`.109 - **Use `${CLAUDE_PLUGIN_ROOT}/poller/lin`, not the Linear MCP** (see step 2 for why): `lin issue comment list <KEY>` to110 check, `lin issue comment add <KEY> --body '...'` to write, `lin issue update <KEY> --state111 '<name-or-type>'` to move state.112 - **Idempotency:** list the comments first and skip a write whose `marker` is already present with113 identical text. `body` always leads with `marker`. A resumed or re-run workflow must not spam.114 - **States by TYPE:** `lin issue update` takes a state by name *or type*, so pass `statePreference`115 when set and fall back to `stateType` (`started`/`unstarted`/`completed`). Never hardcode a name116 that only exists in one team.117 - **Never move the issue to Done** — the harness does not merge, so only the human who merges can118 honestly close it. Never reassign an issue that already has an assignee.119 - **Never fail the task over Linear.** If a write errors, report it and move on; the task's own120 outcome is unaffected. Entries with `skipped: true` need no action — the `note` says why.121 - Tell the user which writes you performed, and which failed.1227. Read the returned structured result:123 `{ status, stage, branch, branchCreated, worktree, lockHeld, cleanupNote, contractPath, changedFiles[], summary, commandJournal[], audit, report, confirmed[], notes, fixLog[], commit, commits[], pr, linearWrites[] }`.124 `worktree` is `null` once removed, or a path still on disk. `lockHeld: true` means the shared-tree125 lock could NOT be released — remove it by hand (path in `cleanupNote`) or the next shared-tree run126 refuses to start.127 Note: the workflow self-corrects — audit/verify/review failures loop back to the implementer with the128 exact issues, up to `args.fixMax` (default 2). A `blocked` result means the loop gave up at the failing129 stage (`fixLog` + `lastFailure`), or the implementer/contract stage failed. On `done`, `pr.prUrl` is the130 opened pull request (never merged by the harness).131132## Plan mode: contract-as-plan133134Detect plan mode from your own context: a "Plan mode is active" reminder is present and the `ExitPlanMode`135tool is available. (No env var exists — detection is reading your context; a deterministic alternative via136a hook's `permission_mode` is documented in HARNESS.md.) When active, pass `stopAtContract: true`.137138The workflow then returns `{ status: 'plan', stage: 'contract', contractPath, openQuestions }` instead of139implementing. Present the contract as the plan:1401411. Read the `contractPath` file; append any `openQuestions`.1422. Write it to the plan file path from your plan-mode reminder — that file is the ONLY file you may write143 in plan mode.1443. Call `ExitPlanMode` — the user reviews the contract as the plan.1454. Approved → re-invoke the SAME workflow with `contractPath: <path>` and WITHOUT `stopAtContract`; the146 implement → audit → verify → review → commit stages run normally.1475. Rejected → do not re-invoke. The user edits the contract file (or re-runs `/workflow-feature`); they may then pass148 `contractPath` to continue.149150If you set `stopAtContract` but `ExitPlanMode` is unavailable (not actually in plan mode), present the151contract in a normal message and ask for approval before re-invoking.152153## Output154155- Relay to the user: stage reached, status (`done` / `blocked`), the gate report, the review verdict156 (when a review ran), any fix rounds (`fixLog`), the commit hash(es), and the opened PR url if one was157 created.158159## Stop conditions160161- `status === 'plan'` → present the contract as a plan and re-invoke with `contractPath` on approval162 (see Plan mode section). Do NOT start implementing without that approval.163- `status === 'blocked'` → relay the blockers verbatim (with the stage: contract / implement / audit /164 verify / review). Do NOT auto-retry in a loop. The user fixes or re-runs.165- `status === 'done'` → show the summary + commit hash + PR url (if opened). Then save memory: only166 `decision` / `constraint` / `failure` records — never chat history.167168## Notes169170- **Models are routed per stage**, not one model for the whole run. `contract` runs on `opus` (one agent,171 but every later stage reads it, and its Non-goals are what let the auditor catch scope creep); the172 mechanical stages `branch`/`commit`/`pr` run on `haiku` (fixed command sequences whose success the173 workflow re-checks itself); `review:test-gaps` and `followups` run on `haiku`. Everything else inherits174 `executorModel`. `verify`, `audit` and `refute` are deliberately NOT downgraded — verify *plans* the175 gate before running it, audit is what catches leaked secrets, and a refuter defaults to `isReal:false`176 when unsure, so a weak one silently drops real findings. Override any stage with `args.models`177 (`{ verify: 'haiku' }`), or pass `null` for a stage to force it back to `executorModel`.178- **The contract author answers its own questions** (APL-47). `openQuestions` blocks the run and waits179 for a human, so it is reserved for genuine PREFERENCE decisions — a product stance, a trade-off only180 the user can price. Anything OBSERVABLE (how the code is structured, what copy the feature already181 uses, what the current screen looks like) the author resolves itself: by reading, or for macOS UI182 questions by building and running the app and taking a screenshot. Resolved-by-looking decisions are183 recorded in the contract's Risks & assumptions so a reviewer can challenge the observation. This is184 what keeps `stopOnOpenQuestions: true` (the default) affordable — before it, a well-specified UI issue185 still cost two round-trips.186- **Parallel runs need `worktree: true`** (APL-45). Without it a run works in the shared checkout and187 takes an exclusive lock; a second concurrent run is refused outright, naming the branch that holds the188 lock — loud, not interleaved. With it, the run gets its own worktree under `.claude/worktrees/` and189 every stage is pointed there, so several `/workflow-feature` runs on different branches are safe at once. Two runs190 on the SAME branch are still impossible: git refuses to check one branch out in two worktrees, and the191 harness will not `--force` past that. A clean run removes its worktree; a **blocked run keeps it** and192 reports the path in `result.worktree` — inspect it, then193 `git worktree remove --force <path>`. Two things worktrees do NOT fix: the token budget is shared194 across concurrent workflows (pass an explicit budget when batching, or each run's guard sees a pool the195 others are also spending), and each run still costs up to ~70 agents.196- A **Branch stage** runs before the implementer: it creates or reuses `claude/<ISSUE_ID>` off an197 up-to-date `prBase`, and refuses to run if that branch would equal `prBase`. The harness therefore never198 commits onto the base branch. See `${CLAUDE_PLUGIN_ROOT}/harness/PIPELINE.md` for the naming convention (and why it199 differs from Linear's suggested `feature/apl-N`).200- A `blocked` result carrying `fatal: true` means a gate stage **did not run** (an agent returned no201 result — usually a terminal API error), not that the diff failed. Never re-read it as a pass; re-run.202- The workflow commits the gated diff, pushes the branch, and opens a PR to `prBase` (default `main`). It203 NEVER merges — merging is the user's call. Review-fix rounds add commits to the same PR.204- The workflow cannot take user input mid-run by design (single-shot). To keep sign-off control, either205 pass `noCommit: true` (review the diff, commit/push/PR later manually), or author a contract first and206 pass `contractPath`.207- Full automation is the default: it commits, opens the PR, and pushes review fixes to it.