command-surface
A command file is five surfaces, not one. Add the file and stop, and the compiled binary breaks while dev-mode auto-discovery hides it from you.
The surfaces
Adding, renaming, or removing lib/commands/<name>.js means all of these:
Manifest — regenerate the static require graph:
node scripts/gen-command-manifest.js # write if changed node scripts/gen-command-manifest.js --check # exit 1 if stalelib/commands/_manifest.jsis generated; never hand-edit it. Drift is enforced bytest/structural/command-manifest-drift.test.js. [verified 2026-08-13]Registry — the command must resolve through the CLI registry (
test/forge-cli-registry.test.js,test/cli-flags.test.js).Skill coverage —
skills/coverage.jsonmaps every registered user-facing command to an owning skill, or carries an explicit{ exempt: <reason> }. Enforced byevaluateCoverageinlib/skill-eval.jsand gated intest/skill-eval.test.js. [verified 2026-08-13]Test lane — an entry in
DIRECT_TEST_CANDIDATES(lib/commands/test.js) so the new file resolves to real tests instead of forcing the full suite. See thetest-laneskill.Documentation — the command help text and, if it is a stage or utility, its row in
AGENTS.md.
Rules
- Regenerate, never hand-write, the manifest. Dev-mode discovery masks a
stale manifest locally;
bun build --compileand the drift gate do not. - Exempt means complete, not deferred. A command leaves
coverage.jsonasexemptonly when it is genuinely mapped, routable, and documented — and only in the PR that owns it. A hollow mapping just draws review rounds. - Use Forge's own generator. Re-implementing what the skill CLI already does is a recurring correction here: "why should we do the work". One canonical source, everything else generated. [Forge #5 ×4]
- Names stay short.
status,ready,ship,trace. Long or technical command names are a taste failure in this CLI.
Done when
node scripts/gen-command-manifest.js --check exits 0, the registry and
coverage tests pass, classifyPushTests reports a targeted lane, and you can
name the skill that owns the new command.