# Forge

> Verification boundary CLI that delegates tasks to autonomous agents. Use when the user wants to run forge, execute specs, run specs in parallel, run pending specs, define specs from a description, resolve specs, audit code against specs, generate test protocols (proof), review changes, watch live logs, check run status, resume a session, or delegate complex multi-step work to an autonomous agent. Triggers include "forge run", "run this spec", "run specs in parallel", "run pending", "forge define", "define specs", "audit the codebase", "forge proof", "forge prove", "generate proof", "test protocol", "review changes", "forge watch", "forge status", "rerun failed", "resolve spec", "delegate this to forge", "hand off to forge", "hand this off", "dispatch to forge". Do NOT use for simple edits you can make directly, questions that don't require implementation, or straightforward work in the current repo that doesn't need autonomous agent execution.

- Skill: `vieko/forge` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add vieko/forge`
- Raw SKILL.md: https://api.skillmd.com/api/skills/vieko/forge/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: vieko (https://skillmd.com/u/vieko)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/vieko/forge

---


# Forge

Delegate complex, multi-step development work to an autonomous agent that builds and verifies code. Forge is driven entirely through its CLI.

## Hard rules

Read these first. They override patterns you've used for other tools.

1. **ALWAYS pass `--detach` when running a detachable SDK command from inside Claude Code.** The detachable SDK commands are `run`, `define`, `audit`, `proof`, `verify`, and `pipeline`. Without `--detach` the nested-session guard (`CLAUDECODE=1`) rejects them — the Agent SDK can't nest inside an active session. With `--detach`, forge auto-starts the executor daemon, runs the SDK in a separate process, and prints a task ID immediately.
2. **After dispatching, poll with `forge task <id> --wait`** (blocks until the task reaches a terminal state) or `forge task <id> --json` (one-shot status). Poll from the same repo you dispatched to (add `-C <repo>` if it's a different repo).
3. **NEVER spawn a new Claude Code instance (tmux pane, new terminal, subagent) to run forge.** `--detach` replaces tmux dispatch entirely. If the user wants to watch, point them at `forge tui` or `forge watch`.
4. **Pack warm context into the prompt.** The prompt string *is* the context — file paths, decisions, and constraints you've already discovered. Don't make the agent re-explore what you already know.
5. **Read-only queries and safe mutations run directly via Bash** (no `--detach`, no guard): `status`, `stats`, `specs`, `tasks`, `watch`, `worktree list/status`, `config`; and the mutations `specs --add/--resolve/--unresolve/--manualize/--archive`, `worktree mark-review/mark-merged`, `pipeline gate`, `pipeline control`.
6. **Three SDK commands have no detach path** -- `go`, `review`, and `specs --check`. Inside Claude Code the guard rejects them and there's no `--detach` bypass. Either present the exact command for the user to run in a separate terminal, or use a detachable equivalent: `pipeline`/`run` instead of `go`; review the diff yourself instead of `review`; `audit --detach` instead of `specs --check` for gap analysis.

## When to use forge

- The work is complex enough to benefit from autonomous agent execution with verification
- The task targets a different repo (`-C ~/other-project`)
- You have spec files describing outcomes to implement
- You want to run multiple specs in parallel

## The handoff pattern — most common use case

When the user says "hand this off to forge", "delegate to forge", "dispatch to forge", or similar:

1. **Pack your research into the prompt** — file paths, findings, decisions, constraints. Keep it tight; the agent does its own exploration.
2. **Dispatch with `--detach`** and capture the task ID. Use `forge pipeline --detach` for the full define → run → verify flow (the default for "hand off"); use a single SDK command (`forge run --detach`) when the user wants one specific stage.
3. **Block on completion** with `forge task <id> --wait`, or offer `forge watch` for live logs.
4. **Stay in this session.** Don't spawn a new Claude Code or tmux pane.

```bash
id=$(forge pipeline --detach -C /Users/me/project \
  "implement rate limiting for the API. Token-bucket; key files src/middleware/auth.ts \
   and src/routes/api.ts; Redis already configured in src/lib/redis.ts; must support \
   per-user and per-endpoint limits; 100 req/min default (team decision).")
forge task "$id" --wait -C /Users/me/project    # blocks until terminal state
# or, for live logs:
forge watch -C /Users/me/project
```

## SDK dispatch reference

Each detachable SDK command (`run`, `define`, `audit`, `proof`, `verify`, `pipeline`) accepts `-D, --detach` (queue the work, auto-start the executor, return a task ID) and `--json` (emit `{task_id, status, source}` instead of plain text). The plain-text form prints just the ID, so it captures cleanly: `id=$(forge run --detach "...")`.

| Intent | Command |
|---|---|
| Full pipeline (define → run → verify) | `forge pipeline --detach "goal"` — default for "hand off to forge" |
| One stage | `forge run\|define\|audit\|proof\|verify --detach "..."` |
| Block until a task finishes | `forge task <id> --wait` |
| One-shot task status | `forge task <id> --json` |
| Discover task IDs in a repo | `forge tasks [--active] [--json]` |
| Pipeline status | `forge pipeline status [id] [--json]` |
| Resolve a waiting gate | `forge pipeline gate <define\|run> [id] [--skip]` |
| Pause / cancel a pipeline | `forge pipeline control [id] --pause\|--cancel` |
| Resume a paused/failed pipeline | `forge pipeline --resume <id>` |

Task lookups are repo-scoped: poll with the same `-C <repo>` you dispatched to.

## Polling cadence

- **`forge task <id> --wait`** when you need the result before continuing (most handoffs). It blocks to a terminal state (`completed | failed | cancelled`); tune with `--interval <ms>` (default 1000) and `--timeout <ms>` (default: wait forever).
- **`forge task <id> --json`** one-shot when you want to check status without blocking.
- **`forge watch`** when the user wants live logs; it auto-follows batch runs and exits after the final session.
- **Unattended wall-clock timeout (#254)**: detached/executor runs (no TTY) fail-fast with `RUN_TIMEOUT` if a single agent invocation (or verify attempt) exceeds `config.runTimeout` (default 60 min) -- this catches a run stalled on auth/network instead of letting it idle for hours. Interactive foreground runs are unbounded. Override with `FORGE_RUN_TIMEOUT=<ms>` (set it for runs that legitimately need longer).
- While a pipeline runs it **owns the repo** — don't commit, push, or open PRs, and don't run individual stages it already ran. The verify stage opens a PR automatically when the pipeline completes.

## Anti-patterns — don't do these

- `forge run "implement feature"` from inside Claude Code without `--detach` — rejected by the nested guard.
- `tmux split-window -h 'forge run ...'` — dispatch with `--detach` and let the user observe via TUI/watch.
- `Agent(subagent_type=..., prompt="run forge ...")` — subagents can't run nested SDK either; dispatch with `--detach` from here.
- Dispatching with an empty or thin prompt — pack the warm context you already have.
- Manually parallelizing (`forge run a.md & forge run b.md & wait`) — use `--spec-dir`; forge owns dependency ordering, skip-passed, and concurrency.

## Operating model

Treat forge in two modes:

- **Authoring mode**: `define`, `proof`, and similar planning/spec-generation flows can operate against the current checkout.
- **Execution mode**: `run --isolate`, worktree-backed execution, and dependency-level consolidation should be treated as committed-state validation.

Rules that matter in practice:

- spawned isolate worktrees are created from git refs, not from uncommitted filesystem state
- if a worktree-backed run depends on a local forge/runtime fix, commit that fix first
- after changing forge runtime code, rebuild with `bun run build` so the executor picks up the fresh build before you trust results
- prefer mechanical verification over narrative agent judgment whenever possible

## Commands

### forge run

```bash
forge run --detach "add auth middleware"                  # Simple task (dispatch + task ID)
forge run --detach --spec specs/auth.md "implement this"  # With one spec file
forge run --detach --spec-dir ./specs/ "implement all"    # Parallel specs (default)
forge run --detach -C ~/other-repo "fix the login bug"    # Target a different repo
forge run --detach --rerun-failed "fix failures"          # Rerun failed specs
forge run --detach --pending "implement pending"          # Run only pending specs
forge run --detach --resume <session-id> "continue"       # Resume an interrupted session
forge run --detach --plan-only "design API for auth"      # Plan without implementing
forge --detach "quick task"                               # Shorthand (no 'run')
```

Key flags (`forge run --help` for the full list):

- `-s, --spec <path>` — one spec file (shorthand resolves via manifest). The prompt becomes additional context.
- `-S, --spec-dir <path>` — a directory of specs. Shared-worktree runs execute sequentially by default; add `-I, --isolate` for parallel worktree-per-spec. Already-passed specs are skipped.
- `-F, --force` — re-run all specs including already passed.
- `-B, --branch <name>` — run in an isolated git worktree on the named branch; auto-commits on success, cleans up after.
- `--in-place` — run directly in the current checkout, skipping worktree creation (incompatible with `--branch`/`--isolate`).
- `--concurrency <n>` / `--sequential` / `--sequential-first <n>` — tune parallelism.
- `--no-escalate` — disable graduated model/effort escalation on verify-fail retry (#297). By default a failed verification retries with a stronger config (effort first, then model — e.g. `sonnet@low -> sonnet@high -> opus@high`) up to 3 attempts. Pin the config across attempts for clean cost/quality measurement.
- `-t, --max-turns <n>` (default 250), `-b, --max-budget <usd>`, `--dry-run`, `-v/-q`.

### forge go

Smart shortcut for terminal use: auto-detects the stage from spec state (define if no specs, run if pending, etc.). **Not detachable** -- the nested guard rejects it inside Claude Code, so dispatch `forge pipeline --detach` or `forge run --detach` directly instead, or have the user run `go` in a separate terminal.

```bash
forge go "build auth system"                     # Separate terminal only (not inside Claude Code)
```

### forge define

Analyzes the codebase and generates outcome spec files from a high-level description. Closes the loop: `define` → `specs` → `run --spec-dir "implement"`.

```bash
forge define --detach "build auth system"            # Generate specs in specs/
forge define --detach "add rate limiting" -o specs/api/
forge define --detach "refactor database" -C ~/project
```

### forge audit

Reviews the codebase against specs. Produces new spec files for remaining work — feed them back into `forge run --spec-dir`.

```bash
forge audit --detach specs/                      # Audit all specs in a directory
forge audit --detach specs/auth.md               # Audit a single spec
forge audit --detach specs/ "focus on auth"      # With additional context
forge audit --detach specs/ --fix                # Audit-fix loop (audit -> fix -> re-audit)
forge audit --detach specs/ --fix --fix-rounds 5 # Custom max rounds (default: 3)
```

### forge proof

Generates real test files from implemented specs: `.test.ts` files colocated with source, a `manual.md` checklist, and a `manifest.json`. Auto-detects test framework. `forge prove` is a backward-compatible alias.

```bash
forge proof --detach specs/feature.md            # Single spec
forge proof --detach specs/                      # All specs in a directory
forge proof --detach specs/a.md specs/b.md       # Multiple specific specs
forge proof --detach specs/ -o ./custom-proofs/
```

### forge verify

Executes generated proof tests and prepares a PR/manifests around the verification run.

```bash
forge verify --detach proofs/
forge verify --detach proofs/ -C ~/other-repo
```

### forge review

Reviews recent git changes for bugs and quality issues. **Not detachable** -- inside Claude Code, present it for the user to run in a separate terminal (or review the diff yourself).

```bash
forge review                                     # Review main...HEAD
forge review HEAD~5...HEAD                        # Specific range
forge review --dry-run -o findings.md             # Report only, write to file
```

### forge pipeline

Chains define → run → verify into one automated flow with observable gates. The pipeline process stays alive and polls for gate changes — the TUI and `pipeline gate`/`pipeline control` approve gates by writing state, not by spawning processes.

```bash
forge pipeline --detach "build auth system"            # Full pipeline
forge pipeline --detach --from run --spec-dir specs/ "go"  # Start at run with existing specs
forge pipeline --detach --gate-all confirm "careful build" # Pause at every gate
forge pipeline status [id] [--json]                    # Show pipeline state
forge pipeline gate <define|run> [id] [--skip]         # Approve (or --skip) a waiting gate
forge pipeline control [id] --pause|--cancel           # Pause or cancel
forge pipeline --resume <pipeline-id>                  # Resume a paused/failed pipeline
```

Gates default to: auto (define→run), confirm (run→verify). TUI controls: `a` advance, `s` skip, `p` pause, `c` cancel. `pipeline gate`/`pipeline control`/`pipeline status` are read/mutation commands — run them directly (no `--detach`).

### Read-only inspection

```bash
forge status [--all] [-n 5] [-C ~/repo]          # Run results (latest / N / all)
forge stats [--by-spec|--by-model|--by-source]   # Aggregate cost + success rate
forge stats --since 2026-03-01
forge tasks [--active] [--json] [-C ~/repo]       # Queued/running tasks across CLI/TUI
forge task <id> [--wait] [--json] [-C ~/repo]     # A single task (poll/block)
forge config [-C ~/repo]                          # Effective config with source tracking
forge watch [<session-id>] [-C ~/repo]            # Live-tail session logs
forge tui                                         # Interactive dashboard
```

### Spec lifecycle

```bash
forge specs [--pending|--failed|--passed]        # List tracked specs (filtered)
forge specs [--orphaned|--untracked|--summary]   # Diagnostics / roll-up
forge specs --add [specs/new.md]                 # Register untracked spec(s)
forge specs --resolve game.md                    # Mark passed without running
forge specs --unresolve game.md                  # Reset to pending, clear run history
forge specs --manualize game.md                  # Toggle manual follow-up (excluded from batch)
forge specs --archive game.md                    # Toggle archived (excluded from batch)
forge specs --reconcile                          # Backfill state from results history
forge specs --prune                              # Archive orphaned entries (file missing)
forge specs --prune-pending                      # Dry-run: list phantom pending rows (scanner noise)
forge specs --prune-pending --apply              # Delete them (no run history, outside spec dirs)
forge specs --check                              # SDK (not detachable): triage pending specs, auto-resolve implemented ones
```

`forge specs --check` is an SDK command with no detach path (it runs a Sonnet agent) -- inside Claude Code, present it for the user to run in a separate terminal, or use `forge audit --detach` for a detachable gap analysis. Lifecycle recovery rules of thumb: `--add` when the spec exists and should be tracked; `--reconcile` when there's run history to backfill; `--manualize` when the remaining work is operator/manual; `--archive` when the spec is intentionally no longer active backlog; `--prune-pending` when `forge specs` shows phantom pending rows that were never real specs (scanner-ingested files with no run history, outside spec dirs -- dry-run first, then `--apply`); leave a spec `pending` without strong evidence to resolve otherwise. SQLite is the source of truth; `.forge/specs.json` is a regenerated export — never edit it by hand.

### Worktree + consolidation

```bash
forge worktree list [--status awaiting_review]
forge worktree status <id>
forge worktree mark-review <id>                  # Ready for review
forge worktree mark-merged <id>                  # After the PR lands
forge worktree prune [--dry-run]
forge worktree repair                            # Defaults to dry-run; --fix to apply
forge consolidate [--work-group <id>]            # Merge one awaiting-review group, open a PR
forge consolidate --all-ready                    # One consolidation per awaiting-review group
forge consolidate --dry-run                      # Preview the merge plan
```

Typical flow: `mark-review <id>` when implementation is ready → for a single awaiting-review worktree, review and PR the `forge/*` branch directly → `consolidate --work-group <id>` only when a group has multiple awaiting-review worktrees needing one combined review branch → `mark-merged <id>` after that PR lands. Consolidation opens PRs to `main`; it never merges into local `main` directly.

### forge executor

Starts the task executor daemon (drains the local queue: CLI `--detach`, TUI). `--detach` auto-starts it, so you rarely run this by hand — use it when tasks are queued but nothing is picking them up.

```bash
forge executor
```

## Important

**Never manually orchestrate parallel forge runs** (e.g. `forge run a.md & forge run b.md & wait`). Forge handles parallelism, dependency ordering, and skip-passed internally via `--spec-dir`. Manual orchestration bypasses the dependency graph, manifest tracking, and batch grouping.

**Always prefer `--spec-dir`** over running individual specs. It skips already-passed specs (use `--force` to override), resolves `depends:` frontmatter into a topological order, tracks the batch with grouped cost reporting, and auto-tunes concurrency.

**For `--isolate`, commit first.** Isolate worktrees only see committed branch state. If the run depends on local forge/runtime changes, commit them, rebuild, and let the executor pick up the fresh build.

**`--spec` takes exactly one file.** The prompt is always the last positional argument (a quoted string). Bare file paths without a flag are interpreted as the prompt, not as spec files. To run multiple specs, use `--spec-dir`.

**Shorthand resolution**: spec paths resolve automatically. `forge run --spec login.md` finds the spec via manifest lookup; `forge run --spec-dir proj-580` finds `.bonfire/specs/proj-580/`. Full paths always work too.

**Pipeline is autonomous end-to-end.** When you dispatch `forge pipeline --detach`, wait for it via `forge task <id> --wait`. Don't run individual stages afterward (it already ran them), and don't commit/push/PR while it runs — verify opens the PR on completion.

## Common mistakes

```bash
# WRONG: SDK command inside Claude Code without --detach (nested guard rejects)
forge run --spec-dir specs/ "implement all"
forge go "build auth"
forge define "add feature"

# WRONG: dispatching to a tmux pane
tmux send-keys -t 2.2 'forge run ...' Enter

# RIGHT: dispatch with --detach, then poll
id=$(forge run --detach --spec-dir specs/ "implement all")
forge task "$id" --wait

# WRONG: bare paths without --spec are treated as the prompt string
forge run --detach specs/auth.md specs/login.md

# WRONG: --spec only takes one file
forge run --detach --spec specs/auth.md specs/login.md "implement"

# WRONG: manually running specs one-by-one bypasses dependency ordering
forge run --detach --spec 01-schema.md "go" && forge run --detach --spec 02-api.md "go"

# RIGHT: a directory of specs via --spec-dir
forge run --detach --spec-dir specs/ "implement all"

# RIGHT: a single spec via --spec
forge run --detach --spec specs/auth.md "implement this"
```

## Recipes

### Spec-driven development

```bash
# 1. Write specs as .md files (see references/writing-specs.md)
# 2. Run them in parallel and block on completion
id=$(forge run --detach --spec-dir ./specs/ "implement all specs")
forge task "$id" --wait
# 3. Rerun any failures
forge run --detach --rerun-failed "fix failures"
# 4. Check results
forge status
```

### Triage then run pending

```bash
forge specs --pending                                  # See what's pending
forge specs --check                                    # Separate terminal: auto-resolve implemented specs
id=$(forge run --detach --pending "implement remaining")
forge task "$id" --wait
```

### Audit-then-fix loop

```bash
# Manual: audit, then run remediation specs
id=$(forge audit --detach specs/ -C ~/project); forge task "$id" --wait -C ~/project
forge run --detach --spec-dir specs/audit/ -C ~/project "fix remaining"
# Automated: convergence loop (audit -> fix -> re-audit, default 3 rounds)
forge audit --detach specs/ --fix -C ~/project
```

## Deep-dive references

| Reference | Load when |
|-----------|-----------|
| [writing-specs.md](references/writing-specs.md) | Writing spec files for forge to execute |
| [parallel-execution.md](references/parallel-execution.md) | Tuning concurrency, understanding cost, monitoring parallel runs |

