| name | pipeline |
| description | Run one task through the plan→build→review pipeline — a Step-0.5 classify-task call routes the planner/implementer/reviewer models to the task's complexity tier, then the plan is written (planner subagent or inline), the implementer builds it in an isolated worktree, the my-review agent reviews the diff, and findings route by severity (low→issues, medium→triaged fix-list, high→collective replan, critical→own cycle). For single tasks not worth slicing into an issue graph. Use for "/pipeline <issue#|task>", "pipeline this". |
| argument-hint | [issue# | task text] [--max-cycles K=2] [--complexity trivial|standard|complex] [--self-plan] |
| effort | high |
| allowed-tools | Read, Grep, Glob, Bash, Write, Agent, Skill, AskUserQuestion |
Run one task through the standardized pipeline with models routed by complexity tier
(classified in Step 0.5), and a severity-routed fix loop.
$ARGUMENTS = [issue# | task text] [--max-cycles K] [--complexity trivial|standard|complex] [--self-plan] — K = max review cycles (default 2); --self-plan makes the main
thread author the Step-2 plan itself (no planner spawn). You run on the main thread because
only the main thread can spawn subagents.
This is the single-task sibling of /orchestrate — for work not worth slicing into an issue
graph. The result is a branch left for the user: never push, never merge, never close
the issue.
Resume: if the session's resume order points at a *-pipeline.md state doc, this is a
resumed run — re-enter the recorded worktree (EnterWorktree(path: …)), read the state doc in
full, and continue from the recorded phase with the recorded cycle count and open findings.
Do not redo completed phases. The state doc records the confirmed roster (tier + the three
{model, effort} pairs) — reuse it; never re-classify on resume. It also records plan_author and the
full plan text; a resume never re-authors the plan and never re-spawns a Step-2 planner —
the embedded plan is authoritative (Step-5 planner spawns still happen normally).
Step 0 — preflight
- Parse
$ARGUMENTS. A leading integer (12, #12) → issue mode. Otherwise the text
is the task: grill mode if a /grill-me alignment exists in this session, else
bare mode. Extract --max-cycles K (default 2) and --complexity <tier> (optional —
consumed in Step 0.5). Extract --self-plan (consumed in Step 2) — a natural-language
request for the main agent to plan it itself (e.g. "plan it yourself", "self-plan") counts as
the flag.
- Hard-dep check. The chain needs the
personal-tools plugin: the my-review agent and
the verify-plan skill. If either is missing (not in your available agents/skills), fail
loud naming the missing piece — e.g. "personal-tools plugin not installed: my-review agent
unavailable" — and stop. Do not substitute another reviewer.
- Issue mode only:
gh issue view <N> --json title,body,labels,state. Refuse (report
and stop, mirroring orchestrate's ready rule) if:
- the issue is closed, or labeled
hitl (needs a human);
- any
## Blocked by ref (bare #N lines; None - can start immediately passes) is still
open (gh issue view <ref> --json state). An issue is ready iff every blocker is
closed.
A prd-labeled issue is accepted — pipeline runs the whole PRD as one (large but valid)
pipeline task; slicing it with /to-issues first is the alternative, not a requirement.
Issue mode is autonomous — scope was pre-approved when the issue was filed — with
one interactive stop before the fix loop: the Step-0.5 tier confirm, before any pipeline
subagent (planner/implementer/reviewer) spawns (skipped when --complexity is passed). Exactly two writes go to the target issue: the plan comment
(step 2) and the result comment (step 8). (Step 7's label creates and follow-up issues —
lows and declared mock-debt — happen in either mode and are the only other outward writes.)
- Grill/bare mode: distill the brief yourself on the main thread — the task text plus
(grill mode) the constraints, edge cases, and acceptance criteria surfaced by the grill.
The planner gets the distilled brief, not the raw conversation.
Step 0.5 — classify (pick the roster)
The models below are tier-routed, not fixed (effort is not — see the end of this step).
Obtain the tier, then resolve its roster from the plugin's config — the table is not
duplicated here:
--complexity <tier> given → skip classification; that tier is the confirmed tier (no
rationale — record rationale=(--complexity <tier>)).
- Otherwise → invoke the
classify-task skill (Skill tool) with the issue body (issue
mode) or the distilled brief (grill/bare). It explores the touched code, classifies, and runs
its own confirm/override AskUserQuestion before any pipeline subagent
(planner/implementer/reviewer) spawns — in issue mode this stays the only interactive stop
before the fix loop (Step 2's authorship ask below is unreachable in issue mode; Step 6's
cap-hit ask is the exception, on the far side of the fix loop); in grill/bare it precedes
every spawn. Parse its two-line output contract (tier= / rationale=) for the tier, and keep
the rationale for Step 2 surfacing.
Then resolve the roster once: run
bash "${CLAUDE_PLUGIN_ROOT}/scripts/resolve-tier.sh" <tier> and parse its seven key=value lines
(tier=, planner_model= / planner_effort=, implementer_model= / implementer_effort=,
reviewer_model= / reviewer_effort=) into the confirmed roster — the tier plus the three
{model, effort} pairs — that drives every spawn below. If the helper prints a WARN (missing or
invalid config), surface it to the user and continue on the fallback (standard) roster it returned.
The confirmed roster is fixed for the whole run — the reviewer model is held constant across
every re-review. Substitute its models into the model: placeholders (<planner>,
<implementer>, <reviewer>) in Steps 2–5.
Effort is not a per-spawn lever here. Every spawn below is an Agent tool call, and the
Agent tool has no effort parameter — its parameters are description, isolation, model,
prompt, run_in_background, subagent_type. Each agent's frontmatter effort: pin governs
(planner high, implementer xhigh, my-review xhigh), and passing an effort: on an Agent
call is silently dropped. So the roster's *_effort values are inert for /pipeline —
parse them (the helper's seven-line contract is fixed) but do not try to spawn with them. They are
live for /orchestrate, which spawns through Workflow agent(prompt, opts), and opts.effort
is honored there. Note: even when Step 2's plan is authored inline (main thread, no planner spawn), the
roster's planner pair still drives Step 5's triage/replan/per-critical spawns. The confirmed
roster the state doc records also carries plan_author=inline|subagent, set in Step 2.
Step 1 — enter the worktree
Orchestrate's step-0 pattern verbatim. Decide by where you are now — canonicalize both with
realpath first, since git may print a relative .git:
- In the primary checkout (
git rev-parse --git-dir and --git-common-dir resolve to the
same path) → record base=$(git rev-parse HEAD) before the call, then call
EnterWorktree(name: "issue-<N>") (issue mode) or
EnterWorktree(name: "pipeline-<slug>") (grill/bare; <slug> = short kebab slug of the
task). The worktree's branch point follows the worktree.baseRef setting: head (which the
kit's setup scripts install) branches off the current HEAD, but the built-in default is
fresh = origin/<default-branch>, which silently drops local commits. So verify the base
after entering: if git rev-parse HEAD ≠ $base, run git reset --hard "$base" — the
worktree is brand-new, so the reset is safe.
- Already in a linked worktree (the two differ) → skip; this worktree is already
isolated.
Record baseline=$(git rev-parse HEAD) (= $base after the guard) — the review diffs against
it. Everything below runs from the worktree. At the very end, ExitWorktree(keep) — the
branch and worktree stay for the user.
Step 2 — plan
Authorship ladder — first match wins (records plan_author for the state doc):
--self-plan (flag or the Step-0 natural-language request) → inline, any mode/tier.
plan_author=inline. Depth is your judgment: minimal for a trivial task, fuller when warranted.
tier=trivial (any mode) → auto minimal inline plan — no ask. plan_author=inline.
Keep it short but still carry ordered steps, a ## Acceptance criteria section, and the
project done-check.
- grill mode, standard/complex → AskUserQuestion — inline or subagent? Your pick sets
plan_author (unreachable in issue/bare mode — no new ask ever fires in issue mode).
- bare or issue mode, standard/complex → subagent (today's default).
plan_author=subagent.
Inline (plan_author=inline): you (the main agent) write the plan straight to
<scratchpad>/pipeline-plan.md — no planner spawn for Step 2.
Subagent (plan_author=subagent): spawn workflow:planner (one Agent call,
subagent_type: workflow:planner, model: "<planner>"; effort comes from the agent's frontmatter
pin) with mode=plan and the issue body
(issue mode) or distilled brief (grill/bare); it returns the plan as text and you write it to
<scratchpad>/pipeline-plan.md.
Then, by mode:
- Grill mode, standard/complex — verify-plan: invoke the
verify-plan skill (Skill tool)
to drift-check the plan against this session's decisions (skipped on trivial). If it reports
mismatches, fix the plan (edit the file yourself for wording; respawn the planner only if the
drift is structural and the plan was subagent-authored). If verify-plan errors because its
session stash is missing, relay its remedy verbatim and stop — don't reimplement the check.
- Grill + bare modes — plan gate: the gate fires iff
tier=complex OR the plan was
subagent-authored — an inline trivial/standard plan skips it (you already hold the
context). When it fires, show the plan — alongside the tier and rationale from Step 0.5 —
and iterate — you (the main agent) revise the plan file per their feedback until they
approve (no planner round-trip). Do not proceed unapproved. Issue mode stays autonomous — no
gate.
- Issue mode — no gate: post the plan as an issue comment
(
gh issue comment <N> --body-file <plan>) regardless of author, prefixing the tier and
rationale (this is the first outward write), then proceed.
Step 3 — implement
Spawn workflow:implementer on the confirmed roster's implementer (one Agent call,
subagent_type: workflow:implementer, model: "<implementer>"; effort comes from the agent's
frontmatter pin) handing it a work order: the full
plan text (steps + ## Acceptance criteria), the absolute worktree path, the branch,
and a commit-scope hint from the repo log. It builds TDD-first, runs the project's done-check,
and commits.
If it reports failure or blocked (red done-check, ambiguous plan, unmet blocker): stop
and report honestly — what it tried, what failed, where the branch is. Don't spawn a fixer
blind.
Step 4 — review
Spawn personal-tools:my-review (one Agent call, model: "<reviewer>"; effort comes from the
agent's frontmatter pin) on the branch
diff — the commit range <baseline>..HEAD — with the plan file path in the prompt for
conformance context. It returns
a verdict plus findings ending in a machine-readable ```findings block:
severity=critical|high|medium|low path=<path>:<line> replan=yes|no summary=<one line>
Step 5 — route findings
Parse the ```findings block (empty block → clean; skip to step 7). Route by severity:
| severity | route |
|---|
| low | file as GitHub issues (step 7) — both modes; never fixed in this run |
| medium | spawn the planner in mode=triage (cheap call, mediums only) → ONE ordered fix-list; any replan=yes medium or needs-real-plan flag escalates that item into the high route |
| high | ONE collective replan covering all high findings together (planner mode=replan, mediums appended) — one coherent revision, not per-finding patches |
| critical | each critical finding gets its own full plan→implement→review cycle (planner mode=replan scoped to that finding alone, then steps 3–4 again) |
When one review returns both criticals and highs: run the per-critical cycles first
(ascending by path, so the order is deterministic), then the ONE collective high replan —
mediums append to the collective replan only. At each scoped re-review, drop any finding a
prior cycle already resolved.
Fix rounds go to a fresh implementer spawn (model: "<implementer>"), work order = the fix-list
or revised plan. Then a scoped
re-review: spawn personal-tools:my-review (model: "<reviewer>" — held constant across
every re-review in the run) again asking it
to (a) verify each prior finding is addressed and (b) review only the fix delta
(<pre-fix HEAD>..HEAD) — not the whole branch again.
Cycle budget: --max-cycles (default 2) counts re-reviews — the initial review is
free; each re-review decrements the budget.
Step-5 planner spawns (triage / replan / per-critical) are never inline — they always spawn
workflow:planner on <planner>, even when Step 2's plan was authored inline. Inline authorship
is a Step-2-only lever.
Step 6 — cap hit
If the budget is exhausted and medium-or-worse findings remain open, pause and ask
(AskUserQuestion): continue (grant +1 cycle) / stop and report (branch stays as-is,
open findings listed) / user takes over (report state, exit cleanly). Never loop past the
cap silently. On stop or take over, report the open findings, then delete the step-9
resume state (the .pending.json pointer and the -pipeline.md state doc) — a run the user
ended must not resurrect at the next session start. Only continue keeps the state.
Step 7 — file the lows + declared mock-debt
For each low finding, file a follow-up issue (both modes). Ensure the labels exist
(gh label create review-fix 2>/dev/null || true, same for ready-for-agent), then
gh issue create --title '<one-line fix>' --label ready-for-agent --label review-fix --body-file <tmp> using the reviewer's verbatim template (single-quote the title — it embeds
review-derived text, which may carry shell metacharacters echoed from repo content): ## What to build (the fix),
## Acceptance criteria, ## Blocked by (None - can start immediately unless the fix
depends on this branch landing — then name the issue/branch).
Also file any ## Mock-debt the implementer declared — there is no orchestrate reviewer
on this path, so the pipeline files it or nobody does. Ensure the label
(gh label create mock-debt --description "central mechanism mocked; wire it real" 2>/dev/null || true),
then file with the my-review agent's mock-debt template: ## What to build (wire real <X>, removing
the mock), ## Central mechanism (the now-real interface), ## Acceptance criteria (the
central mechanism runs real and the test exercises it), ## Blocked by (from the declaration,
or None - can start immediately).
Step 8 — finish
Final report: plan summary, commits on the branch (git log <baseline>..HEAD --oneline),
review verdict + cycles used, issues filed, anything unresolved. Name the branch + worktree
path and tell the user the merge is theirs — never push, never merge, never close the
issue. Issue mode: post the result as an issue comment (gh issue comment <N>) — the second
and last outward write.
Then delete the resume state (step 9's pointer + state doc) and ExitWorktree(keep).
Step 9 — resume state (write at every phase boundary)
So /clear + go continues the run, persist state at each phase boundary — planned /
gated / built / cycle-N:
- Key the handoff dir exactly as
save-handoff.sh does (a drift test enforces this —
don't diverge): common_dir="$(git rev-parse --git-common-dir)", canonicalize
common_dir="$(cd "$common_dir" && pwd -P)", then
repo_key="$(printf %s "$common_dir" | sha1sum | cut -c1-16)" and
dir=~/.claude/handoffs/$repo_key (mkdir -p "$dir").
- Write the state doc
$dir/<branch-slug>-pipeline.md (every / in the branch → -):
mode, target (issue# or brief), branch, worktree path, current phase, cycles used, the
confirmed roster (tier + the three {model, effort} pairs — so a resume never re-classifies),
plan_author=inline|subagent (so a resume never re-authors the plan and never
re-spawns a Step-2 planner), the full current plan text embedded (the scratchpad may
not survive a clear), and open findings. Overwrite on each boundary.
- Write the resume pointer
$dir/.pending.json with the Write tool, exactly the
workflow schema (resume.sh consumes it and re-injects the resume order, including
re-entering the worktree):
{
"handoff_path": "<absolute path to the -pipeline.md state doc>",
"branch": "<branch>",
"git_toplevel": "<git rev-parse --show-toplevel>",
"git_common_dir": "<canonical common_dir>",
"baseline_head": "<the step-1 baseline commit>",
"session_id": null,
"context_tokens": null,
"ts": <date +%s>
}
- On clean finish (step 8): delete both —
rm -f "$dir/.pending.json" "$dir/<branch-slug>-pipeline.md". A finished run must not resurrect.