Skip to content

Autonomous PM Front-End

Manufacture an approved queue from a vision

Section titled “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.

  • A vision doc at docs/vision.md (or pass --path). It must be substantive: a Vision section plus problem/goal/user framing. check-vision fails closed on a thin or missing doc.
  • The /business-case, /capability, /requirement, and /groom skills provisioned (they are universal PM commands).
  • gh authenticated for the repo.
Terminal window
node ~/.claude/scripts/warp-drive/pm-frontend.js check-vision --json

ok: 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.

Terminal window
node ~/.claude/scripts/warp-drive/pm-frontend.js scaffold

This 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.

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 approved

The 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.

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:

Terminal window
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-high

The todo is filed as todo,full-auto,<priority> assigned to paulirv, then validated against the TODO Format Contract. Preview without filing using --dry-run.

Terminal window
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.
Terminal window
/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”.

/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.

/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.

Terminal window
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.