# Forge

> Build a new Claude Code plugin eval-first — interview, design contract, frozen eval suite, headless goal-loop build, verified ship. Use for "build me a plugin", "plugin for X", "forge a plugin", "resume forge", "forge status". Single entry point for the plugin-forge pipeline; resumable across sessions via .forge/state.json in the target project.

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

---


# forge — pipeline conductor

Drive the eval-first plugin pipeline: `interview → contract → evals → armed → building → smoke → verify → ship`. Nothing is scaffolded until a design contract exists and a frozen eval suite defines what "done" means; the build is finished when the suite goes green, not when files exist. All durable state lives in files inside the target project, so the pipeline resumes across sessions with zero memory. Run forge from the root of the project where the plugin will be created.

## Current state

Pipeline state, injected at invocation:

!`cat .forge/state.json 2>/dev/null || echo NO_STATE`

If the line above reads `[shell command execution disabled by policy]` (org setting `disableSkillShellExecution`), recover manually: run `cat .forge/state.json` with Bash and treat a missing file as `NO_STATE`.

`.forge/state.json` shape:

```json
{"phase":"interview|contract|evals|armed|building|smoke|verify|ship",
 "plugin_name":"…","plugin_dir":"./…","contract_sha256":"…","updated":"ISO8601"}
```

If the file exists but is not valid JSON, do not guess a phase: recommend `forge-eval doctor` (clears stuck state and leaked worktrees, resets to the newest phase whose artifacts exist) and stop.

## Arguments

`$ARGUMENTS` is one of:

- **a plugin idea** (free text) — start the pipeline with that idea, or continue an existing run and treat the text as added context.
- **`resume`** — route to the next incomplete step using the routing table below.
- **`status`** — report only: state.json fields; which artifacts exist (`design/INTENT.md`, `design/CONTRACT.md`, `.forge/critic-report.md`, `.forge/freeze.json` — use `cat .forge/*` and Read); the latest `FORGE_EVAL:` scoreboard line from `runs/` if any; and the routed next action. Perform no phase work, then stop.

## Routing table

Route on the injected state. Where a row says "invoke", use the Skill tool with the named skill.

| State | Meaning | Next action |
|-------|---------|-------------|
| `NO_STATE` | pipeline never started | Read [references/interview.md](references/interview.md); run `mkdir -p .forge` and `mkdir -p design`; conduct the phase-0 interview; write `design/INTENT.md`; initialize state |
| `interview` | interview started, INTENT.md incomplete | Resume the interview per [references/interview.md](references/interview.md) |
| `contract` | INTENT.md done; PDR not yet approved | Invoke `plugin-forge:write-contract` |
| `evals` — no suite yet | contract approved; `<plugin_dir>/evals/registry.yaml` absent | Invoke `plugin-forge:build-evals` |
| `evals` — suite drafted | suite exists; `.forge/freeze.json` absent | Invoke `plugin-forge:arm-evals` |
| `armed` | suite frozen; build not started | Invoke `plugin-forge:build-loop` |
| `building` | goal loop running or interrupted | Invoke `plugin-forge:build-loop` — it resumes or monitors the loop and advances phase to `smoke` when the transcript shows the `FORGE_EVAL:` line with `RESULT=PASS` |
| `smoke` | build green; cheap probes pending | Invoke `plugin-forge:verify` |
| `verify` | smoke ALL_PASS; pass^k / holdout pending | Invoke `plugin-forge:verify` — it resumes at the expensive tranche |
| `ship` | verify report exists | RECOMMEND the user run `/plugin-forge:ship`. Never invoke ship via the Skill tool |

To distinguish the two `evals` rows: `cat .forge/freeze.json` (absent → not yet armed) and check whether `<plugin_dir>/evals/registry.yaml` exists (absent → suite not generated).

Gate details — required artifacts, approvals, and regression rules per transition — live in [references/phase-gates.md](references/phase-gates.md). Consult it before declaring any phase complete or when state and artifacts appear to disagree.

## Delegation rules

- Delegate phase work by invoking the phase skill through the Skill tool: `plugin-forge:write-contract`, `plugin-forge:build-evals`, `plugin-forge:arm-evals`, `plugin-forge:build-loop`, `plugin-forge:verify`. Do not inline a phase's work in the conductor turn — each phase skill carries its own references, effort settings, and tool grants.
- Phase skills are default-invocable and self-guard: each opens by reading `.forge/state.json` through a dynamic-injection header and refuses out-of-order execution, printing the remediation command (`/plugin-forge:forge resume`). Trust the guards — invoking a phase skill at the wrong phase is safe; it bounces.
- `build-evals` also runs standalone in `retrofit <path>` and `mine` modes for existing plugins; those flows do not pass through forge.
- `ship` is user-gated. When phase is `ship`, print exactly what the user should run — `/plugin-forge:ship` — with a one-line summary (validates with `claude plugin validate --strict`, generates docs and the permission story, chooses distribution). Never invoke it.

> **Why invocation control is split this way (the plugin's own worked example — decision D2 in forge's PDR).** `disable-model-invocation: true` blocks Skill-tool invocation, not just auto-triggering — a conductor cannot programmatically chain skills that carry it. So only the two user-gated entry points, `forge` and `ship`, carry `disable-model-invocation: true`; the five phase skills use default invocation and carry their safety in the state machine instead: each self-guards by reading `.forge/state.json` in its dynamic-injection header and refusing out-of-order runs. Enforcement moved from the invocation layer (which would break chaining) to the state layer (which cannot be skipped). Apply the same reasoning to every generated plugin: choose invocation control per skill from *who must be able to call it*, then enforce ordering with mechanism, not prose.

## State discipline

- Forge writes `.forge/state.json` in exactly two situations: initialization (`NO_STATE` → `interview`) and interview completion (`interview` → `contract`). Every later transition is written by the phase skill that owns it (ownership column in phase-gates.md). Never hand-edit state to skip a gate.
- Never advance past `contract` without `APPROVED` in `.forge/critic-report.md`; never past `evals` without all four arming gates and `.forge/freeze.json`. If the user asks to skip a gate, explain what the gate prevents and offer the documented escape hatch: sketch mode — prototype without forge first, then forge the real plugin.
- Before routing at phase `evals` or later, verify `sha256(design/CONTRACT.md)` still matches `state.contract_sha256`. On mismatch the pipeline regresses to `contract` — apply regression rule R1 in phase-gates.md.
- `allowed-tools` grants are per-turn: the Bash grants in this skill's frontmatter clear on the user's next message. Long multi-turn phases rely on the phase skills' own grants, and ship emits durable `permissions.allow` suggestions for the generated plugin rather than leaning on per-turn grants.
- Cost honesty: this pipeline is priced in trials × tasks × judges × build iterations. State the expected cost before launching the build loop, pass `--max-cost-usd` to `forge-eval` for unattended runs, and use `--dry-run` to slice before committing to a full run.

## References

- [references/interview.md](references/interview.md) — the phase-0 interview protocol (runtime environment first, live-vs-mock per external system, deliverables, side-effect/consent inventory, success criteria in goal-condition grammar) and the INTENT.md template. Load when state is `NO_STATE` or `interview`.
- [references/phase-gates.md](references/phase-gates.md) — the full transition table (owner, required artifacts, gate per transition), the refusal protocol, and the regression rules (contract sha mismatch; post-freeze eval edits). Load before declaring any transition, and whenever a phase skill's refusal looks wrong.

