<!-- source: openspec/current/forge/narrative.md -->

---
title: Forge — Narrative
status: stable
owner: pavel
audience: [pavel, ai, engineer]
tldr: Positioning context for Forge — why it exists, status, where it lives, distribution, and related-capability cross-references.
---
# Forge — narrative

> Part of openspec/current/forge/ — split from forge.md on 2026-05-12

---

## Why Forge exists

Forge is a project-agnostic CLI engine for Linear-driven autonomous code pipelines. **Thirteen commands shipped:** legacy six (`audit`, `spec`, `review`, `estimate`, `render`, `mirror-export`); Builder-mode four (`inbox`, `inspect`, `plan`, `build`); plus `epic` (RAP-392 epic conductor), `status`, and `cancel` (cross-process sentinel). `tail` and `resume` are RAP-405/RAP-406 deferred. Wraps Anthropic Messages API + Anthropic Agent SDK + Linear + Supabase + Mirror render pipeline.

---

## Status

**Builder mode shipped end-to-end** as of [RAP-48](https://linear.app/rapoport-studio-slr/issue/RAP-48) close 2026-05-09T00:01:24Z. Waves 1-3 merged 2026-05-04 → 2026-05-05 via PRs #161 / #166 / #186; Wave 4 phases A/B/D shipped under `sync-forge-builder-spec` (PR #414 first real-issue dogfood, RAP-167); `status` and `cancel` shipped under the same arc. Thirteen commands available today (see `commands.md § Command surface`): the legacy six (`audit`, `spec`, `review`, `estimate`, `render`, `mirror-export`), Builder-mode four (`inbox`, `inspect`, `plan`, `build`), plus `epic` (RAP-392 D2 epic conductor), `status`, and `cancel`. The canonical command list is the `cli.ts:31-46` whitelist plus the `§ Command surface` table.

Remaining open work after this stabilization arc lives in `verifier.md § Known gaps` (one item — orchestrated review unimplemented). All other previously-listed blockers have been closed and the crossed-out entries are removed from § Known gaps as of this sync.

---

## Where Forge lives

- Source: `packages/forge/`
- Package name: `@rapoport-studio/forge`
- Version: `0.0.1` (publish-ready as of RAP-118 — see § Distribution)
- Entry point (CLI): `bin: { forge: "./bin/forge.mjs" }`; bootstrap at `bin/forge.mjs` registers the `tsx` ESM loader (so `@rapoport-studio/muse/mirror`'s raw-`.ts` exports resolve under Node) before importing the compiled `dist/cli.js`. Source CLI at `src/cli.ts`. Workspace alias: `pnpm forge <args>` from the repo root, defined in the root `package.json`.
- Library entry: `./dist/index.js` (`src/index.ts`)
- Sub-exports: `./core` (`src/core/index.ts`) and `./worker-prompts` (`src/worker-prompts.ts`)
- Build: TS → ESM via `tsc`, prompts copied via `scripts/copy-prompts.mjs`. Output: `dist/`.
- Source size: ~9,579 LOC across ~80 source files (incl. tests + prompt markdown)

---

## Distribution

Forge ships as an npm package on **GitHub Packages** under the `rapoport-studio` org, scoped to `@rapoport-studio/forge`. External engagements (Unbind first, Vivod and Dentour next) install via `pnpm add @rapoport-studio/forge` after wiring `@rapoport-studio:registry=https://npm.pkg.github.com` in their own `.npmrc`.

The decision to use GitHub Packages over npm public is recorded as `Q-FORGE-3` (Closed) in `unbind.life/openspec/_methodology/adoption.md § 6 Forge workflow` — rationale: org-scoped privacy, no extra hosting infra, Infisical already in place for consumer-side `GITHUB_BOT_TOKEN` auth.

`@rapoport-studio/muse` is published alongside forge (option **(a)** of the muse-resolution choice originally listed as a follow-up). Forge depends on muse via `workspace:*`; `pnpm publish` substitutes the local muse version (`0.0.1`) at pack time, so muse must already be on the registry at that exact version when forge resolves on a consumer. The publish workflow enforces order **muse → forge** in a single job.

### Publish workflow

`.github/workflows/publish-forge.yml` — manual `workflow_dispatch` trigger. Steps:

1. Pavel bumps `packages/forge/package.json § version` **and** `packages/muse/package.json § version` in lockstep (manual semver) on a `chore/bump-forge-vX.Y.Z` branch and merges to `main`.
2. From the GitHub Actions UI, run **Publish @rapoport-studio/forge** on `main`. Optional `dry_run=true` packs and inspects the tarballs without publishing.
3. Workflow checks out, builds in topological order (`pnpm --filter "@rapoport-studio/forge..." build` builds muse first, then forge), packs both, then publishes muse first and forge second via `pnpm publish --no-git-checks`. Auth via auto-provided `GITHUB_TOKEN` (workflow declares `permissions: { contents: read, packages: write }`).
4. New versions visible at `https://github.com/rapoport-studio/rapoport.studio/pkgs/npm/forge` and `.../pkgs/npm/muse`.

Tag-based / changesets automation is deferred — `workflow_dispatch` only for v1 until ≥3 publish runs of operational experience.

### Consumer install

External consumer (e.g. `unbind.life`) needs:

```ini
# <repo-root>/.npmrc
@rapoport-studio:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_BOT_TOKEN}
```

Local dev: developer's personal GitHub PAT (with `read:packages`) in `~/.npmrc`. CI: `GITHUB_BOT_TOKEN` from Infisical (per `D-SEC-2` on the consumer side).

### Known follow-ups

- **Tag-based automation.** Replace `workflow_dispatch` with a tag-triggered workflow (`forge-vX.Y.Z`) once first 2-3 manual publishes confirm the pipeline shape.
- **Changesets / semver discipline.** Once forge has ≥2 external consumers, adopt `@changesets/cli` to coordinate version bumps + changelogs across muse + forge.
- **Trim test artefacts from tarballs.** Both tarballs ship `dist/__tests__/` because muse and forge tsconfigs emit tests under `outDir`. Either exclude `__tests__/` from `tsc` outputs or add an `npm-pack-ignore`-style filter.

---

## Related capabilities

- `platform.md` — overall context. Note: Forge is a tool that operates on the platform; it doesn't ship as part of any user-facing surface.
- `muse.md § Architect mode (v1)` — Muse's first activated mode is live as spec source-of-truth in `apps/studio`.
- `muse.md § Builder mode (v1.2)` — Builder mode shipped in this package via RAP-48 Waves 1–3 (PRs #161 / #166 / #186, 2026-05-04 → 2026-05-05). The system-prompt template lives in `packages/muse/src/builder-prompt.ts` and is consumed by `forge build` per the preset-append spike in `openspec/archive/2026-05-05-add-forge-builder-mode/spikes/2026-05-05-claude-agent-sdk.md`. `status` and `cancel` are tracked under `openspec/archive/2026-05-09-sync-forge-builder-spec/`.

---

## Builder mode shipped (applied 2026-05-09 from change `sync-forge-builder-spec`)

Closes the synchronization arc: Builder mode (Waves 1–3 + Wave 4 Phases A/B/D) is shipped end-to-end as of [RAP-48](https://linear.app/rapoport-studio-slr/issue/RAP-48) close (2026-05-09T00:01:24Z); first real-issue dogfood landed via [RAP-167](https://linear.app/rapoport-studio-slr/issue/RAP-167) — PR [#414](https://github.com/rapoport-studio/rapoport.studio/pull/414) merged 2026-05-09T02:56:41Z. Spec edits described above in §§ Status, Command surface, Builder mode, Known gaps, Open questions, Related capabilities — this marker is pure metadata, no duplicate factual content (per `archive/2026-05-09-sync-forge-builder-spec/design.md § D5`).

## Maestro cross-references (applied 2026-05-09 from change `amend-muse-forge-for-maestro`)

Maestro (the orchestra coordinator — see [`agents/maestro.md`](agents/maestro.md)) routes engineering work to Forge via sync request: *"build this Linear issue"*, *"estimate this"*, *"audit this drift"*. Forge remains a leaf execution node in the orchestra communication graph (per `agents-overview.md § Communication graph`); Maestro never bypasses Forge to write code, open PRs, or comment on Linear issues directly. The bilateral edge is **Maestro → Forge sync request** in the work-routing direction; the inverse direction is **Forge → Maestro async event** (journal write).

Forge writes journal events that Maestro observes. Once Layer 2 (`add-knowledge-layout`) provisions the `orchestra_journal` Supabase table, the events are append-only entries Maestro reads via the query helper documented in [`agents/maestro.md § Access scope`](agents/maestro.md). Until that table exists, Forge's per-run state at `~/.forge/state/<RAP-NN>.json` and lessons-learned at `~/.forge/lessons-learned.md` (see `entities.md § Lessons-learned mechanism`) are the de-facto event surface — those files predate the orchestra journal and are not retroactively migrated.

Forge invokes Muse Builder mode programmatically through the existing `forge build` → `packages/muse/src/builder-prompt.ts` relationship (see `entities.md § Builder prompt`). That edge is unchanged by this amendment. The Muse mode roster now includes Maestro alongside Architect / Builder / Scout / Canvas (see [`muse.md § Maestro added as fifth mode`](muse.md)); Forge is **not** a Muse mode and is invoked through its own CLI / programmatic surface, never through `runMuseWithTools`. The Muse ↔ Forge edge is operational; the Maestro ↔ Forge edge described above is the contract that activates when Maestro mode runtime ships.

Echo cross-reference (also tasked by the original Phase A forward-references) is deferred until Echo's spec ships in Phase B (separate change). Cross-reference: canonical Maestro capability spec at [`agents/maestro.md`](agents/maestro.md) (landed via [RAP-150](https://linear.app/rapoport-studio-slr/issue/RAP-150) / PR #428). This amendment closes the Maestro half of the forward-reference in [`agents-overview.md § Forward references — per-agent specs`](agents-overview.md).
