Forgebeta

The CLI

The forge executable handles local file mechanics and artifact previews. It never selects a phase, approves meaning, or judges a candidate.

There are two forges and it's worth keeping them straight. Forge with a capital F is the skill you invoke in agent chat, and it's the thing that selects phases and exercises professional judgment. The lowercase forge executable runs in a shell and does deterministic bookkeeping.

Its own help says so:

Usage: forge [options] [command]

Local file mechanics and artifact previews. Invoke the Forge agent skill for
semantic Explore/Spec/Plan/Build/Review/Acceptance/Ship.

So there's no forge plan and no forge build. A shell command never selects a phase, grants authority, approves meaning, or advances delivery, and CLI success establishes only the mechanical claim that operation names.

You need the executable to initialize a managed loop and to create or validate its documents. Protected decision recording, Spec application, prepared memory changes, and knowledge operations also go through it, and direct shell writes are not a substitute for any of them.

Getting it

The installer writes it to ~/.local/bin/forge, so if you've installed Forge you already have it.

The compiled executable embeds its document templates and runtime, so running it doesn't need Bun, Python, or a source checkout. It needs Git for the GitHub fetch inside setup and for candidate; setup --pack needs neither. Locking uses POSIX file facilities.

Treat --help from your installed version as authoritative over this page.

Commands

serve      Serve an artifact directory on localhost until interrupted
setup      Install Forge skills into this repository from GitHub or --pack
init       Initialize a loop; this is not approval
docs       Scaffold and validate identified documents
decision   Record an authorized human decision in the canonical bundle
candidate  Fingerprint current candidate including dirty files
memory     Validate or apply prepared canonical files
kb         Query or maintain canonical local knowledge

serve

forge serve <directory> [--port <number>] [--json]

Runs a foreground static server bound to 127.0.0.1. --port defaults to 0, which picks an available port; an explicit occupied port fails rather than silently moving. --json prints one readiness record with root, url, port, and pid after the socket binds. Read the printed URL instead of guessing.

The directory is explicit and relative to your working directory, and it doesn't use --repo or need a Git checkout. The selected directory is the entire served scope: its index.html opens at the root URL, nested directories serve their own index and redirect to a trailing slash so relative assets resolve, and files are read fresh on reload with caching disabled. HTML, CSS, JavaScript, images, PDFs, and Markdown keep their file MIME types, so Markdown is served as a file rather than converted to HTML.

Missing files and directories without an index return 404. There's no directory listing and no SPA fallback, and dotfiles and symlinks under the root aren't served. No daemon, server registry, transpilation, Vite installation, or browser launch is involved, and no live-reload script gets injected. Use your project's existing build pipeline for framework source, then serve the output.

Ctrl+C or SIGTERM closes the server and releases the port. Readiness proves a bound local server and nothing about what's rendered in it.

setup

forge setup [--repo <path>] [--tools <list>] [--pack <path>]

Installs the skill pack into a project. By default it fetches the latest default branch of github.com/brightstack/forge into a temp directory, copies the pack out, and deletes the temp tree, so an unreachable GitHub fails with a clear error rather than a half-install. --pack points at a local package root instead and skips the network entirely.

--tools defaults to agents, which is Cursor and Codex. The other two are claude and cursor, and a comma-separated list installs into several hosts at once. An unknown tool name fails. Setup writes only Forge-owned names and merges into them, so your other skills survive it.

Skills live on GitHub or in --pack, never inside the binary, which is why setup exists as a separate step from installing the executable. Run it from the project directory rather than from ~/.local/bin.

init

forge init <loop_id> --repo <path> --title <title>

Creates .forge/loops/<loop-id>/ with four active records — index.md, decisions.md, log.md and build/log.md — so they can carry current state. --repo defaults to ..

Active status means the record is in use. It doesn't accept Spec meaning, prove a candidate, or authorize a phase, which is why the help text says so out loud.

docs

forge docs create <kind> <path> --repo <repo> --title <title> [--code <code>] [--body-file <file>]
forge docs update <path> --repo <repo> [--body-file <file>] [--set <key>=<json-or-string>]
forge docs validate [paths...] --repo <repo>
forge docs append <path> --repo <repo> --heading <heading> --body-file <file>

<kind> is a fixed list, not free text: issue, bug, spec-change, standing-spec, plan, build-log, product, design, visual, tech, work, acceptance, review, ship, concept, process, interface, index, log, decisions, kb-decision, kb-index, kb-log. Anything else is rejected outright.

Creation assigns id (a UUID), a readable code, an immutable type, plus title, status, createdAt, and updatedAt. Codes use letters and numbers separated by -, _, or .. Creation and identity fields stay fixed; --set handles other metadata.

The usual rhythm is scaffold, edit the ordinary Markdown body with your normal file tools or agent, then validate. --body-file takes body-only Markdown, frontmatter is preserved through ordinary body edits, a missing top-level heading is supplied from --title on creation, an existing heading is kept, and empty bodies are rejected. Updates still need a descriptive heading.

docs validate with no paths checks the corpus listed in .forge/identities.json, minus docs/knowledge/, which belongs to kb verify and is rejected if you name it explicitly. Pass paths to check a specific draft.

The frontmatter reader is deliberately scoped rather than a general YAML implementation. Unknown nested or block metadata is retained verbatim during body edits, and it isn't interpreted as authority or schema.

decision

forge decision record [loop_decisions_path] --repo <repo> \
  --authorization-file <file> --body-file <file> \
  [--title <title>] [--supersedes <Dn-or-legacy-id>]

Records an authorized human decision in the canonical decisions bundle, assigns the next readable code (D1, D2, and so on), updates the numeric decisions index, and retains a memory receipt. Supply the loop decisions path to also record the canonical reference there, or omit it for standalone recording. --supersedes creates a new record and preserves the prior one.

The authorization file is JSON with actor: "human", a local transcript path or URL in source, an actual quote, a bounded scope, and an ISO date. When source is a local path, the operation checks that the quote is really in it; when it's a URL the quote is embedded unchecked. Either way it does not authenticate the human. Generic document updates can't create or overwrite decision authority.

candidate

forge candidate --repo <repo> [--path <path>...] [--expect <identity>]

Fingerprints the current candidate, including dirty files: tracked, untracked, deleted, mode, and symlink state for the selected paths. .forge loop mechanics are excluded by default, so writing a verdict doesn't invalidate the candidate it's about. Gitignored content is excluded too, because the walk is git ls-files --cached --others --exclude-standard; name such a path with --path to pull it back in. Include changed accepted Spec or decision paths explicitly with repeated --path, or pin their exact accepted revision separately in the packet.

memory

forge memory verify <manifest> --repo <repo>
forge memory apply <manifest> --repo <repo>

Validates or applies prepared canonical files. Canonical docs/specs and docs/knowledge are protected from generic document writes, so the flow is to prepare drafts under a loop or another ordinary path, pin the proposed hashes and the independently retained authority inputs, then verify and apply after approval.

Forge spec apply <change> in chat uses exactly these two commands with an application: spec manifest. There's no executable Spec apply or merge alias. Generic memory jobs omit that discriminator and stay compatible.

Spec normally records approved meaning as a proposal. An explicit Spec apply installs it when requested; Forge finish can invoke the same guarded operation at actual work completion. Finish is an agent operation, not a CLI command or a sixth phase.

A document-only receipt establishes the checked mutation. It doesn't establish implementation, Review, Acceptance, or Ship.

kb

forge kb scaffold <path> --repo <repo> --type <type> --title <title> --code <code> [--body-file <file>]
forge kb ask <query> --repo <repo> [--scope <kind>...]
forge kb verify --repo <repo> [--scope <kind>...]
forge kb history --repo <repo>
forge kb add|update|remove <manifest> --repo <repo>

kb ask retrieves authority from the canonical local corpus and returns cited sources with explicit gaps. kb verify reports OKF structure and health findings. Neither proves that a candidate complies with anything.

kb history is receipt-derived: it summarizes successful applied memory operations from .forge/memory/, including Spec changes, knowledge and decision maintenance, and evidenced delivery. A manual log, a failed operation, or a structural check doesn't become shipped behavior, and malformed or incomplete receipts are reported as issues.

Create only knowledge topics the work actually earned. OKF concept types stay open and no empty corpus is required. KB write verbs reject empty changes, so an integrated delivery with no canonical document delta gets recorded through memory verify and memory apply with an empty changes list plus human authorization and nonempty source, evidence, and acceptance references. That receipt doesn't imply deployment or publication.

A worked sequence

forge setup --repo /path/to/project
forge init sidebar-label --repo /path/to/project --title "Clarify sidebar labels"
forge docs create issue .forge/loops/sidebar-label/spec/issues/label.md \
  --repo /path/to/project --title "Identify the sidebar action"
forge docs validate --repo /path/to/project
forge candidate --repo /path/to/project --path src
forge kb scaffold .forge/prepared/sidebar.md --repo /path/to/project \
  --type "Domain Concept" --title "Sidebar" --code "KB-SIDEBAR"
forge kb ask "sidebar" --repo /path/to/project
forge kb verify --repo /path/to/project

On this page