ship-playbook: dialable review gates to cut token cost (reorder intake, skippable reviews, per-merge worktree removal)

The skill ran every gate every time and burned tokens. Each expensive gate is now independently
dialable from full-rigor down to skip; defaults are lighter (but the user can still go full swing).

1. Reorder intake to execution order (7 questions, two AskUserQuestion calls): second harness → plan
   review → build handoff → per-task review → impl review → go-live audit → map refresh.
2. Per-task review skippable — taskReview ∈ skip|native|harness. 'skip' removes the per-task reviewer
   AND the fix loop (biggest save); task passes on engineer validate.
3. Final impl review skippable — implReview ∈ skip|claude|claude+harness.
4. Plan/founder review — planReview ∈ skip|claude|claude+harness.
   + harness is now ONE global external review harness (none|codex|kiro) used by any claude+harness gate
     or taskReview=harness; buildHarness (who writes) stays a separate axis.
   + MUSTs preserved: full-swing config (everything + harness + goLive) and delegating build AND
     per-task review to codex/kiro both supported.
   + Guardrail: warn (not block) when taskReview AND implReview are both skipped — nothing checks the
     build; return surfaces noReviewGate + reviewConfig and Phase 3 caveats the verdict.
5. Worktrees: integrate now removes each merged worktree IMMEDIATELY (per-merge, not batch); preflight
   and final dangling-sweep kept.

Reconciled across SKILL.md (intake, rules 2/3/5/6, Phase 2 steps, Phase 3, success criteria, output
contract, description), workflow-template.js (config, gating, handoff routing, return), harness-routing.md,
playbook-state.md, build-loop.md. Removed MAX_ROUNDS/maxRounds remnants. JS syntax verified.
This commit is contained in:
Ciprian Spiridon
2026-06-19 08:36:01 +04:00
parent 3e5e3dcb0b
commit 0a92002eca
5 changed files with 215 additions and 146 deletions
+103 -77
View File
@@ -6,11 +6,12 @@ description: |
plan, build it task by task, review the build, and optionally audit it for launch — then return the
verified findings as feedback (one pass, no autonomous loop; the user decides on any fix round). It
chains the existing skills as one runnable Workflow:
plan-to-task-list-with-dag (plan + assign a specialist agent per task) → plan-founder-review (loop
to APPROVE) → a specialist engineer/reviewer build across the DAG → a full claude ∥ codex/kiro
cross-review → go-live-audit. Up front it asks two things — which harness cross-reviews
(claude / codex / kiro / none) and whether to run a go-live audit at the end — then executes every
step end to end. Use when the user wants "prompt → planned, built, reviewed, audited" in one go
plan-to-task-list-with-dag (plan + assign a specialist agent per task) → plan-founder-review
a specialist engineer/reviewer build across the DAG → a full claude ∥ codex/kiro cross-review →
go-live-audit. Up front it asks which gates to run and at what depth — every review is independently
dialable from full rigor (claude + a second harness everywhere, build/review delegated to codex/kiro)
down to skip, so the user controls token cost. Use when the user wants "prompt → planned, built,
reviewed, audited" in one go
instead of running each phase by hand.
allowed-tools:
- Skill
@@ -47,24 +48,28 @@ This skill drives a long-running, multi-agent delivery Workflow. Non-negotiable
skill (Phase 3) presents them and the USER decides whether to run a fix round. The Workflow executes
steps 314 as real phases; the skill performs steps 1, 2, 2.1 (the prompt + the intake questions)
and feeds them in as `args`.
2. ALWAYS ask the intake questions first (plan-review harness + go-live audit, plus the optional
end-of-run project-map refresh). The first two are Workflow inputs, not steps it can skip; the map
refresh is a Phase-3 action the skill runs after the Workflow returns.
2. ALWAYS ask the intake questions first (the seven: second harness, plan review, build handoff,
per-task review, impl review, go-live audit, project-map refresh). These select which gates run and
at what depth; they are Workflow inputs (except the map refresh, a Phase-3 action). Honor the
choices — the user may dial to full rigor or skip gates to save tokens.
3. The BUILD is a Workflow phase, not a description. Per task across the DAG layers: the ENGINEER
implements on a task branch in an isolated worktree, an in-workflow INTEGRATE agent git-merges it
onto the working branch, the REVIEWER reviews the integrated state, and a bounded fix loop runs
until the task passes. Engineer and reviewer default to the plan's matched specialist agents; when
the user chose a build/review handoff they route to `codex` or `kiro` instead (`buildHarness` /
`taskReviewHarness`).
onto the working branch AND removes each merged worktree, the REVIEWER reviews the integrated state
(unless `taskReview skip`), and a bounded fix loop runs until the task passes. Engineer routes per
`buildHarness` (native specialist / `codex` / `kiro`); reviewer routes per `taskReview` (native
`-reviewer` / the second harness / none).
4. The build picks the closest AVAILABLE specialist per task; it falls back to `general-purpose` ONLY
with the user's consent after the skill notified them a specialist is missing — never silently. When
a task's stack skill is installed, the engineer MUST use it (`/nextjs`, `/laravel`, `/rust`, …).
(This applies to the native path; when the user handed building/reviewing to `codex` or `kiro`,
those tasks route there instead.)
5. Gates are real. The founder-review loops review → FIX → re-review until APPROVE / no issues; the
build loops engineer → reviewer → fix until the task passes. Never wave a gate through.
6. Codex delegation goes through the codex plugin (`codex:codex-rescue` agentType). Kiro via the
kiro path. "claude" = native. "none" = skip the external cross-review. (See `harness-routing.md`.)
5. Gates that ARE enabled are real — never wave one through or fake a clean verdict to exit. But the
user controls WHICH gates run: a skipped gate (`planReview skip`, `taskReview skip`, `implReview
skip`, `goLive no`) is a deliberate choice, not a gate to sneak back in. Warn (don't block) when
both per-task and impl review are off — nothing checks the build then.
6. The `harness` is ONE global external review harness: `none` (claude/native only), `codex` (the
`codex:codex-rescue` plugin), or `kiro` (the kiro path). It is the second opinion any `claude+harness`
gate or `taskReview harness` uses. `buildHarness` (who writes) is a separate axis. (See `harness-routing.md`.)
7. There is no autonomous recursion. After one pass, surface the verified findings honestly and let
the user choose to run a fix round (re-invoke with the findings as the prompt) — NEVER fake a clean
verdict, and never silently loop.
@@ -89,32 +94,45 @@ plan-vs-implementation gate), and an optional go-live audit — then it RETURNS
feedback. It runs ONE pass and does not loop on its own; if findings remain, the user decides whether
to run a fix round.
The 14 steps map to the Workflow phases: **step 3 → Plan · steps 49 → Plan review (native ∥ selected
harness, one bounded loop) · steps 1011 → Build · step 12 → Impl review (plan-vs-implementation) ·
step 14 → Verify (dedup + adversarial verify → feedback) · step 13 → Audit (only if build+impl
verified-clean)**. Steps 1, 2, 2.1 are the prompt and the questions the skill collects up front. There
is no automatic recursion — the workflow returns its findings and stops.
The 14 steps map to the Workflow phases: **step 3 → Plan · steps 49 → Plan review (optional, bounded
loop) · steps 1011 → Build (per-task review optional) · step 12 → Impl review (optional,
plan-vs-implementation) · step 14 → Verify (dedup + adversarial verify → feedback) · step 13 → Audit
(only if `goLive` AND build+impl verified-clean)**. Steps 1, 2, 2.1 are the prompt and the questions
the skill collects up front. Each review gate runs at the depth the user chose (skip / claude /
claude+harness); there is no automatic recursion — the workflow returns its findings and stops.
## Phase 1 — Intake (steps 1, 2, 2.1)
The prompt is `$request` (step 1). Ask the governing questions up front (in one or two
`AskUserQuestion` calls — the tool allows up to 4 questions each), unless `$request` already pins them:
The prompt is `$request` (step 1). Ask the governing questions up front (in two `AskUserQuestion` calls
— the tool allows up to 4 each), in execution order so they make sense, unless `$request` already pins
them. Each review gate is independently dialable so the user controls token cost — defaults are LIGHT;
the user can dial every gate UP to full rigor, or DOWN to skip. The questions:
1. **Plan/impl cross-review harness** (step 2) — which second harness cross-reviews the PLAN and the
full implementation: `claude`, `codex`, `kiro`, or `none`. (This is the review cross-check; it is
separate from who builds/reviews each task below.)
2. **Go-live audit at the end** (step 2.1) — `yes` adds the go-live audit after the build, `no` stops
at the implementation review.
3. **Refresh the project map at the end** — whether to regenerate the `CLAUDE.md` context map after
the build lands so it reflects the new code: `map-project` (single project),
`map-project-monorepo` (workspace), or `no`. Detect the repo layout and offer the matching default
(a workspace/monorepo → `map-project-monorepo`, otherwise `map-project`). Run only in Phase 3 on a
real, non-aborted run.
4. **Build handoff** — who WRITES the code for each task: `native` (the plan's specialist engineer
agents — default), `codex` (the codex plugin), or `kiro` (the Kiro CLI). Passed as `buildHarness`.
5. **Per-task review handoff** — who REVIEWS each task: `native` (the matched `-reviewer` agent —
default), `codex`, or `kiro`. Passed as `taskReviewHarness`. Independent of #1 (which is the
one-shot plan/impl cross-review) — this is the per-task reviewer in the build loop.
1. **Second harness** — the ONE external review harness used wherever a gate below is set to
"claude + harness": `none` (default), `codex`, or `kiro`. (claude/native always runs its own side;
this is the optional second opinion.) Passed as `harness`.
2. **Plan (founder) review**`skip`, `claude` (native founder review only — default), or
`claude + harness` (native ∥ the second harness). Passed as `planReview`.
3. **Build handoff** — who WRITES the code for each task: `native` (the plan's specialist engineer
agents — default), `codex`, or `kiro`. Passed as `buildHarness`.
4. **Per-task review** — who REVIEWS each built task: `skip` (no per-task reviewer or fix loop —
biggest token save), `native` (the matched `-reviewer` agent — default), or `harness` (the second
harness). Passed as `taskReview`.
5. **Final implementation review** — the plan-vs-implementation review after the build: `skip`,
`claude` (native — default), or `claude + harness`. Passed as `implReview`.
6. **Go-live audit at the end**`no` (default) adds nothing; `yes` runs the go-live audit (only if
build+impl come back verified-clean). Passed as `goLive`.
7. **Refresh the project map at the end** — regenerate the `CLAUDE.md` context map after the build:
`no` (default), `map-project` (single project), or `map-project-monorepo` (workspace). Detect the
repo layout and offer the matching default. Run only in Phase 3 on a real, non-aborted run.
**Defaults** (lighter than full, kept safe): `harness none`, `planReview claude`, `buildHarness native`,
`taskReview native`, `implReview claude`, `goLive no`, map `no`. The user can choose **full swing**
`planReview claude+harness`, `taskReview harness`, `implReview claude+harness`, `buildHarness codex|kiro`,
`goLive yes`, with `harness codex|kiro` — or delegate building and per-task review to codex/kiro
(`buildHarness` + `taskReview harness`). **Warn (do not block)** if the user sets BOTH `taskReview skip`
AND `implReview skip`: nothing then checks the build, so a clean verdict only means the engineer
validates passed — say so before launching.
Then gather the project facts the Workflow needs (do not ask the user — read the repo): `root`
(absolute repo path), `workingBranch` (the current branch to build on — never build on a protected
@@ -147,21 +165,23 @@ that wasn't installed):
Never silently substitute `general-purpose` for a missing specialist without telling the user first.
**Verify the chosen build/review handoff harness is installed, and notify if not.** If `buildHarness`
or `taskReviewHarness` is not `native`, confirm its tooling exists before launching:
- **kiro build** needs the `hand-over-to-kiro` skill (by Sabeur Thabti, @thabti) **and** `kiro-cli`
(`kiro-cli --version`); **kiro review** needs the `kiro-review` skill **and** `kiro-cli`.
- **codex** (build or review) needs the codex plugin (`codex:codex-rescue`).
**Verify any chosen harness tooling is installed, and notify if not.** Whenever `harness` is `codex`
or `kiro`, or `buildHarness` is `codex`/`kiro`, confirm its tooling exists before launching:
- **codex** (the `harness` second opinion, or `buildHarness codex`) needs the codex plugin (`codex:codex-rescue`).
- **kiro build** (`buildHarness kiro`) needs the `hand-over-to-kiro` skill (by Sabeur Thabti, @thabti)
**and** `kiro-cli` (`kiro-cli --version`); **kiro as the `harness`** (used by any `claude+harness`
gate or `taskReview harness`) needs the `kiro-review` skill **and** `kiro-cli`.
If a chosen handoff's tool is missing, NOTIFY the user with `AskUserQuestion` — offer to **install it**
If a chosen harness's tool is missing, NOTIFY the user with `AskUserQuestion` — offer to **install it**
(for kiro: `hand-over-to-kiro` via `npx skills add …` + kiro-cli from <https://kiro.dev/docs/cli>) or
**switch that handoff to `native`** (or another available harness). Do not silently fall back.
**fall back** (drop the `+harness` to `claude`, set `harness none`, or `buildHarness native`). Do not
silently degrade.
Open a master `TodoWrite` mirroring the phases in `references/playbook-state.md`.
**Success criteria**: `harness`, `goLive`, `mapRefresh`, `buildHarness`, `taskReviewHarness`, `root`
(a confirmed git work tree), `workingBranch`, `validate`, `hardRules`, and `availableAgents`
(+ `allowGeneralFallback` if any specialist is missing) are all resolved.
**Success criteria**: `harness`, `planReview`, `buildHarness`, `taskReview`, `implReview`, `goLive`,
`mapRefresh`, `root` (a confirmed git work tree), `workingBranch`, `validate`, `hardRules`, and
`availableAgents` (+ `allowGeneralFallback` if any specialist is missing) are all resolved.
## Phase 2 — Run the playbook Workflow (steps 314)
@@ -174,9 +194,9 @@ Then launch `references/workflow-template.js` via the **Workflow** tool, passing
```
Workflow({ scriptPath: ".../references/workflow-template.js",
args: { prompt, harness, goLive, root, workingBranch, validate, hardRules,
auditScriptPath, availableAgents, allowGeneralFallback,
buildHarness, taskReviewHarness } })
args: { prompt, root, workingBranch, validate, hardRules, goLive,
harness, planReview, buildHarness, taskReview, implReview,
auditScriptPath, availableAgents, allowGeneralFallback } })
```
**Pass `args` as a real JSON object, NOT a JSON-encoded string.** A stringified blob reaches the
@@ -185,26 +205,28 @@ script as one string, fails its `typeof args === 'object'` check, and every inpu
`claude|codex|kiro|none`) instead of returning a fake `converged:true`, so a stringified-args launch
errors loudly — if you hit it, relaunch as a FRESH run (no resume) with `args` as an object.
The Workflow then executes the rest of the playbook, in order, as real phases — there is no step it
skips:
The Workflow then executes the playbook in one pass, running each gate at the level the user chose:
- **Plan (step 3)** — a planning agent follows the plan-to-task-list-with-dag methodology unattended
(mode auto-selected), grounds every path in the real repo, assigns a specialist engineer +
`-reviewer` + stack skill to each task, writes `.ulpi/plans/<name>.md`+`.json`, returns `{tasks, layers}`.
- **Plan review (steps 49)** — ONE bounded loop: native founder review (∥ the selected harness when
`harness != none`) → fix the plan (JSON-first, re-render MD) → re-review. Exits as soon as no
BLOCK/CONCERN remain (OBSERVATIONs never block) OR a fix round stops reducing the blocking count —
- **Plan review (steps 49)** — per `planReview`: `skip` (no review), `claude` (native founder review),
or `claude+harness` (native ∥ the second harness). ONE bounded loop → fix the plan (JSON-first,
re-render MD) → re-review; exits on no BLOCK/CONCERN (OBSERVATIONs never block) OR non-convergence,
capped at `MAX_REVIEW` (2).
- **Build (steps 1011)** — walk the DAG layers; per task: engineer (worktree, task branch) →
in-workflow integrate agent (`git merge` onto the working branch) → reviewer → bounded fix loop
until it passes; barrier between layers. Engineer/reviewer = the native specialist by default, or
`codex`/`kiro` per the `buildHarness`/`taskReviewHarness` handoff.
- **Impl review (step 12)** — full implementation review (plan vs implementation), native ∥ selected harness.
in-workflow integrate agent (`git merge` onto the working branch, then removes each merged worktree)
→ reviewer (unless `taskReview skip`) → bounded fix loop until it passes; barrier between layers.
Engineer = native specialist / `codex` / `kiro` per `buildHarness`; reviewer = native `-reviewer` or
the second harness per `taskReview` (or none if `skip`).
- **Impl review (step 12)** — per `implReview`: `skip`, `claude`, or `claude+harness`. The
plan-vs-implementation review of everything built.
- **Verify (step 14)** — dedup + adversarially verify the build+impl findings. These become the
returned `openRegister` — the feedback. No automatic re-plan/re-build; the workflow returns and stops.
- **Audit (step 13)** — runs only when build+impl are verified-clean: if `goLive`, COMPOSE the proven
`go-live-audit` workflow inline via the `workflow()` hook (`auditScriptPath`) — gates → finders →
dedup → dual-lens verify → critic — ∥ a selected-harness audit lane; its findings become `openRegister`.
- **Audit (step 13)** — runs only when `goLive` AND build+impl come back verified-clean: COMPOSE the
proven `go-live-audit` workflow inline via the `workflow()` hook (`auditScriptPath`) — gates →
finders → dedup → dual-lens verify → critic — ∥ a second-harness audit lane; its findings become
`openRegister`.
Watch progress via `/workflows`. To iterate on the script, edit the saved `scriptPath` the tool
returns and re-invoke with `{scriptPath}` (and `resumeFromRunId` to reuse cached agent results).
@@ -213,7 +235,7 @@ the script re-executes from the top, so omitting `args` empties `CFG` and the sc
`FILL:` guard. Always include the full `args` object you launched with.
**Success criteria**: The Workflow runs to completion and returns
`{ converged, ranReal, plan, build, openRegister, missingAgents }`.
`{ converged, ranReal, plan, build, openRegister, missingAgents, reviewConfig, noReviewGate }`.
## Phase 3 — Report and escalate
@@ -226,8 +248,11 @@ Read the Workflow result:
- **If `missingAgents` is non-empty**, some tasks ran on `general-purpose` because the assigned
specialist isn't installed here. Surface the list (which agents, how to install) so the user can
decide whether to install them and re-run for higher-quality output.
- **If `noReviewGate: true`** (the user skipped BOTH per-task review and impl review), CAVEAT any
clean verdict: it only means the engineer validates passed, nothing reviewed the build. Report
`reviewConfig` so the user sees which gates ran.
- **`converged: true`** (real run, `openRegister` empty) → DONE. Report the build outcome per task,
the review/audit verdicts, and where the plan landed.
the review/audit verdicts (per `reviewConfig`), and where the plan landed.
- **`openRegister` non-empty** → PRESENT the feedback and let the user decide. List the verified
BLOCK/CONCERN findings (file:line, issue, suggested fix, which gate found them). Then offer the next
move: **run a fix round** (re-invoke the workflow with the findings as the prompt — same intake),
@@ -239,16 +264,17 @@ aborted), run it last** — invoke the chosen skill (`map-project` or `map-proje
`CLAUDE.md` context map reflects the code the build just landed. Skip it on an aborted/false-clean run
(there's nothing new to map). This is the final step, after reporting.
**Success criteria**: Either the gates are genuinely clean, or the user is handed an honest list of
what still blocks, with the round budget respected; and the project map is refreshed if requested.
**Success criteria**: Either the enabled gates are genuinely clean (caveated by `reviewConfig` /
`noReviewGate`), or the user is handed an honest list of what still blocks plus next moves; and the
project map is refreshed if requested.
## Guardrails
- Do not run proactively; this is explicit-user-only (it spawns many agents across rounds).
- Round 1 runs the full cycle; recursion rounds are a fix loop (decompose → build → impl review) and
deliberately skip founder plan review. Do not re-introduce plan review on recursion, and do not skip
Impl review on any round — it is the plan-vs-implementation gate. The Workflow owns 314, the skill
owns 12.1.
- The workflow runs ONE pass and never loops on its own; a fix round is a deliberate user choice
(re-invoke with the findings as the prompt). Review gates are user-selected per run — honor the
user's `planReview`/`taskReview`/`implReview` choices, and warn (don't block) when both per-task and
impl review are skipped. The Workflow owns 314, the skill owns 12.1.
- Do not hand-roll the plan — the Workflow's plan phase follows the plan-to-task-list-with-dag
methodology and assigns a specialist agent per task.
- The build assigns the closest AVAILABLE specialist per task; fall back to `general-purpose` only with
@@ -287,9 +313,9 @@ what still blocks, with the round budget respected; and the project map is refre
Report:
1. intake — selected harness and go-live choice, resolved working branch
2. rounds run and convergence status
3. per-round plan name + build outcome per task (passed / fixes / blocked)
4. implementation review — native + harness findings (confirmed vs rejected)
5. go-live audit — verdict and blockers (or "skipped")
6. final state — clean, or the honest remaining-findings list with the round budget status
1. intake — the review config used (`reviewConfig`: harness + which gates ran at what depth), go-live
choice, resolved working branch
2. plan name + build outcome per task (passed / fixes / blocked)
3. plan review and implementation review — findings by enabled gate (confirmed vs rejected), or "skipped"
4. go-live audit — verdict and blockers (or "skipped")
5. final state — clean (caveated if `noReviewGate`), or the honest remaining-findings list + next moves
+4 -2
View File
@@ -89,8 +89,10 @@ Spawn the task's assigned specialist agent (the plan's `Agent` field) via the Ag
### 2. Review — the reviewer agent
When the engineer reports done, spawn the MATCHED specialist reviewer (the engineer's name +
`-reviewer`) read-only over that task's diff:
This step is gated by `taskReview`: `skip` (no per-task reviewer or fix loop — the task passes on its
engineer validate alone), `native` (the matched `-reviewer` below), or `harness` (the global review
harness — codex/kiro). When review is enabled, on engineer-done spawn the reviewer read-only over the
task's diff:
- `isolation: "worktree"` against the engineer's branch/worktree; do NOT let it edit.
- Brief: read the task's diff + surrounding context, verify each acceptance criterion is actually
+25 -20
View File
@@ -1,35 +1,40 @@
# Harness routing
The intake question picks ONE second harness: `claude`, `codex`, `kiro`, or `none`. "claude" is
always the native side (this orchestrator IS claude). The selected harness is the *external
cross-check* that runs alongside native claude. `none` skips the external cross-check entirely.
The `harness` intake picks ONE global external review harness: `none`, `codex`, or `kiro`. Native
claude (this orchestrator) always runs its own side of any enabled review; the harness is the optional
*external cross-check* run alongside it. It is used wherever a gate is set to **`claude+harness`**
(`planReview`, `implReview`) or `taskReview` is **`harness`**. `none` = native only, no external lane.
This file pins how each choice maps to a concrete invocation for the three review surfaces the
playbook uses: **plan review** (a markdown/JSON plan, not a diff), **code review** (a branch diff),
and **go-live audit** (the whole repo).
This file pins how each choice maps to a concrete invocation for the review surfaces the playbook uses:
**plan review** (a markdown/JSON plan), **code review** (a branch diff), and **go-live audit** (the repo).
## The matrix
| Surface | `claude` (native, always runs) | `codex` | `kiro` | `none` |
|---|---|---|---|---|
| Plan review (Phase C) | `plan-founder-review <plan>` (forked) | `codex:codex-rescue` agent, read-only founder-review brief | `kiro-review` adapted to the plan files | native only |
| Code review (Phase F, impl review) | `claude-review` over the branch (or a `general-purpose` reviewer in a worktree) | `codex-review` over the branch | `kiro-review` over the branch | native only |
| Go-live audit (Phase G) | `go-live-audit` (multi-agent workflow) | `codex:codex-rescue` agent, read-only launch-audit brief | `kiro-review` whole-repo | native audit only |
| Surface | native (claude, always runs its side) | `codex` | `kiro` |
|---|---|---|---|
| Plan review (`planReview claude+harness`) | `plan-founder-review <plan>` (forked) | `codex:codex-rescue` agent, read-only founder-review brief | `kiro-review` adapted to the plan files |
| Impl review (`implReview claude+harness`) | `claude-review` over the branch (or a `general-purpose` reviewer in a worktree) | `codex-review` over the branch | `kiro-review` over the branch |
| Go-live audit (Phase G) | `go-live-audit` (multi-agent workflow) | `codex:codex-rescue` agent, read-only launch-audit brief | `kiro-review` whole-repo |
Native claude always runs its side. When `harness != none`, the selected column runs **in
parallel** with the native side. Plan review (Phase C) is a bounded loop (exits clean or
non-converging); impl review and audit run once and their findings are returned as feedback.
Native always runs its side when the gate is enabled. With `claude+harness` AND `harness != none`, the
harness column runs **in parallel** with native. Plan review is a bounded loop (exits clean or
non-converging); impl review and audit run once and their findings are returned as feedback. Any gate
can be `skip`ped — then neither lane runs.
## Per-task build & review handoff (separate from the cross-review harness)
## Per-task build & review handoff
The `harness` above is the one-shot cross-review of the plan and the full implementation. Two
**independent** selectors decide who does the per-task work inside the build loop — `buildHarness`
(who WRITES each task) and `taskReviewHarness` (who REVIEWS each task), each `native | codex | kiro`:
Two selectors decide who does the per-task work inside the build loop — `buildHarness` (who WRITES each
task) and `taskReview` (who REVIEWS each task). `buildHarness``native | codex | kiro` is an
independent axis; `taskReview``skip | native | harness`, where `harness` routes to the ONE global
`harness` (codex or kiro):
| Handoff | `native` (default) | `codex` | `kiro` |
|---|---|---|---|
| Build (write) — `buildHarness` | the plan's specialist engineer agent (`resolveAgent(t.agent)`, in a worktree) | `codex:codex-rescue` agent (write-capable), worktree, brief allows edits | a `general-purpose` agent that runs the **`hand-over-to-kiro`** skill (by Sabeur Thabti, @thabti) to delegate the build to `kiro-cli`; if that skill or the CLI is absent it implements directly |
| Per-task review — `taskReviewHarness` | the matched `-reviewer` agent (`resolveAgent(t.reviewer)`) | `codex:codex-rescue` agent, READ-ONLY brief | the **`kiro-review`** skill via the Kiro CLI, READ-ONLY; if unavailable it says so and returns empty findings (never substitutes a native review) |
| Build (write) — `buildHarness` | the plan's specialist engineer agent (`resolveAgent(t.agent)`, in a worktree) | `codex:codex-rescue` agent (write-capable), worktree, brief allows edits | a `general-purpose` agent that runs the **`hand-over-to-kiro`** skill (by Sabeur Thabti, @thabti) to delegate the build to `kiro-cli` (autonomous); if that skill or the CLI is absent it implements directly |
| Per-task review — `taskReview` (`harness` → global) | the matched `-reviewer` agent (`resolveAgent(t.reviewer)`) | `codex:codex-rescue` agent, READ-ONLY brief | the **`kiro-review`** skill via the Kiro CLI, READ-ONLY; if unavailable it says so and returns empty findings (never substitutes a native review) |
`taskReview skip` runs no per-task reviewer at all (and no per-task fix loop) — the task passes on its
engineer validate alone.
These are wired in `workflow-template.js` (`buildSpawn` / `taskReviewSpawn`). The native path keeps the
specialist-agent availability handling (`resolveAgent` + `missingAgents` reporting); the codex/kiro
+7 -5
View File
@@ -28,11 +28,13 @@ A intake ──> B plan ──> C plan-review loop (native ∥ harness, bounded)
DONE user decides: fix round / hand-fix / accept
```
- B (plan) and C (plan review) run ONCE. C is a plan-QUALITY gate (scope, decomposition, phantom
paths): ONE bounded loop (native ∥ selected harness; native-only when `harness == none`), exits on no
BLOCK/CONCERN (OBSERVATIONs never block) OR non-convergence, capped at `MAX_REVIEW` (2).
- E barriers between DAG layers; each task loops engineer↔reviewer until it passes.
- F is the plan-vs-implementation gate.
- B (plan) runs once. C (plan review) runs per `planReview`: `skip` (omitted), `claude` (native), or
`claude+harness` (native ∥ the global harness). When it runs it's a plan-QUALITY gate (scope,
decomposition, phantom paths): ONE bounded loop, exits on no BLOCK/CONCERN (OBSERVATIONs never block)
OR non-convergence, capped at `MAX_REVIEW` (2).
- E barriers between DAG layers; each task loops engineer↔reviewer until it passes — unless `taskReview
skip`, then there is no per-task reviewer/fix loop and a task passes on its engineer validate alone.
- F (impl review) runs per `implReview` (`skip` / `claude` / `claude+harness`) — the plan-vs-implementation gate.
- V dedups + adversarially verifies the build+impl findings. Survivors are `openRegister`.
- If `openRegister` is empty and `goLive`, G (the heaviest phase) runs; otherwise the workflow RETURNS
`openRegister` as feedback. There is NO automatic loop back to B/E — a fix round is a deliberate
+76 -42
View File
@@ -15,9 +15,16 @@
// the playbook; the skill just supplies them as inputs to this script. Everything else runs here.
//
// HOW TO USE: the skill launches this with
// args = { prompt, harness, goLive, root, workingBranch, validate, hardRules, auditScriptPath,
// availableAgents, allowGeneralFallback, buildHarness, taskReviewHarness }
// args = { prompt, root, workingBranch, validate, hardRules, goLive,
// harness, // 'none' | 'codex' | 'kiro' (one global external review harness)
// planReview, // 'skip' | 'claude' | 'claude+harness'
// buildHarness, // 'native' | 'codex' | 'kiro' (who WRITES each task)
// taskReview, // 'skip' | 'native' | 'harness' (who REVIEWS each task)
// implReview, // 'skip' | 'claude' | 'claude+harness'
// auditScriptPath, availableAgents, allowGeneralFallback }
// (auditScriptPath is optional — see the comment at its CFG read below.)
// Every review gate is independently dialable: from full-rigor (planReview+implReview claude+harness,
// taskReview harness, goLive) down to fast (everything skip). Lighter is the default; skip nothing for max.
// Or fill the FILL: fallbacks and run directly. Keep `meta` a pure literal or the Workflow tool
// rejects it. Build agents have Bash, so the in-workflow integrate agent does the git merges.
@@ -43,13 +50,28 @@ if (args && typeof args === 'object') CFG = args
else if (typeof args === 'string' && args.trim()) { try { CFG = JSON.parse(args) } catch { CFG = {} } }
const ROOT = CFG.root || 'FILL: absolute repo path'
const WORKING_BRANCH = CFG.workingBranch || 'FILL: branch to build on (e.g. main or a feature branch)'
const HARNESS = CFG.harness || 'FILL: claude | codex | kiro | none'
const GO_LIVE = CFG.goLive === true
const MAX_REVIEW = 2 // bounded plan-review iterations (a plan isn't code; non-convergence also early-exits)
const MAX_FIX = 3 // bounded per-task engineer↔reviewer fix iterations
const VALIDATE_ALL = CFG.validate || 'FILL: workspace validate, e.g. pnpm -w exec tsc --noEmit && pnpm lint'
const HARD_RULES = CFG.hardRules || `FILL: load-bearing invariants (import boundaries, Node strip-only,
money is BIGINT/string, RLS fail-closed, append-only ActivityLog, route-barrel wiring, …)`
let PROMPT = CFG.prompt || 'FILL: the feature request'
const GO_LIVE = CFG.goLive === true
const MAX_REVIEW = 2 // bounded plan-review iterations (a plan isn't code; non-convergence also early-exits)
const MAX_FIX = 3 // bounded per-task engineer↔reviewer fix iterations
// ── review controls (each expensive gate is independently dialable to save tokens) ──
// HARNESS is the ONE global external review harness used wherever a gate is set to "claude+harness"
// (claude/native always runs its own side; this is the optional second opinion). 'none' = no external.
const HARNESS = ['none', 'codex', 'kiro'].includes(CFG.harness) ? CFG.harness : 'none'
// PLAN_REVIEW: founder review of the plan — 'skip' | 'claude' (native only) | 'claude+harness'.
const PLAN_REVIEW = ['skip', 'claude', 'claude+harness'].includes(CFG.planReview) ? CFG.planReview : 'claude'
// TASK_REVIEW: who reviews each built task — 'skip' (no per-task reviewer/fix loop) | 'native' | 'harness'.
const TASK_REVIEW = ['skip', 'native', 'harness'].includes(CFG.taskReview) ? CFG.taskReview : 'native'
// IMPL_REVIEW: final plan-vs-implementation review after build — 'skip' | 'claude' | 'claude+harness'.
const IMPL_REVIEW = ['skip', 'claude', 'claude+harness'].includes(CFG.implReview) ? CFG.implReview : 'claude'
// BUILD_HARNESS: who WRITES each task — 'native' (plan's specialist agent) | 'codex' | 'kiro'.
const BUILD_HARNESS = ['codex', 'kiro'].includes(CFG.buildHarness) ? CFG.buildHarness : 'native'
const useHarness = (gate) => gate === 'claude+harness' && HARNESS !== 'none' // does this gate add the external lane?
// step 13: path to a FILLED go-live-audit workflow script (the skill authors it via the go-live-audit
// skill and passes its scriptPath). When set, the Audit phase COMPOSES that proven workflow inline via
// the workflow() hook; when unset, it falls back to an inline finder pass.
@@ -60,23 +82,15 @@ const AUDIT_SCRIPT_PATH = CFG.auditScriptPath || null
// specialist to general-purpose (the skill NOTIFIES the user before setting this).
const AVAILABLE_AGENTS = Array.isArray(CFG.availableAgents) ? CFG.availableAgents : null
const ALLOW_GENERAL_FALLBACK = CFG.allowGeneralFallback !== false // default true: degrade, don't crash
// Per-task work handoff (independent of the plan/impl cross-review HARNESS): who WRITES each task and
// who REVIEWS each task — 'native' (the plan's specialist agent), 'codex', or 'kiro'. Default native.
const BUILD_HARNESS = ['codex', 'kiro'].includes(CFG.buildHarness) ? CFG.buildHarness : 'native'
const TASK_REVIEW_HARNESS = ['codex', 'kiro'].includes(CFG.taskReviewHarness) ? CFG.taskReviewHarness : 'native'
let PROMPT = CFG.prompt || 'FILL: the feature request'
// Fail LOUD if inputs never reached the script. Without this, the values above stay at their FILL:
// placeholders, the plan agent is handed "FILL: the feature request", returns no tasks, and the run
// reports a fake converged:true. Refuse to start on placeholders rather than emit a false clean.
const _missing = Object.entries({ ROOT, WORKING_BRANCH, HARNESS, VALIDATE_ALL, PROMPT })
const _missing = Object.entries({ ROOT, WORKING_BRANCH, VALIDATE_ALL, PROMPT })
.filter(([, v]) => typeof v !== 'string' || v.startsWith('FILL:')).map(([k]) => k)
if (_missing.length) {
throw new Error(`ship-playbook: inputs did not reach the script — ${_missing.join(', ')} still at FILL: placeholder (typeof args="${typeof args}"). Pass args as a real JSON object per the skill's Phase 2 contract, NOT a stringified blob, then relaunch as a FRESH run.`)
}
if (!['claude', 'codex', 'kiro', 'none'].includes(HARNESS)) {
throw new Error(`ship-playbook: harness="${HARNESS}" is invalid — expected one of claude | codex | kiro | none.`)
}
const harnessAgentType = HARNESS === 'codex' ? 'codex:codex-rescue' : 'general-purpose'
// The harness lane's brief prefix. codex routes via its plugin agentType (codex:codex-rescue); kiro
@@ -213,13 +227,14 @@ Implement ONLY this task.`
}
function integrateBrief(branches) {
return `On ${WORKING_BRANCH} in ${ROOT}, integrate these task branches IN ORDER: ${branches.join(', ')}.
For each: \`git merge --no-edit <branch>\`. If one conflicts: \`git merge --abort\`, record it under
conflicted[], continue with the rest. Never force-resolve a conflict.
AFTER merging, CLEAN UP this workflow's transient build worktrees BEFORE validating — they are full
checkouts of the repo and will otherwise pollute the validate. For each merged branch: find its
worktree path via \`git -C ${ROOT} worktree list --porcelain\`, run \`git -C ${ROOT} worktree remove --force <path>\`,
then \`git -C ${ROOT} branch -D <branch>\`. Finish with \`git -C ${ROOT} worktree prune\`.
Process them ONE AT A TIME — merge a branch, then IMMEDIATELY remove its worktree, then move to the
next. For each branch:
1. \`git merge --no-edit <branch>\` (on conflict: \`git merge --abort\`, record it under conflicted[],
skip to the next branch — never force-resolve).
2. As soon as it merges, REMOVE its transient build worktree so it can't pollute anything: find the
path via \`git -C ${ROOT} worktree list --porcelain\`, \`git -C ${ROOT} worktree remove --force <path>\`,
then \`git -C ${ROOT} branch -D <branch>\`.
Finish with \`git -C ${ROOT} worktree prune\` to clear stale admin entries.
THEN run ${VALIDATE_ALL} once. The validate must cover ONLY the project at ${ROOT} — it must NOT scan
\`.claude/worktrees/**\` or sibling agent dirs (\`.factory\`, \`.gemini\`, \`.opencode\`, \`.trae\`, \`.vibe\`).
@@ -253,10 +268,11 @@ const auditBrief = `READ-ONLY launch-readiness (go-live) audit of ${ROOT}. Check
(${HARD_RULES}), build/test/lint honesty, secrets (redact values), tenancy/security, dead wiring,
placeholder/TODO in shipping code. verdict + findings BLOCK/CONCERN/OBSERVATION with file:line + evidence.`
// run native ∥ selected-harness for a read-only review surface; tag each finding's source
async function reviewBoth(label, phaseTitle, brief) {
// run native (the external harness when withHarness) for a read-only review surface; tag each
// finding's source. withHarness = the caller's gate is "claude+harness" AND a harness is configured.
async function reviewBoth(label, phaseTitle, brief, withHarness) {
const lanes = [{ source: 'native', run: () => agent(`${brief}\n(native claude)`, { label: `${label}:native`, phase: phaseTitle, schema: FINDINGS }) }]
if (HARNESS !== 'none') {
if (withHarness && HARNESS !== 'none') {
lanes.push({ source: HARNESS, run: () => agent(`${harnessRoute}\n${brief}`, { label: `${label}:${HARNESS}`, phase: phaseTitle, schema: FINDINGS, agentType: harnessAgentType }) })
}
const out = await parallel(lanes.map(l => l.run))
@@ -345,11 +361,11 @@ Never delete non-worktree files and never remove the main checkout. Report remov
}
// ── build/review handoff: who WRITES & who REVIEWS each task ─────────────────────
// Independent of the plan/impl cross-review HARNESS. buildHarness / taskReviewHarness each ∈
// native|codex|kiro. native = the plan's specialist agent (via resolveAgent + missingAgents reporting);
// codex = the codex plugin agent (write-capable); kiro = the kiro-review skill for review and the
// hand-over-to-kiro skill (which wraps the Kiro CLI, run autonomously) for build, each with a
// self-implementation fallback if the skill/CLI is absent.
// buildHarness (who WRITES) ∈ native|codex|kiro — independent of the global review HARNESS.
// taskReview (who REVIEWS) ∈ skip|native|harness; 'harness' routes to the ONE global HARNESS.
// native = the plan's specialist agent (resolveAgent + missingAgents); codex = the codex plugin agent;
// kiro = the hand-over-to-kiro skill (build) / kiro-review skill (review) wrapping the Kiro CLI, each
// with a self-implementation fallback if the skill/CLI is absent.
function buildSpawn(t, brief, label) {
if (BUILD_HARNESS === 'codex')
return spawnSpecialist(`You MAY edit files to implement this task.\n${brief}`, { label, phase: 'Build', schema: TASK_RESULT, agentType: 'codex:codex-rescue', isolation: 'worktree' })
@@ -357,12 +373,13 @@ function buildSpawn(t, brief, label) {
return spawnSpecialist(`Use the hand-over-to-kiro skill (\`/hand-over-to-kiro\`) to delegate implementing this task to kiro-cli — it builds an injection-safe prompt, runs kiro in this worktree, and verifies the diff. This is UNATTENDED: tell it to run kiro autonomously (\`--trust-all-tools\`), since no human can approve tool calls. If the hand-over-to-kiro skill or kiro-cli is unavailable, say so and implement the task yourself.\n${brief}`, { label, phase: 'Build', schema: TASK_RESULT, agentType: 'general-purpose', isolation: 'worktree' })
return spawnSpecialist(brief, { label, phase: 'Build', schema: TASK_RESULT, agentType: resolveAgent(t.agent), isolation: 'worktree' })
}
// only called when TASK_REVIEW !== 'skip' (the skip case is handled in buildPlan, no reviewer spawned).
function taskReviewSpawn(t, brief, label) {
if (TASK_REVIEW_HARNESS === 'codex')
if (TASK_REVIEW === 'harness' && HARNESS === 'codex')
return spawnSpecialist(`READ-ONLY review — do NOT edit.\n${brief}`, { label, phase: 'Build', schema: FINDINGS, agentType: 'codex:codex-rescue' })
if (TASK_REVIEW_HARNESS === 'kiro')
if (TASK_REVIEW === 'harness' && HARNESS === 'kiro')
return spawnSpecialist(`Use the kiro-review skill (\`/kiro-review\`) to review this task via the Kiro CLI, READ-ONLY; if the Kiro CLI is unavailable, say so and return empty findings — do not substitute a native review.\n${brief}`, { label, phase: 'Build', schema: FINDINGS, agentType: 'general-purpose' })
return spawnSpecialist(brief, { label, phase: 'Build', schema: FINDINGS, agentType: resolveAgent(t.reviewer) })
return spawnSpecialist(brief, { label, phase: 'Build', schema: FINDINGS, agentType: resolveAgent(t.reviewer) }) // native (or harness=none fallback)
}
// ── steps 1011: build across DAG layers, engineer → integrate → reviewer → fix ──
@@ -381,8 +398,14 @@ async function buildPlan(plan) {
// engineer-failed tasks are blocked outright
for (const b of built.filter(b => b && (!b.r || b.r.status !== 'passed')))
log.push({ task: b.t.id, status: 'blocked', reason: 'engineer validate failed', fixes: 0, findings: [] })
// initial per-task reviews are READ-ONLY → run them in PARALLEL across the layer
const passed = built.filter(b => b && b.r && b.r.status === 'passed')
// TASK_REVIEW === 'skip' (#2): no per-task reviewer / fix loop — a task passes on its engineer
// validate alone. Biggest token saver; the user opted out of per-task review.
if (TASK_REVIEW === 'skip') {
for (const b of passed) log.push({ task: b.t.id, status: 'passed', fixes: 0, findings: [] })
continue
}
// initial per-task reviews are READ-ONLY → run them in PARALLEL across the layer
const reviewed = await parallel(passed.map(b => () =>
taskReviewSpawn(b.t, reviewerBrief(b.t), `review:${b.t.id}`)
.then(r => ({ t: b.t, review: r || { verdict: 'concerns', findings: [] } }))))
@@ -447,17 +470,23 @@ if (!plan || !plan.tasks || !plan.tasks.length) {
return { converged: false, ranReal: false, aborted: 'no tasks were planned — aborted before any build (verify args/PROMPT reached the script)', harness: HARNESS, goLive: GO_LIVE }
}
// Plan review (steps 49): plan-QUALITY gate (scope, decomposition, phantom paths). ONE bounded loop,
// native ∥ selected harness; exits on no BLOCK/CONCERN or non-convergence (capped at MAX_REVIEW).
phase('Plan review')
if (HARNESS === 'none') await nativeReviewLoop(plan)
else await harnessReviewLoop(plan)
// Plan review (steps 49) — #4: 'skip' | 'claude' (native only) | 'claude+harness'. Plan-QUALITY gate
// (scope, decomposition, phantom paths). ONE bounded loop; exits on no BLOCK/CONCERN or non-convergence.
if (PLAN_REVIEW !== 'skip') {
phase('Plan review')
if (useHarness(PLAN_REVIEW)) await harnessReviewLoop(plan)
else await nativeReviewLoop(plan)
}
phase('Build') // steps 1011
const buildLog = await buildPlan(plan)
phase('Impl review') // step 12 — the plan-vs-implementation gate
const implFindings = await reviewBoth('impl', 'Impl review', implBrief(plan))
// Impl review (step 12) #3: the plan-vs-implementation gate. 'skip' | 'claude' | 'claude+harness'.
let implFindings = []
if (IMPL_REVIEW !== 'skip') {
phase('Impl review')
implFindings = await reviewBoth('impl', 'Impl review', implBrief(plan), useHarness(IMPL_REVIEW))
}
// Verify (step 14): dedup + adversarially verify the build+impl findings → this is the feedback.
phase('Verify')
@@ -473,7 +502,7 @@ if (openRegister.length === 0 && GO_LIVE) { // step 13 — only w
if (AUDIT_SCRIPT_PATH) {
lanes.push(async () => ingestGoLive(await workflow({ scriptPath: AUDIT_SCRIPT_PATH }))) // go-live-audit as a sub-workflow
} else {
lanes.push(async () => await reviewBoth('audit', 'Audit', auditBrief)) // fallback
lanes.push(async () => await reviewBoth('audit', 'Audit', auditBrief, false)) // native inline fallback (harness lane added below)
}
if (HARNESS !== 'none') {
lanes.push(async () => {
@@ -497,6 +526,11 @@ return {
build: buildLog.map(b => ({ task: b.task, status: b.status, fixes: b.fixes })),
openRegister, // verified findings = the feedback to show the user
missingAgents: [...missingAgents], // specialist agent types the plan wanted that aren't installed here → skill notifies the user
// the review configuration this run used (so the skill can report it honestly and caveat the verdict)
reviewConfig: { harness: HARNESS, planReview: PLAN_REVIEW, taskReview: TASK_REVIEW, implReview: IMPL_REVIEW, buildHarness: BUILD_HARNESS },
// TRUE when NOTHING checked the build: no per-task reviewer AND no impl review. converged then means
// "engineer validates passed", not "reviewed clean" — the skill must caveat this.
noReviewGate: TASK_REVIEW === 'skip' && IMPL_REVIEW === 'skip',
harness: HARNESS,
goLive: GO_LIVE,
}