| name | forge |
| description | Use when the user wants to drive a raw feature or bug prompt all the way to a reviewed, merge-ready PR/MR in one hands-off, autonomous run with only two human touchpoints (requirements grilling, final merge approval), or invokes /forge. Stack- and tracker-agnostic (GitHub or GitLab); reads per-repo settings from .yaah/config.yml (written by /setup-yaah); each run works in its own git worktree off the latest default branch, so many runs go in parallel without colliding; supports a parallel branch-per-issue build mode. The full phase chain and its mechanics live in the body and PLAYBOOK.md, not here. |
| disable-model-invocation | true |
| argument-hint | <what to build or fix> |
forge
Drive a raw prompt from idea to a merge-ready PR/MR by orchestrating six existing skills inside a dedicated git worktree. This file is the spine; per-phase mechanics, the subagent prompt templates, and edge cases live in PLAYBOOK.md — read it once before Phase 0.
/forge <what to build or fix> — everything after /forge is the seed prompt.
Configuration
forge is stack- and tracker-agnostic. All repo-specific settings live in .yaah/config.yml at the repo root, written by /setup-yaah:
cli — gh (GitHub) or glab (GitLab); decides every issue/PR/MR command. Recipes for both are in setup-yaah/scm-commands.md.
default_branch — the branch to base worktrees on and merge into (blank = auto-detect).
checks — the ordered commands the builder runs and forge re-checks before merge.
smoke — optional ordered commands that prove the built artifact actually RUNS (boot + health check, CLI --help, build + start), distinct from "tests pass". Run after checks in the build and re-run in Phase 6; empty = skip (library-only repos).
issue_label — label applied to forge-created issues (optional).
review — the model and subagent type for each of forge's two reviewers (all optional). Models: review.model (the per-round reviewer — cheap/scaled) and review.final_model (the once-per-run heavy Phase-6 review — most-capable); both are Agent-tool aliases (sonnet/opus/haiku), blank → omit the param so the dispatch inherits the session model (never a forced-expensive tier). Agents: review.agent (default per-round-reviewer) and review.final_agent (default final-reviewer) — the read-only reviewer subagents yaah ships and /setup-yaah installs to .claude/agents/; both fall back to general-purpose if absent. A missing block = inherit models + the default reviewer agents.
implementer — which engine runs the Phase 3 build and every Phase 4 fix round. implementer.engine is claude (default — a Claude Code subagent via the Agent tool), cursor (the cursor-agent CLI), or codex (the OpenAI codex exec CLI); the two CLI engines run headlessly inside the worktree. implementer.model (optional) overrides the model: for claude it is an Agent-tool alias (sonnet/opus/haiku, blank = inherit the session model); for cursor/codex it is that engine's own model id (blank = that CLI's default; ids are engine-specific). implementer.agent applies to the claude engine only (cursor/codex ignore it) — the subagent type forge invokes (default general-purpose; must have Bash + tracker CLI + edit tools). implementer.workflow applies to all engines: false (default) builds the children with one sequential implementer, true builds dependency-independent children in parallel — claude via the Workflow tool (one isolated worktree per agent), cursor/codex via the orchestrator launching one background forge-implement.sh per child worktree; either way each child's PR is squash-merged onto the single PRD integration branch by a serial merge barrier, behind one user gate. A missing block = claude / general-purpose / workflow:false. Only the implementer changes; grilling, issues, review, and merge are identical across engines. Exact commands + preflight live in PLAYBOOK.md under "Implementer engines".
tools.* — the token-efficiency stack (graphify, rtk, caveman). forge always uses all three, regardless of these flags — the booleans only record what /setup-yaah detected and wired; forge never gates its behavior on them (the legacy top-level graphify: key is likewise no longer read as a gate). graphify: forge explores the codebase with graphify query / explain / path instead of raw grep or whole-file reads, and refreshes the graph (graphify update .) in Phase 6 — if the binary is genuinely absent at run time it notes that and continues (never a hard fail). rtk + caveman: global Claude Code hooks that already cover the orchestrator and every Agent-tool subagent transparently. Every subagent prompt — the claude Agent build/fix, the parallel-workflow build agents, and the cursor/codex CLI builds — explicitly carries the same directive: graphify-first exploration, rtk-prefixed shell, and terse (caveman) working output, so the savings hold even for the CLI engines, which run outside those hooks. Code, commits, PR/MR bodies, and security notes always stay in normal prose. Recipes: setup-yaah/efficiency-tools.md.
At Phase 0, read this file. If it is missing, invoke /setup-yaah first, then continue with the values it wrote. Wherever a phase below says "the tracker CLI", "the checks", or "the default branch", it means the value from this config.
Non-negotiables (read first)
- Invoke the real sub-skill; never reimplement. Each orchestrator phase is a real Skill-tool call to
grill-with-docs, to-prd, to-issues, handoff, and spec-and-quality-review — all vendored into yaah, so the pipeline never depends on a harness-provided skill or built-in command. (Review runs inside a dispatched subagent that follows spec-and-quality-review — PER-ROUND mode in Phase 4, FINAL mode in Phase 6 — so the diff never enters the orchestrator's context and each review names its model.) The builder runs /tdd when the implementer is the Claude engine; under a CLI engine (cursor or codex) the builder is that CLI, which cannot call Claude Code skills, so the build prompt inlines the TDD discipline — that is the only sanctioned substitution. Paraphrasing or reinventing any orchestrator sub-skill is a violation of the forge contract.
- Autonomous after kickoff. The user is involved at EXACTLY two moments: the grilling interview (Phase 1) and the merge approval (Phase 6). NEVER prompt the user anywhere else. There is NO review-round cap and NO escalation — the review loop repeats until the reviewer approves, and a failing check just re-spawns the builder. Interrupt ONLY for a true hard blocker (no git repo, no auth, worktree-script failure, an unrecoverable tool failure): report it and stop. NEVER turn ordinary findings or test failures into questions.
- Isolated worktree, one per run. Phase 0 creates a worktree off the latest default branch and you
cd into it; every file write and command for the rest of the run happens there. The base branch stays untouched until merge, so any number of /forge runs proceed in parallel without colliding. (The one exception: with implementer.workflow: true any engine treats $BRANCH as a PRD integration branch and builds each child on its own issue branch + worktree, merging each child's PR into $BRANCH — claude's per-child worktrees are auto-cleaned by the Workflow tool, while cursor/codex worktrees are created and torn down by the orchestrator via forge-worktree.sh; the base branch is still untouched until the single Phase 6 gate merges $BRANCH → default.)
- Merge is the only gate, and the user's call. NEVER merge before the Phase 6 approval. Present the gate ONLY when the reviewer has approved AND every required check is green. Remove the worktree ONLY after a successful merge.
Pipeline
Phase 0 CONFIG+WT bash <skill-dir>/scripts/forge-worktree.sh create read config, isolated branch off default, cd in
Phase 1 GRILL /grill-with-docs interactive — lock requirements + docs
Phase 2 PRD+ISSUES /to-prd → /to-issues publish PRD parent issue, then child tasks attached to it (task-list + Parent refs)
Phase 3 BUILD /handoff → implementer (claude|cursor|codex) → /tdd work child issues one-by-one (or in parallel on per-issue branches when implementer.workflow=true): 1 commit/issue, check its PRD box, backlink + close the issue
Phase 4 REVIEW /spec-and-quality-review (dispatched) one combined reviewer/round, cheap model; loop until clean (no cap)
Phase 5 RECAP summarize the run
Phase 6 MERGE approve → rebase on latest default branch → graphify + push → verify-review → merge
State block — re-print at every phase transition
forge state
seed: <one line>
worktree: <abs path> (or: pending)
branch: <name> (or: pending)
prd: #P <url> parent issue (or: pending)
issues: #a #b #c child tasks — mark ✓ AND close each when its commit lands (or: pending)
globals: <verbatim binding rules from grill+PRD> (Phase 2: injected into every build agent + the per-round reviewer as its attention lens)
ifaces: <per child: consumes / produces signatures> (Phase 2: injected per child so parallel builds don't diverge)
pr: #M <url> the user-gate PR for the whole PRD (workflow mode: the $BRANCH→default PR; internal issue-PRs aren't tracked here) (or: pending)
round: k (starts at 0; +1 per review round)
attempts: <failing-check → consecutive-fail count> (ledger: at 3 on the same check, next dispatch is a /systematic-debugging investigation)
declined: <reviewer comment-id → implementer's push-back reason> (re-presented to the reviewer each round; only the reviewer can withdraw)
verdict: pending | changes-requested | approved (never approved while a reviewer-raised Critical/Important is unresolved)
Phases (full mechanics in PLAYBOOK.md)
- CONFIG + WORKTREE — Read
.yaah/config.yml (run /setup-yaah first if absent). Then run bash <forge-skill-dir>/scripts/forge-worktree.sh create <slug> (slug from the seed; the script auto-detects the default branch, or honors default_branch via FORGE_BASE_BRANCH). Parse WORKTREE and BRANCH from the last two stdout lines into state, then cd "$WORKTREE" — it is now the working root for every later edit, command, and subagent cwd. Script failure = hard blocker; stop. If implementer.engine is cursor or codex, also preflight that CLI now (cursor: cursor-agent --version + CURSOR_API_KEY/cursor-agent status; codex: codex --version + codex login status); a missing or unauthed CLI is a hard blocker (PLAYBOOK has the exact checks per engine).
- GRILL — Invoke
/grill-with-docs with the seed. Let it own the interview to completion: one question at a time, challenge terms against CONTEXT.md, update CONTEXT.md and docs/adr/ (under $WORKTREE) inline as decisions settle. Exit when no decision-tree branch is open. Carry forward a short locked-requirements summary + the doc files touched.
- PRD + ISSUES — First invoke
/to-prd on the locked plan: it synthesizes the grilled CONTEXT.md/ADRs into a PRD and publishes it as the parent issue via the tracker CLI from config (gh issue create / glab issue create) with the configured issue_label. Capture the PRD #/URL. Then invoke /to-issues, which breaks that PRD into tracer-bullet child issues — each references the PRD in its Parent field, and the PRD body carries a task-list (- [ ] #child) of them all — published in dependency order with the same label. Capture every child #/URL. Both skills run non-interactively: requirements were locked in Phase 1, so skip their built-in seam-check / quiz steps and decide from CONTEXT.md. Then self-review the published artifacts inline (orchestrator-run, no subagent, no user prompt — fix by editing the issues in place): every PRD user story maps to ≥1 child; the blocked-by DAG has no cycles or dangling refs; no placeholders (reject/rewrite TBD, TODO, "decide during build", "handle edge cases", "add validation", "appropriate error handling", "similar to issue N"); every interface an Implementation Decision names is built by some child; titles use CONTEXT.md terms and contradict no ADR. (PLAYBOOK Phase 2 has the checklist; a true self-contradiction the orchestrator cannot resolve from CONTEXT.md/ADRs is a hard blocker — surface and stop.) The whole PRD becomes ONE PR in Phase 3 — exactly one worktree, one branch, one PR, and one merge gate for the entire PRD; each child issue is a single commit inside it. (Under implementer.workflow: true the topology differs — $BRANCH is a PRD integration branch fed by per-child internal PRs — but there is still exactly one user merge gate, the $BRANCH → default PR; see "Implementer engines" in PLAYBOOK.)
- BUILD — Invoke
/handoff to write a compact handoff (reference the PRD + child issues by URL + the grilled decisions; do NOT restate the issue bodies). Then hand the build prompt (handoff + the build contract in PLAYBOOK.md, carrying the configured checks and cli) to the configured implementer engine: claude runs the configured subagent type (implementer.agent, default general-purpose) at the configured model (implementer.model alias, blank = inherit), cwd $WORKTREE — when implementer.workflow is false, one subagent via the Agent tool; when true, the Workflow tool fans those subagents out in parallel (each child on its own issue branch + worktree, its PR merged into the PRD integration branch $BRANCH); cursor / codex write the prompt to a .md file and run scripts/forge-implement.sh headlessly (never hand-build the CLI command — PLAYBOOK has the call) — when implementer.workflow is false, one CLI agent against $WORKTREE, and when true, the orchestrator fans out one background forge-implement.sh per child (each with its own per-child handoff in its own forge-worktree.sh worktree, its PR merged into $BRANCH by the same serial barrier). Either way the implementer runs TDD and works the child issues one-by-one in dependency order on the single $BRANCH: for each child it lands exactly one commit whose message carries Closes #<child>, then checks that child's box in the PRD task-list, backlinks the commit SHA + PR/MR URL on the child issue, and closes the child issue immediately (a Closes # ref only fires at merge, so close it by hand when the commit lands — the PRD parent stays open until merge). It runs the configured checks, opens ONE PR/MR (body Closes #<prd> + Closes #<each child>), and returns a strict receipt. (Under implementer.workflow: true each child instead rides its own issue branch + PR squash-merged into $BRANCH, and that ONE PR/MR is the $BRANCH → default gate; the per-child result is identical — one commit on $BRANCH, box checked, issue closed, commit backlinked. PLAYBOOK has the topology.) Record pr (and, for cursor, the session handle) into state.
- REVIEW — One reviewer per round, in its cheap PER-ROUND mode on
review.model. Each round dispatches a single read-only review subagent (Agent tool, model = review.model or omit when blank) that follows the vendored /spec-and-quality-review skill in PER-ROUND mode and returns, in one pass over the origin/<default>..$BRANCH diff, both verdicts plus a ⚠️ can't-verify verdict: spec compliance (Missing / Extra / Misunderstood + correctness + security) AND focused code quality (Parts 1–3). It self-derives the diff (forge never pastes one); you hand it the PRD + child acceptance criteria + the Global Constraints block verbatim as its lens. A requirement that lives in code the diff doesn't touch comes back as a ⚠️ can't-verify-from-diff item — you resolve it into a fix-task or a Phase 5 recap note, never a user question. The reviewer is read-only on the worktree (reports findings, never edits/commits/stages/git checkout on $BRANCH — a mutated tree corrupts the Phase 6 rebase); all fixes route through the implementer. The skill's deep maintainability audit (Part 4) is NOT run here — it runs once at the Phase 6 final gate in FINAL mode on the most-capable model. Post all findings as inline review comments (GitHub) or MR discussions (GitLab) per setup-yaah/scm-commands.md, capturing each comment/discussion ID.
- approved (combined reviewer clean — spec ✅ and quality Approved, no unresolved Critical/Important) → Phase 5.
- changes-requested (any Critical/Important, spec or quality) → re-run the configured implementer with the findings + comment IDs (claude: a fresh fix subagent; cursor:
cursor-agent --resume <session>; codex: codex exec resume --last — each keeps build context; PLAYBOOK has all three). It fixes on the same $WORKTREE/$BRANCH, replies on each comment thread, pushes; then re-run this phase, round += 1. Loop until the reviewer approves — no cap, no escalation.
- RECAP — Summarize: locked decisions + doc changes, issue link(s), PR/MR link(s), rounds taken, final verdict, checks run (flag any not green).
- MERGE — Present the gate ONLY if the reviewer approved AND all required checks +
smoke are green, confirmed by forge's own fresh re-run in $WORKTREE (Phase 5), not a subagent receipt (otherwise keep looping). Ask the user to approve merging $BRANCH to the default branch. On approval, sync-then-verify before merging (all autonomous — this is still one user gate): in $WORKTREE, git fetch origin <default-branch>; if it moved, rebase $BRANCH onto origin/<default-branch> (rebase, never a merge commit — keeps concurrent base-branch changes without discarding the PR/MR); always run graphify update . and commit any graph change (forge refreshes the graph on every merge — not gated on any flag; if the graphify binary is absent, note it and continue); git push --force-with-lease; then run the ONE heavy final review as verification — dispatch /spec-and-quality-review in FINAL mode on the most-capable review.final_model, read-only on the whole branch diff: that runs all four parts — the spec+correctness+quality sweep PLUS Part 4, the deep maintainability audit PER-ROUND mode skips (no cap — run normal fix rounds if it surfaces anything, re-running graphify after each code change). When the final reviewer is clean, merge the single PR/MR via the tracker CLI — its Closes #<prd> ref auto-closes the PRD parent (the child issues were already closed in Phase 3 as each commit landed; close any straggler by hand). After merge: cd to the main repo, git checkout <default-branch> && git pull, then bash <forge-skill-dir>/scripts/forge-worktree.sh remove "$WORKTREE". A rebase conflict you cannot resolve cleanly is a hard blocker — surface and stop. If declined, leave everything in place and stop.
Guardrails (the contract, restated)
- Invoke every sub-skill for real — never paraphrase or reimplement, the reviewer included.
- Config-driven, not hardcoded. Tracker CLI, checks, default branch, label, and
implementer.engine all come from .yaah/config.yml — never assume a stack, gh-vs-glab, or which implementer engine. (The tools.* efficiency flags are the deliberate exception — see the next bullet — forge does NOT gate on them.)
- Efficiency tools are always on, never config-gated. forge always uses graphify, rtk, and caveman regardless of
tools.*: it explores via graphify query/explain/path (not raw grep / whole-file reads), runs shell through rtk, and keeps its working/status output terse (caveman). Every subagent prompt — the claude Agent build/fix, the parallel-workflow build agents, and the cursor/codex CLI builds — explicitly carries those same instructions, so the CLI engines (which run outside the global rtk/caveman/graphify hooks) get the savings too. Code, commits, PR/MR bodies, and security notes stay in normal prose. If graphify's binary is genuinely missing at run time, note it and continue — never a hard fail.
- Same prompt, swappable engine — and never hand-build a CLI command. The build/fix prompts are identical across engines; only delivery changes (Agent tool vs a headless CLI) — and, under
implementer.workflow: true, whether forge runs one implementer or fans out several (claude: Workflow agents; cursor/codex: one background forge-implement.sh per child). For cursor/codex the ONLY supported invocation is writing the prompt to a .md file and running scripts/forge-implement.sh (it assembles argv safely, wraps the timeout, parses the receipt, prints a STATUS=ok|fail block). Hand-assembling the command inline is forbidden — that caused a real EXIT=127 word-splitting failure. Gate the round on the script's STATUS=ok; STATUS=fail/EXIT≠0 is a failed round (re-run, no cap), never silent success. Preflight the chosen CLI at Phase 0; a missing/unauthed CLI is a hard blocker — never silently fall back to claude.
- No user prompts between Phases 2–5. Surface only a true hard blocker, then stop.
- No round cap, but never blind retry. The per-round review loop ends only when the combined reviewer approves (and the Phase-6 final gate adds one heavy maintainability pass). A failed check is NOT a hard blocker — but the response is root-cause debugging (
/systematic-debugging: read the error, reproduce, trace the bad value to its source, one hypothesis, smallest fix), not a re-spawn of the same prompt. The re-spawn ledger carries the attempt count + the last failure summary into each retry; 3 failures on the SAME check escalate to a dedicated investigation subagent before any further fix.
- One reviewer skill, two depth modes — cheap per round, heavy once at the end — dispatched, read-only, never softened. A single vendored skill
/spec-and-quality-review covers everything. Phase 4 gates each round on its PER-ROUND mode (spec match + correctness + security + focused quality, Parts 1–3, both verdicts in one pass) dispatched on review.model; Phase 6 runs the same skill in FINAL mode once on review.final_model — adding Part 4, the deep maintainability audit. It is a vendored skill that ships with yaah — never depend on a harness-provided review command. Reviews are dispatched subagents (the diff never enters the orchestrator's context; each names its model — an omitted model silently inherits the most-expensive tier). Every reviewer is read-only on $BRANCH — it reports findings and must not edit/commit/stage/git checkout (a mutated tree corrupts the Phase 6 rebase); all fixes go through the implementer. The orchestrator NEVER tells a reviewer what to downgrade, skip, or pre-rate; findings cite file + line. A ⚠️ can't-verify-from-diff item becomes a fix-task or a recap note, never a user prompt.
- React to typed status; let the implementer push back; adjudicate via the reviewer. Implementer receipts carry a typed
status: (DONE / DONE_WITH_CONCERNS / BLOCKED / NEEDS_CONTEXT) plus a tdd: RED/GREEN certification. React to it specifically — address concerns, supply missing context, split a too-big child, escalate the model, stop only on a true architectural blocker — never one uniform re-spawn. In the fix loop the implementer may decline a wrong/breaking/YAGNI finding with technical reasoning (declined:); the orchestrator never downgrades a finding itself — it re-presents declined findings to the reviewer, who alone can withdraw one. That adjudication is what lets the no-cap loop terminate.
- Stay in
$WORKTREE. You cd in at Phase 0; address files relative to it or as $WORKTREE/…. NEVER write to the main checkout — that collides with parallel runs.
- One worktree + one branch + one PR per PRD. Every child issue is a single commit on that one branch (
Closes #<child>); fix rounds reuse the branch; NEVER branch again. There is exactly one merge gate, for the whole PRD. (implementer.workflow: true is the sole exception, on any engine: $BRANCH becomes a PRD integration branch and each child rides its own issue branch + own worktree + own internal PR that squash-merges into $BRANCH — claude fans out via the Workflow tool, cursor/codex via the orchestrator's background forge-implement.sh processes (it owns the per-child worktrees and the serial merge barrier). Those issue-PRs merge with no human gate; the single user gate is still the one $BRANCH → default PR.)
- Verify via evidence, not the receipt. Before Phase 5 recap and the Phase 6 gate, the orchestrator itself re-runs
checks (and smoke) fresh in $WORKTREE and reads real exit codes, and confirms the commits/PR/Closes refs via git log/git diff — a subagent's self-reported "pass" is never the merge evidence.
- Never merge before Phase 6, never offer merge with a red check or a failing
smoke, and remove the worktree only after a successful merge.
- Sync before merge by rebase, not merge commit. On approval, rebase
$BRANCH onto the latest default branch, refresh the graph (graphify update . — always; skip only if the binary is absent, noting it), force-push with --force-with-lease, and re-verify with one review pass; only then merge. An unresolvable rebase conflict is a hard blocker.
- Never claim done if a check was skipped. The configured
checks are the subagent's job via /tdd; report exactly what ran.
Rationalizations — STOP
A fully-autonomous, no-cap, two-touchpoint run has no human in the loop to catch a shortcut. Under pressure you will be tempted to rationalize one. Every excuse below is wrong; the reality is absolute.
| Excuse | Reality |
|---|
| "A check is red but the change is basically fine — ship it / let it reach the gate." | A red check NEVER reaches the merge gate. Debug it (/systematic-debugging), fix it, re-run. No cap. |
| "Re-run the same build, it'll probably pass this time." | Re-running an unchanged build is not a fix. Find the root cause first; carry the attempt ledger. |
| "This finding is cosmetic — approve it myself / tell the reviewer to drop it." | You don't set the verdict and you never soften a reviewer. The reviewer decides; declined findings are re-judged by the reviewer, not you. |
| "Reimplementing handoff/to-prd/the reviewer inline is faster than invoking it." | Paraphrasing ANY sub-skill violates the contract. Invoke the real Skill, always. |
| "The prompt is clear, I can skip grilling." / "The diff looks fine, skip review." | The per-round review and the grill are not optional. Every PRD runs the full chain, even a one-liner. |
| "Run the review inline / skip naming the model to keep it simple." | Reviews are dispatched subagents with a named model. Inline review bloats your context with the diff; an omitted model silently inherits the most-expensive tier. |
| "I'll just write the code instead of invoking /tdd." | No production code without an observed failing test first (verify-RED). Code written test-after is rewritten test-first. |
| "The CLI engine is flaky — fall back to claude." | The user chose the engine. A missing/unauthed CLI is a hard blocker, never a silent fallback. |
| "I'll hand-build the cursor/codex command just this once." | That caused a real EXIT=127 word-splitting failure. Write the prompt to a .md file and call forge-implement.sh. |
| "Just merge — rebasing is fiddly." | Rebase onto latest default, never a merge commit. An unresolvable conflict is a hard blocker, not a force. |
| "The subagent reported all checks green, so we're done." | Verify via evidence: the orchestrator re-runs checks + smoke and inspects the VCS diff itself. A self-report is never the evidence. |
| "Three fixes failed but one more might work." | 3+ failures on the same check = root-cause/architecture problem. Investigate or return BLOCKED — do not attempt fix #4 blindly. |
Red flags — the moment you think any of these, STOP and follow the contract: "just this once", "good enough", "I'll skip the script/skill", "close enough to green", "the user won't mind", "I'll note it and move on" (about a red check or an unresolved Critical).