Appearance
Manufacture an approved queue from a vision
Goal: start from a vision doc alone and end with an approved work queue that /warp-drive can consume — without authoring any requirements by hand.
This is the Level 4 "clear the runway" front-end (#869). It sequences the existing PM command skills; it does not reimplement them. For the backbone CLI contract see the Autonomous PM Front-End reference.
Prerequisites
- A vision doc at
docs/vision.md(or pass--path). It must be substantive: a Vision section plus problem/goal/user framing.check-visionfails closed on a thin or missing doc. - The
/business-case,/capability,/requirement, and/groomskills provisioned (they are universal PM commands). ghauthenticated for the repo.
Steps
1. Confirm the vision is usable
bash
node ~/.claude/scripts/warp-drive/pm-frontend.js check-vision --jsonok: true → proceed. ok: false → the reasons[] tell you what is missing (no Vision heading, too thin, no problem/goal framing). Do not invent a vision — an absent vision is a human-only blocker.
2. Get the plan
bash
node ~/.claude/scripts/warp-drive/pm-frontend.js scaffoldThis prints the ordered chain — /business-case → /capability → /requirement → /groom — grounded in a digest of your vision, with a reuse note on each step. Follow it in order.
3. Drive the PM chain
Run the skills in sequence, letting each one do its own authoring:
/business-case # justify the investment (skip for a narrow, obvious vision)
/capability # capabilities with user stories + a requirements checklist
/requirement # requirements with testable ACs, a priority label, Part-of links
/groom # reconcile the cluster, confirm readiness, mark ready reqs approvedThe one rule the gate enforces later: every requirement must come out of /groom with a priority label, testable acceptance criteria, and no unresolved blocked / needs-clarification collision.
4. Hand human-only blockers back as TODOs
When decomposition hits something only a human can do — a paid account, an API key, a domain registration, a design sign-off — file a TODO instead of guessing:
bash
node ~/.claude/scripts/warp-drive/pm-frontend.js emit-todo \
--title "register the production domain" \
--summary "Test-env promotion needs the domain registered and DNS delegated." \
--instructions "Register the domain;Delegate DNS to Cloudflare;Comment the zone ID here" \
--blocks 42 --priority p2-highThe todo is filed as todo,full-auto,<priority> assigned to paulirv, then validated against the TODO Format Contract. Preview without filing using --dry-run.
5. Gate the queue
bash
node ~/.claude/scripts/warp-drive/pm-frontend.js verify-queue --area <slug> --json- exit 0 — the queue is non-empty, consumable unchanged by warp-drive discovery, and every requirement is groom-ready. The runway is clear.
- exit 1 — read
failures[]and fix the offending requirements, then re-run. - exit 2 — a
gh/repo error, not a queue verdict.
6. Hand off to warp-drive
bash
/warp-drive --area <slug>Discovery picks up exactly the queue the gate just verified — the gate's oracle is discover-queue.sh, so there is no drift between "verified" and "consumed".
Doing it all at once
/autonomous-pm run --area <slug> walks these steps as one command; /autonomous-pm plan (or --dry-run) stops after the scaffold and authors nothing — the read-mostly pre-flight.
From a shell: bob groom (#2051)
/groom needs a model session; the farm needs to schedule one. bob groom runs the same command headless — scripts/groom/groom.sh inlines the /groom command text (commands/groom.md) with the scope and a mode line into one claude -p prompt (precedent: scripts/swarm/grade-review.sh). It is the wrapper, not a re-implementation: no grooming logic lives in it.
bash
bob groom # bare /groom (all-open), DRY-RUN — proposes, edits nothing
bob groom --area warp-drive --apply # /groom area:warp-drive at Level 3 — logs the plan inline and applies
bob groom --issues 2051 # the single-target /groom 2051, DRY-RUN
bob groom --issues 2050,2051 --apply --json| Flag | Effect |
|---|---|
--area <slug> | --issues N,N | --all | The scope, in /groom's own grammar: area:<slug> · N (one issue) or "issues #N, #N — groom them as one set" (several) · bare /groom. Exactly one; --all is the default. |
--apply | Automation Level 3: read-then-write logs the plan inline and applies it. The project is switched to Level 3 first when it is below it (skills/automation/scripts/switch-level.sh 3 --yes — a visible settings.local.json edit, named on stderr). Without it the run carries an explicit DRY-RUN instruction: propose only. |
--timeout <min> | Default 30. The run is sent TERM at the limit and KILL 30 s later; the kill is reported (timed_out: true, exit 4), never silent. Works without coreutils: timeout, else gtimeout, else perl (scripts/lib/portable-timeout.sh), so a Mac bounds the run the same way. |
--cwd <dir> / --json | The project to groom; one bob-groom/1 document instead of the streamed output. |
Decisions without a human. AskUserQuestion and the RDB ask_remote tool are passed as --disallowedTools, and the prompt says why: a step that needs a human files one conforming todo (format contract), leaves that item blocked, and continues. That is how the RDB enforcement hook (hooks/rdb-enforce-ask-remote.sh) is satisfied headlessly — nothing hangs on a Telegram reply.
The exit code is the summary. The prompt asks the model to end with the per-mode summary and one trailer line — GROOM-RESULT: groomed=<n> approved=<n> blocked=<n> todos=<n> deferred=<n> — which the wrapper maps: 0 groomed · 1 blockers reported (blocked>0), or no trailer at all · 2 usage/config · 3 claude not on PATH or failed to run · 4 killed at --timeout. tests/test-bob-groom.sh drives it with a fake claude on PATH that echoes the prompt.
A rate limit never ends a groom early (#3190). The gh shim waits for GitHub quota by itself, and the prompt tells the model so. If a run still ends without its trailer and its output mentions a rate limit, the wrapper waits for the quota to reset and runs it once more. --json reports that as attempts: 2 and retry: {reason, waited_s}.
A run always ends with a trailer. When the model gave none, the wrapper prints its own as the last line: GROOM-RESULT: groomed=0 approved=0 blocked=0 todos=0 deferred=0 incomplete=1 reason=<why>. --json marks it trailer_source: "wrapper" and keeps result null. The exit code is unchanged, so it is never read as a groomed result. See Forge Health.
Related
- Autonomous PM Front-End reference
- Warp-Drive how-to — the loop that consumes the queue
- TODO Format Contract