| name | orchestrate |
| description | Turn a well-specified change request (ADR / spec / issue / feature) into a dependency-ordered, test-first, code-grounded GOAP execution plan. Use when the user wants to plan a complex, multi-part or cross-cutting implementation before writing code; wants a TDD/test-first execution plan; wants work fanned out across code-grounded analysis agents and synthesized into a dependency-ordered plan; or asks to "orchestrate", "plan this ADR/feature", "structure this into workstreams", or "build a test-first plan". Derives its own workstreams from the spec + real code (does not assume fixed API/Data/UI lanes), grounds every step in cited source, and gates the plan through a perspective-diverse Codex critique panel before the human ratifies and writes the final plan of record.
|
orchestrate — code-grounded, test-first planning
Turn a change request into a dependency-ordered, test-first, code-grounded GOAP execution
plan. You (top-level Claude) are the conductor: you own the human gates and the Codex
critique; a deterministic Workflow script (scripts/orchestrate.workflow.js) owns the
Understand → Fan-out → Synthesize core.
This skill deliberately fixes the failure modes of a naïve fan-out planner: it derives its
workstreams (never a fixed API/Data/UI carve-up), forces evidence/provenance into every node,
reconciles conflicts at synthesis, and replaces a single completeness critic with a
perspective-diverse Codex panel. See references/rationale.md for each fix and why it matters.
When to use / when not
Use it to plan a complex, multi-part, or cross-cutting change before writing code. Do not
use it for a one-line fix, a pure question, or work with no code surface — the fan-out overhead only
pays off when the change spans multiple concerns and the ordering/tests are non-obvious.
"Lightweight" is not a second code path — it is the same workflow with fewer workstreams, fewer
lenses, and a smaller budget. Never hand-roll a parallel alternative.
Prerequisites (preflight — check BEFORE Phase 1)
This skill is self-contained except for one declared peer dependency: the Phase 4 critique panel
runs on the codex-review skill (its codex_session.sh helper drives the Codex TUI). That
dependency is by design — genuine model diversity is the whole point of the panel — but it means the
skill needs codex-review installed on the machine. Preflight it and fail fast rather than
discovering it mid-run after burning the fan-out:
CODEX="$(dirname "$SKILL_DIR")/codex-review/scripts/codex_session.sh"
[ -x "$CODEX" ] || CODEX="$HOME/.claude/skills/codex-review/scripts/codex_session.sh"
[ -x "$CODEX" ] || { echo "orchestrate: requires the 'codex-review' skill for the critique panel — install it first"; exit 1; }
command -v wezterm >/dev/null || { echo "orchestrate: codex-review needs wezterm"; exit 1; }
command -v codex >/dev/null || { echo "orchestrate: codex-review needs the codex CLI on PATH"; exit 1; }
Use "$CODEX" for the Phase 4 launches below (the bare codex_session.sh in the examples is that path).
If codex-review is absent and cannot be installed, do not silently skip the panel — stop and tell
the user the critique gate is unavailable (a plan with no adversarial review is a different, weaker
deliverable). Everything else the skill needs (schemas, prompts, the workflow) is bundled under
<skill>/.
Reference files (read the one you need, when you need it)
references/spec-quality.md — the single source of truth for the Phase 0 rubric (the five
"well-specified" dimensions). The workflow's gate prompt embeds a generated copy; the adr skill
reads this file directly. dev/orchestrate/tests/rubric-drift.sh guards them against divergence — never hand-edit
the generated gate block, edit only the JSON.
references/goap-schema.md — the JSON Schemas (workstreams, GOAP nodes, synthesized
plan) and the normalized-token rule. The schemas are also inlined in the workflow script — that
script is the runnable source of truth; the doc explains the fields.
references/critique-lenses.md — the critique lenses, a minimal review-instructions template per
lens, the provenance-audit tiering, and the opt-in structured-findings contract.
references/synthesis-contract.md — canonicalize → dedup → reconcile → topo-sort responsibilities.
references/rationale.md — why the skill is shaped this way (the failure modes it engineers out);
read it if you're unsure why a step exists before changing it.
Phase 0 — Gate (you own this, before the workflow)
Bind provenance once, richly. Record a run-level provenance object and pass it into the workflow:
repo=$(git -C "$WORKDIR" rev-parse --show-toplevel)
branch=$(git -C "$WORKDIR" rev-parse --abbrev-ref HEAD)
commit=$(git -C "$WORKDIR" rev-parse HEAD)
dirty=$(git -C "$WORKDIR" status --porcelain | head -c1 | grep -q . && echo true || echo false)
captured_at=$(date -u +%FT%TZ)
run=$(date +%Y%m%d-%H%M%S)
Two distinct ids — do not conflate them (see Resume). run above is the human/audit slug used
for filenames and Codex session names. The Workflow engine's runId is the runId field in the
Workflow tool result — that is the only value valid for resumeFromRunId. Persist both.
-
If dirty, snapshot the complete dirty state so citations stay auditable — a plain
git diff misses staged and untracked changes that git status --porcelain counts as
dirty, so cited code could be absent from the snapshot. Capture both, and hash the whole bundle:
git -C "$WORKDIR" diff --binary HEAD > "$WORKDIR/reviews/$run.patch"
git -C "$WORKDIR" ls-files --others --exclude-standard -z \
| tar -C "$WORKDIR" --null -T - -czf "$WORKDIR/reviews/$run.untracked.tgz"
patch_hash=$(cat "$WORKDIR/reviews/$run.patch" "$WORKDIR/reviews/$run.untracked.tgz" 2>/dev/null | sha256sum | cut -d' ' -f1)
Make the provenance lens mandatory for the run. Offer the human (via AskUserQuestion) the
choice to commit/stash/git add first for a clean anchor. Provenance object:
{ repo, branch, commit, dirty, patch:"reviews/<run>.patch", untracked:"reviews/<run>.untracked.tgz", patch_hash, captured_at }.
-
content_hash format (dirty runs). Each cited range's content_hash is
sha256:<hex> over the exact cited line bytes as they exist in the working tree (i.e. after the
dirty patch is applied) — schema pattern ^sha256:[0-9a-f]{64}$. Compute it as
printf 'sha256:%s' "$(sed -n '44,71p' "$WORKDIR/src/api/router.rs" | sha256sum | cut -d' ' -f1)"
(substitute the cited path + Lstart,Lend). The provenance lens recomputes and compares.
Spec-quality gate. The workflow's first step scores the spec; if it returns { blocked:true, gaps },
stop and surface the gaps to the human via AskUserQuestion — do not fan out over a vague spec.
Re-invoke once the spec is clarified. (The workflow never prompts the human itself; only you can.)
Phases 1–3 — run the Workflow (deterministic core)
Invoke the workflow (multi-agent orchestration — invoking this skill is the user's opt-in).
Always give the workflow both the spec text and a real spec_path, so source:"spec" fact refs
are auditable:
- spec given as a path → Read the file, pass its full text as
spec and the path as spec_path
(never pass the bare path as spec — the gate would score the path string, not the spec);
- spec given inline (an issue/feature typed by the user) → persist it to
reviews/<run>-spec.md and pass that path as spec_path. Otherwise agents must invent a path for
spec citations and the audit trail breaks.
Workflow({
scriptPath: "<skill>/scripts/orchestrate.workflow.js",
args: { spec: "<full TEXT of the ADR/spec>", spec_path: "<path, for provenance>",
provenance: <the object above> }
})
(The workflow's prompts also defensively read a bare path if one slips through, but the conductor
reading it is the authoritative contract.)
It returns one of:
{ blocked:true, gaps } → gate/derive failed; ask the human, then re-invoke.
{ noop:true, reason } → no code change is warranted; report reason and stop (do not invent lanes).
{ needs_human:[{kind,question,context}], plan, … } → Synthesis raised human-decision escalations
(unresolvable conflict, ambiguous token, or plan-blocking unmet fact). Stop before the panel,
ask each question via AskUserQuestion, record the answers, and re-invoke the workflow with
args.humanAnswers = [{question, answer}, …] (plus resumeFromRunId) so Synthesis settles them.
{ plan, workstreams, dropped_lanes, provenance, node_count } → the synthesized plan; persist it
(next step) and proceed to the panel.
Persist the plan artifact (the Codex panel reviews a file, never an in-memory value): write the
returned plan in full — nodes, ordered_plan, alias_map, node_merges, dropped_nodes,
conflicts, unresolved_facts, unresolved_dependencies, assumptions, escalations — to
reviews/<run>-plan-r<round>.json, and store that path in the state file. Each
re-synthesis round writes a new -r<round>.json before its re-review.
Record { scriptPath, auditRun:<run>, workflowRunId:<runId from the tool result>, round:0, plan_file, review_files:[], spec, spec_path, provenance } in a small state file under
reviews/<run>.state.json so you can resume (see Resume). Persist spec_path here — every
resume invocation must pass it back or inline-spec provenance vanishes on the re-review round.
Phase 4 — Critique panel (you drive Codex; loop back on FIXES_REQUIRED)
Run a perspective-diverse Codex panel via the codex-review skill — genuine model diversity is
the whole point (a Claude critic of a Claude plan shares blind spots). Lenses, per-lens minimal
instructions, and provenance tiering are in references/critique-lenses.md. Default lens set:
correctness, integration, test-coverage, provenance. A lightweight run drops integration
(keep correctness + test-coverage); provenance is never fully dropped — on a lightweight run it
still audits high-risk nodes + a small sample per the tiering in critique-lenses.md, and it is
exhaustive on a dirty-worktree run. (Don't state a contract here that contradicts that doc.)
For each lens, write minimal instructions in the project with a unique name, then launch one
review per lens concurrently in the background (Bash run_in_background: true). Pass absolute
paths — the helper does not resolve them relative to --workdir, so a relative path breaks unless
you happen to be cd'd into $WORKDIR:
codex_session.sh review --workdir "$WORKDIR" \
--instructions-file "$WORKDIR/reviews/<run>-<lens>-r<round>-codex-instructions.md" \
--review-file "$WORKDIR/reviews/<run>-<lens>-r<round>-codex-review.md"
Completion is the helper's process return. codex_session.sh review now waits for the Codex
turn to finish generating and the review file to be fully written (its wait_written closes the
old streamed-partial-file race), verifies the file ends in an exact VERDICT: line, then prints it
and closes the window. So just wait for each background command's completion notification — no
--keep-open, no .env sourcing, no manual pane polling. (It also pre-seeds Codex folder-trust, so
a fresh --workdir no longer hangs on the trust dialog.)
On a non-zero exit, distinguish two cases and do NOT just re-launch blindly (the helper refuses
to stomp an existing review file):
- Died at startup — the session is not
ALIVE (codex_session.sh list) and no review file
appeared: retrying the same command is safe and correct.
- Timed out / pane died — the window is left open and a partial review file may exist. Stop the
session (
codex_session.sh stop --session …), delete the partial review file, then relaunch with a
larger --timeout. There is no further completion notification to wait on for the dead attempt.
Read each review's verdict from the final physical line (tail -n 1 <review-file>) and accept it
only if it is exactly VERDICT: GO or VERDICT: FIXES_REQUIRED (don't grep for any VERDICT:
substring — a malformed review with trailing text must not pass).
The loop (MAX_ROUNDS default 3 = total panel attempts):
round = 0
loop:
run all lenses concurrently (background); wait for each review to return; collect each VERDICT
if every lens VERDICT == GO: → SHIP → Phase 5
elif round + 1 >= MAX_ROUNDS: → ESCALATE: hand the human the unresolved log to accept/reject
else:
re-invoke the workflow with the prior review files (see Resume), so only Synthesize re-runs;
the re-review points each lens at its OWN prior review file (don't re-state findings —
let Codex re-verify); round += 1
A human may accept residual findings at any round to ship early; record who/when/which in the
state file. Keep a persistent unresolved-issue log across rounds so a surviving gap stays visible.
Optional unattended low-risk auto-exit: only if the user asks for it, switch the lenses to the
structured-findings contract in references/critique-lenses.md and ship when every residual finding
is severity:NIT / risk:low. Off by default (it trades the minimal-instructions discipline for a
parseable contract).
Resume (re-invoke on FIXES_REQUIRED)
Workflow({
scriptPath: "<skill>/scripts/orchestrate.workflow.js",
resumeFromRunId: <workflowRunId from the state file — the runId in the prior Workflow tool result,
NOT the audit slug>,
args: { spec, spec_path, provenance, priorReviews: [<paths of this round's review files>],
humanAnswers: [<{question, answer} from any needs_human round>] }
})
// spec, spec_path, and provenance MUST be the exact same values from the state file — omitting
// spec_path drops source:"spec" provenance on the re-review round.
Unchanged agent() calls (Understand, Fan-out) return cached; only Synthesize re-runs.
resumeFromRunId is same-session only — if it is unavailable/invalid, re-invoke without it
(a full fresh run) and mark that round in the state file as a fresh analysis round, not a resume,
so the audit trail stays honest.
Phase 5 — Deliver (the human writes the plan of record)
Assemble the ratifiable package and present it: the dependency-ordered TDD plan, the alias map +
node-merge record, the dropped-node ledger (fan-out nodes rejected outright, with reasons), the
conflict resolutions, the unresolved-facts, unresolved-dependencies, and open-assumptions logs,
the per-lens critique verdicts, and the provenance table. Then hand off: the human writes and owns
the final plan
document. You produced the nodes and the audit trail; you do not author the plan of record.
Dependency (satisfied)
The Phase 4 panel relies on codex_session.sh review returning only after the review is complete.
That is now the case: the helper's wait_written waits for the Codex turn to finish generating and the
review file to be fully written before it returns and closes the window — so the panel just launches
each lens in the background and waits for the process to return. (Earlier revisions of this skill
carried a manual pane-polling fallback for when the helper returned on a partial file; that is no
longer needed.)