Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD across contents and paths, upstream package/repo coordinates -> @golem15/msd-core and golem15com/msd-core. Deep links into upstream history, sibling upstream packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is. Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line, package/plugin identity, regenerated lockfile, install-tree fixtures, derived registries and benchmark baseline; migration checksum baseline re-locked (MSD keeps its own install state, so no install had applied the old sums); sort-order and regex-escaped expectations in tests adjusted.
68 lines
4.6 KiB
Markdown
68 lines
4.6 KiB
Markdown
# Exit code reference
|
||
|
||
> **Generated file — do not edit by hand.**
|
||
> This page is generated from the exit-code declaration
|
||
> (`msd-core/bin/shared/exit-codes.json`) by `scripts/gen-exit-code-docs.cjs`
|
||
> and kept honest by a drift guard in `npm run lint:generated-sync` (which runs
|
||
> `node scripts/gen-exit-code-docs.cjs --check`). Any manual edit is overwritten
|
||
> on the next generation run. To register a new code, add an entry to the
|
||
> declaration and run `node scripts/gen-exit-code-registry.cjs --write && node
|
||
> scripts/gen-exit-code-docs.cjs --write`.
|
||
|
||
See also: [ADR-3889 — one exit-code registry](../adr/3889-process-exit-contract.md) —
|
||
[Adopt the v2 exit contract](../how-to/adopt-the-v2-exit-contract.md) —
|
||
[JSON error mode](../json-errors.md)
|
||
|
||
---
|
||
|
||
## Registered codes (6)
|
||
|
||
Every process-level exit code `msd-tools`, its hooks, and its scripts may terminate
|
||
with, by name, meaning, and the module that owns it.
|
||
|
||
| code | name | meaning | owning module | authorized by |
|
||
|---|---|---|---|---|
|
||
| 2 | `HOOK_DENY` | Hook protocol deny — the harness blocks the tool call | `hook-adapter` | ADR-3889 |
|
||
| 64 | `USAGE` | Caller error — bad argv, unknown subcommand, missing argument | `generic` | ADR-3889 |
|
||
| 66 | `NO_INPUT` | Ran; zero units were in scope, and that emptiness is known to be genuine | `generic` | ADR-3889 |
|
||
| 69 | `UNAVAILABLE` | Could not run — prerequisite absent, input unreadable, scope unestablished | `generic` | ADR-3889 |
|
||
| 70 | `INTERNAL` | Self-failure — crash, timeout, killed subprocess | `generic` | ADR-3889 |
|
||
| 80 | `DEGRADED` | Ran to completion and is reporting a condition through its result payload rather than as a process failure | `msd-tools` | ADR-3889 + ADR-2980 |
|
||
|
||
---
|
||
|
||
## Reserved bands
|
||
|
||
The registered codes above are not chosen freely — each falls inside one of a
|
||
fixed set of allocatable bands (ADR-3889 §1). A code outside these bands can
|
||
never be registered; validation rejects it before it reaches the tables above.
|
||
This is what makes an unfamiliar number in a CI log actionable: look up its
|
||
band first, then its registered name if it has one.
|
||
|
||
| Band | Meaning |
|
||
|---|---|
|
||
| `0`–`1` | **Free — never allocatable.** `0` is the universal "succeeded" convention and `1` is the universal "failed, no further detail" convention across nearly every CLI ecosystem. Registering either here would collide with that universal meaning instead of adding a distinct, named signal — so the registry leaves both permanently unallocated. |
|
||
| `2` | Reserved exclusively to the Claude Code hook-protocol deny (`HOOK_DENY`) — owned by `hook-adapter` and no other module. |
|
||
| `3`–`13` | **Node-reserved.** Node.js itself assigns meaning to this range (e.g. internal JavaScript errors, fatal exceptions, invalid argument errors) before a MSD process ever gets a chance to project its own outcome. Allocating one of these would be indistinguishable from a Node-level failure the process never intended to report. |
|
||
| `14`–`63`, `79`, `126+` | Outside every allocatable band — not Node-reserved, but also not opened for MSD use. `126`+ additionally collides with the shell convention for "command not executable" / "signal N" (`128+N`), which a process exit code must never impersonate. |
|
||
| `64`–`78` | **Generic band.** Codes any module may use for caller-facing, non-domain-specific outcomes (bad argv, no input in scope, a missing prerequisite, an internal crash). |
|
||
| `80`–`125` | **Domain band.** Codes reserved for a specific product surface's own vocabulary — currently only `msd-tools`' `DEGRADED` (a completed run reporting a condition through its payload rather than as a process failure). |
|
||
|
||
## The v1/v2 exit contract
|
||
|
||
ADR-3889 §4 adds a **version projection** on top of this registry, not a second
|
||
registry: every registered name above projects to the *same* code under both
|
||
contract versions, with one deliberate exception — `DEGRADED`. Under the
|
||
default, backward-compatible `v1` contract, a payload-carried error
|
||
(`output({error})`) still exits `0`, exactly as
|
||
[ADR-2980](../adr/2980-payload-carried-error-is-a-degraded-result.md) ratified
|
||
for the pre-existing call sites that already depended on that behavior — **64**
|
||
call sites across 9 modules per that ADR's own amendment (its original text
|
||
said ~60). Under the
|
||
opt-in `v2` contract, the same outcome exits `80` (`DEGRADED`) instead, so a
|
||
caller that wants to branch on the exit code alone — without parsing stdout —
|
||
can opt in without breaking every existing consumer. See
|
||
[Adopt the v2 exit contract](../how-to/adopt-the-v2-exit-contract.md) for how to
|
||
turn this on, and [JSON error mode](../json-errors.md) for the full fault vs.
|
||
degraded-result channel taxonomy this registry sits underneath.
|