harness-claude-code · workflow guide
A walkthrough of the top-level commands, the role-based agents, and the GitHub-issue lifecycle they drive together — including who talks to whom, where the user sits in the loop, and how every state transition is recoverable because the source of truth lives on issues, labels, and a per-unit task checklist.
New in v0.41 — the
/ship command unifies all three kinds of work into one loop.
It is a superset of /implement-feature: the same feature flow,
plus an enhancement lane (one feature-shaped
kind:enhancement issue, no interview) and a full
bug lane (read-only analyze-bug → human approval
gate → the lighter fix-bug Workflow). Kickoff routes by
kind: — feature/enhancement launch implement-slice.mjs,
bugs launch fix-bug.mjs. Milestone is optional: omit it for the
repo-wide maintenance lane. /implement-feature remains as a
feature-only fallback. See what changed.
The harness is built from top-level commands and a set of
role-based agents. Commands are orchestrators: they don't write code
themselves; they bring agents onto a team, brief them, route messages, and —
in execution — launch a background unit-cycle Workflow per unit of
work against GitHub-issue state, backed by a pure-shell discovery
script that decides what's eligible each pass. The unified execution command
is /ship, driven by ship-finder.sh
(five stages: reconcile · analyze-bug · kickoff · fix-pr · close-pr). It spans
all three kinds of work and routes kickoff by kind: —
kind:feature / kind:enhancement launch
implement-slice.mjs, kind:bug launches
fix-bug.mjs. (/implement-feature +
task-finder.sh remain as a feature-only fallback with four stages.)
Durable state lives in three places: the GitHub issue and its labels, the
issue body's task checklist (or, for a bug, its approved analysis
comment), and the unit branch's commits — which means the loop can be stopped,
resumed, or re-run without losing track of where work is.
┌──────────────────────────────────────────────────────────┐
│ USER (you) │
└──┬────────────────────┬──────────────────────────────┬──┘
│ /deep-dive-feature │ /scaffold-project │ /ship [milestone]
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌──────────────┐
│ product- │ │ scaffold- │ │ orchestrator │
│ owner → │ │ project │ │ (ship-finder │
│ design- │ │ (templates │ │ .sh · 5 │
│ lead → │ │ + seeds │ │ stages) │
│ architect │ │ locked │ └──────┬───────┘
│ + writers │ │ tokens) │ kickoff routes by kind:
└─────┬──────┘ └─────┬──────┘ ▼
│ │ ┌───────────────────────────────────┐
▼ ▼ │ feature / enhancement → implement- │
PRD + design system + ADRs bootable stack │ slice.mjs (author E2E → cov gate │
+ surfaces + contracts + tokens │ → implement → pass E2E → review) │
(committed on feature (compose up; │ bug → fix-bug.mjs (regression test │
branch; PR opened) PR opened) │ first → fix → review) │
└─────────────────┬───────────────────┘
▼
draft PR → fix-pr / close-pr
(the outer loop's other stages)
(bug lane adds an up-front analyze-bug stage: read-only reproduce + root-cause
→ # Bug Analysis comment → human approves → kickoff launches fix-bug.mjs)
Everything in discovery (/deep-dive-feature,
/scaffold-project) is unchanged. The whole shift is in
execution. Through 0.39, /implement-feature was a
nine-stage state machine: each step of a slice's life — implement a task,
review it, fix it, validate E2E, review the slice, fix the slice — was its own
label-driven stage that dispatched a one-shot agent and then ended the pass,
handing control back to GitHub labels until the next pass re-discovered the
work. In 0.40 that entire inner cycle collapses into one background
implement-slice Workflow per slice, and the outer command
keeps only the four stages that genuinely need to live outside a single run.
level:* / type:* / review:* / e2e:* labelstask-finder.sh ran nine per-stage scripts; the orchestrator round-tripped each task and slice through GitHub one stage per pass/tmp handoff files)review-slice (added in 0.39.26) flipped the review:* label and opened the PR itselftask-finder.sh runs four stages: reconcile (0), kickoff-launch (1), fix-pr (8), close-pr (9)implement-slice.mjs; that one run owns author E2E → coverage gate → plan → implement → pass E2E → gate review → fix → quality review → fix → open draft PR[ ]/[x] checklist; commit trailers carry Task: <static-id> (not Refs #<task#>)runReviewSlice() fan-out posts its comment and returns the verdict — it flips no label and opens no PR; the surrounding implement-slice phases own those| Dimension | 0.39 | 0.40 |
|---|---|---|
| outer loop | 9 stages, all owned by /implement-feature |
4 stages — reconcile / kickoff-launch / fix-pr / close-pr. The inner cycle is no longer the command's concern. |
| inner slice cycle | spread across stages 2–7, one dispatch + label flip per pass per step | one background implement-slice Workflow that runs the whole cycle serially in a single run |
| issues created | slice issue plus a typed task sub-issue per task (e2e/backend/frontend) | slice issue only; the task breakdown is an inline static-ID checklist in the slice body |
| task identity | GitHub issue number; commits trail Refs #<task#> |
permanent static ID (s42.be.1); commits trail Task: <id> — never translated to an issue number |
| labels | level:*, type:*, review:*, e2e:* + status/merge |
those four families deleted; GitHub keeps only the slice issue, the status:in-progress lock, the status:need-attention halt, and the PR / merge:* |
| E2E coverage | specs authored, then validated against a stack (no pre-implementation gate) | new coverage gate — runReviewSlice('test-coverage') reviews the authored specs before any production code is written |
| slice review contract | flips review:running → review:passed/need-fix and opens the PR |
posts the comment and returns the verdict; the post-implementation review is split into a gate review (reviewMode:'gate', spec/contract/security, blocks) and a quality review (reviewMode:'quality', code-quality axes, advisory); plus the pre-implementation scope:'test-coverage' gate; inlined as runReviewSlice(); the surrounding phases own the lock + PR |
| crash recovery | engineer handoff docs (budget-gate + precompact hooks) | WIP commits + durable checklist + Workflow resume journal; fix loops are uncapped (loop to confidence-to-pass), kept convergent by anchored re-review rounds (closure-check the prior findings, hunt new ones only in changed code) + aggressive-recall first rounds + opt-in adversarial verify. Handoff hooks/skill deleted. |
| reviewer agent | the primary task reviewer, dispatched per task | a single-agent fallback only, used when Workflow is unavailable |
What did not change: labels are still the cross-pass
protocol for the durable state that remains; every state transition is still
recoverable from GitHub + git; the orchestrator still never writes code or
diagnoses failures (detect-and-dispatch); and /loop /implement-feature
<feature-name> is still the way to ship a feature unattended.
There are two distinct phases, and they don't share state in memory — they share state through git and GitHub. Discovery produces documents; execution consumes those documents and produces code.
Run once per feature, before any code lands. The user converses with
product-owner until the requirement is locked, then with
design-lead until the visual language + surface/navigation
inventory are locked, then with architect until the
technical decisions are locked. Each interviewer is
read-only; writer teammates (doc-writer
instances) commit the artifacts. The phase ends with a single PR
titled feature-lockin.
/deep-dive-feature — PRD + critical path + glossary + design system + surface/nav inventory + per-surface UI interaction contracts + ADRs + implement-detail + per-entity api-contract / data-model files + runbooks/scaffold-project — greenfield only; reads the ADRs and brings up a bootable stack, seeding the locked design tokens
Run repeatedly per feature, idempotently, against GitHub-issue state.
The orchestrator runs task-finder.sh once per pass — pure
shell, no LLM — to find candidates across four outer
stages, then processes the report. Stage 1 launches one
background implement-slice Workflow per eligible slice;
that run owns the whole inner cycle. The other three stages reconcile
dead runs and handle the PR. Wrap with /loop for unattended
end-to-end shipping.
/ship [milestone] drives reconcile → analyze-bug → kickoff → fix-pr → close-pr (/implement-feature is the feature-only four-stage subset)implement-slice.mjs (feature/enhancement) or fix-bug.mjs (bug), which dispatch e2e-author / engineer and run the inlined review fan-out (axis-reviewer agents)
Role-based subagents under agents/. Each one is briefed by a
command, a workflow, or a workflow skill — never by the user directly. Roles
are sharp on purpose: product-owner never writes architecture;
design-lead never writes code; engineer never
writes E2E specs; reviewer is read-only on production code. In
execution the agents are no longer dispatched by the /ship
orchestrator directly — they are dispatched by the unit-cycle
Workflow (implement-slice.mjs / fix-bug.mjs).
The two exceptions the outer loop still owns are the read-only
analyze-bug engineer (pre-approval) and the fix-pr
engineer (an external-wait stage).
| Agent | Model | Mode | Owns |
|---|---|---|---|
| product-owner | opus | read | Interviews the user about the six product axes (user, problem, success criteria, scope-in, non-goals, edge cases). Composes a dispatch prompt for the requirement-writer at the end; never writes files. |
| design-lead | opus | read | Interviews the user about the visual language and information architecture. Locks the design system + the surface / navigation inventory (every routed surface and how it's reached). Composes a dispatch prompt for the design-writer; ui-ux-pro-max is its toolbox. Answers the designer teammates' requests for the locked interview results and folds the human-voted winner into its payload. Reads PRD; never writes files. |
| designer | sonnet | write | Sample-page generator, 1–2 named instances after the design interview: designer-pro-max (toolbox ui-ux-pro-max) and designer-taste (toolbox taste-skill) — one per installed toolbox plugin. Each pulls the interview results from design-lead and writes self-contained plain-HTML candidates under docs/design-system/sample-candidates/<name>/; the human votes the winner (solo mode skips the vote and adds a token proposal; with neither plugin the phase is skipped — design-lead's own taste, the pre-existing fallback). Writes uncommitted candidates only; design-writer moves the winner into docs/design-system/samples/ and commits. |
| architect | opus | read | Interviews the user about technical decisions. Reads the locked surface inventory and models the app shell / nav container as a real C4 component. Composes five scoped dispatch prompts (implement-detail, ADR, api-contract, data-model, runbooks). Reads PRD; never writes files. |
| doc-writer | sonnet | write | Seven named instances: requirement-writer (Phase 1), design-writer (Phase 1.5), then implement-detail-writer, adr-writer, api-contract-writer, data-model-writer, runbook-writer (Phase 2). Each writer pulls its scoped payload from the matching interviewer via SendMessage, then commits its artifacts. |
| engineer | sonnet | write | Fullstack implementer. Dispatched by the implement-slice Workflow with a (slice #, task IDs) pair, routed by verb: implement (named backend/frontend checklist tasks), pass-E2E (drive production code to green against a booted stack), fix-slice (review findings), fix-pr (CI / merge conflict). Reads the slice body's ## Tasks checklist as the ledger, resumes from ticked boxes + Task: <id> WIP commits. Strict outside-in TDD. Never writes E2E specs. |
| e2e-author | sonnet | write | Authors and fixes Playwright E2E specs for a slice's e2e checklist tasks, dispatched by the implement-slice Workflow with a (slice #, task IDs) pair. Sets up its own slice worktree, smoke-runs each touched spec, commits with Task: <id> trailers and pushes, ticks the authored boxes, posts a summary comment. |
| axis-reviewer | sonnet | read | Single-axis reviewer — applies exactly ONE pattern-reviewer-* catalogue to the slice diff and returns structured findings (no verdict, no comment, no label). The implement-slice fan-out (runReviewSlice()) spawns one per applicable pattern; the workflow owns dedup, adversarial verify, scoring, the verdict, and posting. Runs in full or coverage scope. |
| reviewer | sonnet | read | Single-context fallback reviewer for one slice — used only when the implement-slice fan-out review is unavailable in the running harness. Collapses the fan-out into one context: applies the same per-axis rules (axis-reviewer) to every applicable pattern-reviewer-* at once on top of the always-on pattern-test-coverage gate, posts one # Slice Review comment, and returns the verdict (it flips no label and opens no PR — the calling workflow owns those). The primary path is the runReviewSlice() fan-out (below). |
| sre | sonnet | write | CI/CD owner (GitHub Actions, OIDC, environments, image promotion). Defined but not yet auto-dispatched by any workflow skill — invoke manually for now. |
/deep-dive-featureThree sequential phases (product → design → architecture). The orchestrator grows the team one teammate at a time: it does not pre-create writers until the interviewer they answer is ready to hand off a dispatch payload.
product-owner + userproduct-owner directlyrequirement-writerdocs/<feature-name>requirement-writer (subagent_type = doc-writer)product-owner via SendMessagedesign-lead + user + 1–2 designers + design-writerdesign-lead after the requirement is publisheddesign-lead directlydesigner teammates (toolboxes ui-ux-pro-max / taste-skill, one per installed plugin) generate plain-HTML candidates; the human votes the winner (no plugins → skip, design-lead's own taste)design-writer commits docs/design-system/{overview,tokens,components,accessibility}.md + surfaces.md + docs/ui-contract/<screen>.yaml + the winning samples into docs/design-system/samples/architect + userarchitectarchitect directlydoc-writer instancesarchitectdocs/<feature-name> branchfeature-lockin/scaffold-project
Optional, runs once on a greenfield project (the skill aborts if any of
backend/, frontend/, a compose file, or
e2e/ already exists). Reads stack and topology decisions
from docs/architecture-decision-record/ and materializes a
bootable skeleton from templates. Ends in its own PR.
backend, frontend, compose, e2e) must be missing.docs/stack.yaml manifest exists (the adr writer publishes it at lock-in — scaffold distills it only as a fallback for older lock-ins). A declared stack without a template takes the skeleton path (layout + manifests + ci-checks.sh pinned; framework entry owned by the first engineer slice).chore/scaffold-project.docker-compose.yaml → commit.docker compose up -d --build, probe each framework-metadata endpoint, then docker compose down. Stops on failure — does not mutate templates to mask a broken boot.npm install → commit.docs/design-system/tokens.md and surfaces.md must be present (locked upstream by design-lead during /deep-dive-feature). Fails loudly if absent — scaffold consumes the design system, it does not generate it.tokens.md into frontend/src/styles/tokens.css and import it from the frontend entry → commit. (The ## Design taste section of CLAUDE.md is already authored by design-writer — scaffold doesn't re-write it.)/ship [milestone]
One sweep through the outer stages, in order. The orchestrator runs
skills/operation-git/scripts/ship-finder.sh [milestone]
once — pure shell, no LLM — to discover every eligible candidate against ONE
GitHub-state snapshot, then walks the report top-to-bottom. /ship
has five stages — reconcile →
analyze-bug → kickoff →
fix-pr → close-pr — spanning all three kinds.
Milestone is optional: pass one to scope to a feature, omit
it for the repo-wide maintenance lane (all open bugs + one-off enhancements).
Each stage is self-skipping (its report section reads
- (none) when there's nothing to do). One invocation = one pass —
wrap with /loop /ship [milestone] to keep advancing until the
work ships.
/implement-feature <feature-name> is the
feature-only fallback: the same flow minus the analyze-bug stage
(four stages, always milestone-scoped), driven by task-finder.sh.
The command's whole job is: reconcile dead-run locks,
dispatch the read-only analyze-bug engineer for freshly-filed
bugs (→ # Bug Analysis comment → human approval gate),
launch a unit's Workflow at kickoff (routed by
kind: — implement-slice.mjs for feature/enhancement,
fix-bug.mjs for bug), and shepherd the resulting
PR. The inner unit cycle — author E2E, coverage gate,
implement, pass E2E, review, fix (or, for a bug, regression-test-first → fix →
review) — is never the command's concern; it runs entirely inside the
Workflow that kickoff launches (next section).
The orchestrator never waits for backgrounded work within a pass:
once it launches a workflow or dispatches an engineer, it ends the pass; a
finished run re-invokes it (event-driven) and the next pass picks up what
moved.
status:in-progress whose implement-slice Workflow died, or a draft PR status:fix-in-progress whose fix-pr engineer diedlast_seen vetoes the reap) with GitHub-activity staleness as fallbackkind:feature + status:ready-to-implement slices with zero open Blocked by and not already lockedstatus:ready-to-implement → status:in-progress (the lock that hides the slice from the next pass)implement-slice.mjs in the background, one per slice, via the Workflow toolstatus:fix-in-progressengineer (fix-pr verb) — the only agent the outer loop dispatches directlymergeable + check rollup as a go/no-go gatemerge:autoCloses #<slice-#> line; merge:manual PRs are left for the userStage numbers are non-contiguous (0, 1, 8, 9) on purpose — they preserve the identity of the surviving stages from the old nine-stage scheme. Stages 2–7 (implement-task, review-task, fix-task, prepare-slice, review-slice, fix-slice) were retired: their work now lives inside the slice workflow.
/loop /implement-feature <feature-name>implement-slice / fix-pr run re-invokes the orchestrator (fast path); its tracking task is closed by owner at pass entryScheduleWakeup (≈1800s) is the backstop for dead runs, merge-driven Blocked by cascades, and lost sessions — not a pollstatus:need-attentiontask-finder.sh drops it from every stagestatus:ready-to-implement so kickoff relaunches a fresh run
The heart of v0.40. The slice lifecycle is exactly two workflow
layers (Workflow nesting is one level deep — a child
calling workflow() throws). A workflow script spawns every
agent() as a peer in one flat pool, expressing fan-out the
two-level Agent tree can't. Both scripts ship with the plugin under
workflows/ and are invoked by scriptPath against
${CLAUDE_PLUGIN_ROOT}.
/loop /implement-feature <feature> (outer driver: reconcile / kickoff / fix-pr / close-pr)
└─ Stage 1 LAUNCHES (background, one per slice):
implement-slice.mjs ← TOP: owns author → implement → review → fix → PR
├─ agent() e2e-author / engineer (generative, serial — shared worktree)
└─ runReviewSlice(…) ← inlined fan-out: coverage gate + gate review + quality review (one axis-reviewer agent per pattern)
└─ agent() ×N (one per pattern-reviewer dimension + adversarial verify)
The split rule: assessment work that is parallel-decomposable → a
fan-out child workflow; generative work that is sequential → a single
agent. Only the reviewer stages qualify as workflows — the author /
implement / pass-E2E / fix stages are TDD chains on one shared slice worktree,
so they can't parallelize and stay single agent() dispatches.
implement-slice.mjs — the per-slice cycle (TOP)
One background run per slice. It owns the entire inner cycle that the old
nine-stage /implement-feature used to round-trip through GitHub
labels. GitHub keeps only durable, human-relevant state: the slice issue, the
status:in-progress lock (held for the whole run), the
status:need-attention halt, and the final draft PR. Task tracking
lives in the slice body's ## Tasks static-ID checklist — Prep
parses it, and each dispatched agent ticks its boxes as it finishes.
| Phase | Realization | What it does |
|---|---|---|
| Prep | agent() | Read the slice body, parse the checklist (the resume source), resolve branch + PR metadata. |
| Author E2E | agent · e2e-author | One dispatch for every not-yet-[x] e2e task. Skipped if the slice has no e2e tasks — and a slice gets one only when it closes a cross-surface journey segment, so backend-only / pure-layout slices skip this phase entirely. |
| Coverage gate | runReviewSlice('test-coverage') | New in 0.40. Static review of the authored specs vs the slice AC + non-happy-paths, before any production code. Loops to an e2e-author fix until covered (no round cap). On resume it is skipped only when the newest # E2E Coverage Gate comment says APPROVE — ticked e2e boxes prove authoring, not passage, so a run killed on a BLOCK re-gates. |
| Plan | agent() | Group impl tasks into ordered engineer dispatches (DAG-respecting, ≤3 tasks/group — the size cap that replaces the deleted budget gate's "bound the context" role). |
| Implement | agent · engineer | Groups run serially (shared worktree). Done groups skipped (resume). |
| Pass E2E | agent · engineer (diagnose → fix loop) | Each round: one diagnose dispatch boots the stack, runs the specs, and categorizes failures into correlated groups; then one fix dispatch per group runs serially (shared worktree). Loops (uncapped) until a round diagnoses GREEN. A test-case constraint → halt(). |
| Gate review | runReviewSlice('production-code', …, 'gate') | The fan-out over the gating dimensions only (spec-compliance / contract / security), looping to an engineer fix-slice until APPROVE (no round cap). Judges each task at its owning layer (a backend invariant is proven at the backend layer, never demanded through E2E) via a per-task discharge ledger; on APPROVE the workflow ticks every AC checkbox — the reviewer-gated verified gate (the engineer's task-box tick is only a progress claim). |
| Quality review | runReviewSlice('production-code', …, 'quality') | The fan-out over the code-quality axes only (never blocking). Bounded, not a loop: exactly one review/fix cycle (review → one engineer polish pass over the Defer/Nit findings) plus one final re-review, whose residual debt is triaged into kind:refactor / kind:enhancement tracking issues at status:ready-to-review. |
| PR | agent() | Open the idempotent merge:auto draft PR (Closes #<slice>) and release the slice lock. |
Gating fix loops are uncapped — coverage gate, implement
re-dispatch, and the gate review each loop until they reach
confidence to pass (review APPROVE, or every task ticked
[x]). The quality review is the exception — bounded to one
fix cycle + one re-review, never a loop (code quality never blocks, so
its residual is triaged into tracking issues rather than chased to zero).
Re-review rounds are anchored: each gets the prior round's
findings + the exact sha that round judged, closure-checks them (same
title/file, no upward re-grade of unchanged code), and hunts new findings only
in the code changed since — convergence instead of an independent re-sample of
the whole diff per round. A gating I:M is always classed
Fix (never Defer) and the fix dispatch
inlines the Fix-class findings, so a skipped gating MEDIUM can't
flap into a later-round blocker. The fan-out's
full adversarial verify is
opt-in (verifyLenses arg, default OFF) — when on,
only a finding that survives refutation holds a gate open; when off the
dimension reviewer's own severity stands for non-blocking findings, but each
newly-reported verdict-driving blocker still faces an always-on
2-lens (correctness + context) floor — neutralised only when both
lenses refute it on concrete evidence (coverage gap dropped; gate blocker
downgraded to MEDIUM, still fixed via the gating-I:M→Fix
class). Either way the
gate review blocks only on a gating-dimension
I:H — spec-compliance, contract, or security — while
code-quality findings are deferred debt handled by the separate
quality review and never block the slice.
halt() flips
status:in-progress → status:need-attention and posts
a comment — the only path to a human; the outer loop never recovers it. Two
progress guards bound the uncapped loops: the oscillation
stall (the same blocker surviving its own targeted fix for 3
consecutive rounds) and the churn guard (3 consecutive
rounds each surfacing a new blocker on code unchanged since the
prior round — reviewer noise, not defects).
Resume is the slice branch's WIP commits (each carrying
Task: <id> + Refs #<slice>) + the durable
checklist + the Workflow resume journal — plus the
verdict comments for review passage: every gate/review
comment is stamped with the reviewed branch-tip SHA
(**Reviewed tip:**) and an invisible
<!-- resume-state --> marker carrying the loop-guard
streaks. Each looping review (coverage gate, gate review) runs a
one-shot read-only reviewEntryAction probe before its first
review (the gate review's probe is hoisted to the Pass E2E phase): a
durable coverage-gate APPROVE skips the gate; a gate APPROVE still at the
remote tip skips Pass E2E + Gate review (straight to the idempotent
AC-tick + PR, and the quality pass too when its comment already exists at
that tip); a standing BLOCK verdict that nothing landed
against — no commit and no fix-summary comment after it —
returns fix-first, dispatching the fix straight away instead of
re-running the fan-out only to reproduce the same BLOCK (a fix
that did land, even partially, falls through to
review, which catches the rest); and any BLOCK re-seeds the
oscillation + churn streaks from its resume-state marker instead of
resetting them. There are no handoff docs.
runReviewSlice() — inlined fan-out review
A function inside implement-slice.mjs (was a separate
review-slice.mjs child workflow before this change), called for
the pre-implementation coverage gate
(scope:'test-coverage') and the two
post-implementation review stages (scope:'production-code',
switched by reviewMode: 'gate' runs the gating
dimensions, 'quality' runs the code-quality axes). It isolates each review dimension onto its own
axis-reviewer agent and — only when the
verifyLenses arg is on (default OFF) — adversarially
verifies every finding before it can block: verification batches
same-dimension findings (≤10 per agent) through three independent skeptic
lenses, so dispatch scales with dimensions × chunks rather than one agent per
finding while the cross-lens majority vote stays intact. With verify off (the
default) findings are trusted as the reviewer graded them and this pass is
skipped — it is itself a self-review, so it is opt-in.
The new boundary (changed in 0.40): it posts the
verdict comment and RETURNS the verdict object — it flips
no label and opens no PR. The parent
implement-slice owns the lock and the terminal draft PR.
Previously, when the outer /loop called it directly at Stage 6, it
flipped review:running → review:passed/need-fix
and opened the PR itself; that boundary moved up into the parent.
gate mode : Prep ─► Gating dims (fan-out) ──── dedup ─ verify ─► compose ─► Publish (BLOCK on gating I:H)
quality mode : Prep ─► Quality dims (fan-out) ─── dedup ─ verify ─► compose ─► Publish (ADVISORY, never blocks)
(worktree/diff) gate: ≤3 gating pattern-reviewer-* dims · quality: the debt dims the touched surfaces select (incl. per-language lenses)
each fan-out + 3-lens refutation (opt-in) (code) (1 agent)
Each pass fans out, dedups, then verifies before composing —
so the verdict decides on a confirmed finding, never a raw
one. Dedup and scoring (severity → Impact, (Impact, Effort)
→ Fix/Defer/Nit/Drop, gate verdict = BLOCK iff a gating-dimension
(spec/contract/security) I:H survives; quality verdict = always
ADVISORY — every code-quality finding is deferred debt) are plain
deterministic JS, not LLM steps. Each dimension agent
reads exactly one pattern-reviewer-* skill and applies
that skill's per-project .claude/memory/patterns/<skill>.md
overlay — so dreamed rules reach the fan-out the same way they reach the
single-agent fallback.
Scope coverage runs only the Spec-phase
test-coverage dimension over the authored E2E specs,
pre-implementation: the usual "test files are out of scope" rule
inverts (the specs are the deliverable), the verdict is BLOCK
on any confirmed coverage gap (not just I:H), and Quality
is skipped entirely.
Quality review — one fix cycle, one re-review, then debt triage.
Because code-quality findings never block, the slice doesn't churn on them: the
quality review is a separate, bounded pass that runs only after the gate
review APPROVES. It does exactly one review/fix cycle — review the
code-quality axes, then a single engineer polish pass over the non-gating
(Defer / Nit) findings — plus one final
re-review (it is not a loop). Whatever debt remains after that pass is then
triaged into tracking issues — one per review dimension, routed by
kind: non-functional findings → kind:enhancement
(they add observable behavior, so they earn a feature-shaped body with ACs + an
e2e task and the full E2E/integration treatment); every other dimension →
kind:refactor (behavior-preserving — a no-e2e
## Tasks checklist, so implement-slice skips all E2E
machinery and the only new tests are unit tests for extracted seams). Both are
created at status:ready-to-review (the human gate) and deduped
against open issues of that kind, so the quality debt is recorded for the
/ship maintenance lane instead of holding the slice. fix-bug.mjs
mirrors the same two-stage split via its own runReview('gate') /
runReview('quality') — gate fix loop, then one bounded quality cycle +
triage — minus the AC-tick (a bug has no AC ledger; the regression test is its
spec-compliance gate).
The phases split across two models by the kind of work each does — judgment stays on
Sonnet, mechanical work drops to Haiku. Tunable in one place via
AGENT_MODEL / WRITER_MODEL at the top of the script.
| Phase | Model | Why this tier |
|---|---|---|
| Prep | haiku | Read-only worktree, diff vs origin/main. Pure tool-orchestration — carries no review judgment. |
| Prep · surfaces | sonnet | Turns the raw touched paths into the surface flags that decide which dimensions run (full scope only). The one judgment call in prep: a misclassified path silently drops a whole review dimension, so it keeps the stronger model (and is biased toward true). |
| Spec / Quality / Verify | sonnet | The pattern-reviewer-* dimension fan-out plus the 3-lens adversarial refutation — the judgment-bearing review work. Pinned to match the single reviewer fallback agent (model: sonnet). |
| Publish | haiku | Writes the comment, runs post-comment.sh, returns the verdict. A pure executor — the only write in the whole workflow. |
Agents don't share memory. They share GitHub state. The cross-pass protocol is a small set of labels; the within-slice task ledger is the slice body's checklist. That's why the lifecycle survives crashes, context limits, and user interruptions — the next pass just reads the state and re-derives where work is.
v0.40 deleted four whole label families. The inner slice cycle no longer
round-trips through labels — it runs inside one workflow — so the labels that
drove each inner step are gone:
level:*
type:*
review:*
e2e:*.
level:* is moot (one issue per slice now), type:*
lives in the checklist's per-task type, and review:* /
e2e:* became in-memory state inside the workflow.
implement-slice.mjs)implement-slice.mjs cycle, no interviewimplement-slice.mjs minus E2E (no-e2e task body)/ship analyze → human gate → fix-bug.mjs# Bug Analysis)merge:auto)/deep-dive-feature## Tasks section is the durable task ledgere2e.1, be.1, fe.2) are permanent — never translated to issue numbers[ ] → [x] as each agent finishes; this is the resume sourceTask: s<slice#>.<id> + Refs #<slice#>Two of the three lanes below are state machines over GitHub labels (the slice issue and the draft PR). The middle lane is different: the inner cycle that used to be a label machine is now a phase progression inside one workflow run — no labels flip between its phases. Read top to bottom for the happy path; the orange call-outs mark the failure loops. The pill on each arrow is the actor that performs the step.
/implement-feature stage or a workflow skill (e.g. create-feature-issues)
agent the implement-slice Workflow or a dispatched sub-agent
human the user
github GitHub automation (PR merge auto-closes linked issues)
Blocked by; otherwise locks + LAUNCHES the workflow
Closes #<slice-#> body closes this issue
status:need-attention is a
user-owned halt. The orchestrator never touches it; the human comments,
fixes the blocker (e.g. edits an E2E spec), then flips
status:need-attention → status:ready-to-implement
so kickoff relaunches a fresh run from the checklist + WIP commits.
## Tasks checklist (the resume source)
merge:auto draft (Closes #<slice>); release the lock
agent() prefix from the resume journal — no
handoff docs.
Closes #<slice-#>
engineer (fix-pr)
merge:auto
Two cross-cutting rules emerge from the diagrams. (1) The
status:in-progress label is the slice lock — held for the
entire workflow run, it hides the slice from the next kickoff pass and is what
the reconcile reaper releases when a run dies. (2) The inner cycle no
longer flips labels — review verdicts, E2E validation, and fix loops
are in-memory phase transitions inside one run; only the four durable
transitions (lock, halt, draft PR, merge) touch GitHub.
Two distinct channels: a Team-shared channel for the
interactive discovery agents (product-owner,
design-lead, designer and doc-writer
instances, architect) and a workflow dispatch channel for the
lifecycle agents (engineer, e2e-author,
axis-reviewer agents) — almost all of which are now
dispatched by the implement-slice Workflow, not the
command directly.
TeamCreate spins up named teammates that can
SendMessage each other. The orchestrator grows the team
one teammate at a time. Writers pull dispatch payloads from
interviewers via SendMessage — the orchestrator never
forwards artifacts inline.
product-owner ↔ user (direct)product-owner ↔ requirement-writer (pull payload)design-lead ↔ user (direct)design-lead ↔ designer-pro-max / designer-taste (pull interview results; user votes the winner)design-lead ↔ design-writer (pull payload)architect ↔ user (direct)architect ↔ 5 writers (pull scoped payloads)
/implement-feature runs task-finder.sh once per
pass, then at Stage 1 launches one implement-slice
Workflow per slice. That workflow dispatches every inner-cycle
agent as a background peer; the outer loop dispatches only the
fix-pr engineer. Agents run to completion, commit, push, tick
their checklist boxes. No shared memory.
implement-slice Workflow (one per slice)e2e-author / engineer (per task group)runReviewSlice() → N axis-reviewer agentsengineer fix-pr (the lone outer-loop dispatch)
engineer-pre-push.sh fires as a PreToolUse
hook on every Bash call. It no-ops unless the command
contains git push in an engineer worktree. On a real
push it runs the lint / type / security / test gate for the relevant
stack and denies the push on failure.
┌──────────────┐ ┌────────────────────┐
│ USER │ │ orchestrator │
└──────┬───────┘ │ (/deep-dive) │
│ └─────────┬──────────┘
│ talks directly to │ invites + briefs
│ │
▼ ▼
┌──────────────┐ SendMessage ┌────────────────┐
│ architect │ ◄──── pull ───────│ adr-writer │
│ (read-only) │ ─── payload ────► │ (subagent_type │
│ │ │ = doc-writer) │
└──────────────┘ └────────────────┘
▲ │
│ also answers: │ commits ADRs
│ • implement-detail-writer │ on the feature
│ • api-contract-writer │ branch
│ • data-model-writer │
│ • runbook-writer │
The user is in the loop in three specific places — and intentionally out of the loop everywhere else.
| Moment | Why | What the user does |
|---|---|---|
| discovery interview | Only the user knows what they want to build. product-owner, design-lead, and architect talk to the user directly — the orchestrator does not interpose, paraphrase, or guess. |
Answers questions. Says "lock requirements" / "lock the design" / "lock decisions" when ready. |
| PR review | Every workflow ends with a PR. Discovery PRs (feature-lockin) and scaffold PRs require a human merge. Slice PRs default to merge:auto (the implement-slice workflow's default), so close-pr lands them once green + MERGEABLE. |
Reviews and requests changes via comments before CI goes green — or relabels to merge:manual to hold the PR open and merge it by hand. |
status:need-attention |
The implement-slice workflow calls halt() rather than guess when an E2E spec rewrite is needed, scope is ambiguous, or an infra step fails (the inlined review can't set up its worktree, or a verdict can't be posted). Fix loops themselves are uncapped — they loop to confidence-to-pass rather than halting. The lifecycle stops on that slice / PR until the human clears the label. |
Edits the spec / clarifies scope / removes the label so the next pass picks the work up. |
Everywhere else — task dispatch, code review, security review, fix
loops, draft PR creation, merge of merge:auto PRs — the
user can step away. The loop reads labels, dispatches one-shot agents,
and advances. /loop /implement-feature <feature-name>
keeps it going until the feature is shipped or until something hits
status:need-attention.