REQ-C-001: Command Declares Exit Codes
Tier: Command Contract | Priority: P0
Source: §1 Exit Codes & Status Signaling
Addresses: Severity: Critical / Token Spend: High / Time: High / Context: Low
Description
Every command MUST declare a complete, exhaustive map of all exit codes it may emit, as part of its registration metadata. The framework MUST refuse to register a command that lacks this declaration. The exit code map MUST use the framework's named constants (REQ-F-001). The declared exit codes MUST be exposed in the command's --schema output. A passthrough command (REQ-C-031) declares only the codes the framework emits for it; the delegated tool's own codes pass through as DELEGATED_EXIT undeclared.
Each entry SHOULD list in error_codes the error.code values (REQ-C-013) the command emits under that exit code, so an agent can plan a branch for each before the first call. An absent error_codes means the command does not declare them; an empty array means the exit carries no error.code.
Acceptance Criteria
- Attempting to register a command without an
exit_codesdeclaration raises a framework error - Attempting to register a command whose
exit_codesmap does not include key"0"(SUCCESS) raises a framework error - Attempting to register an entry with
retryable: trueandside_effectsnot equal to"none"raises a framework error - The
--schemaoutput for every command includes anexit_codesobject keyed by code string, each value conforming toExitCodeEntry - A command that emits an exit code not in its declared map triggers a framework warning in development mode
- When an entry declares
error_codes, every response the command emits under that exit code carries anerror.codefrom the list, or none when the list is empty
Schema
Types: exit-code-entry.md · exit-code.md · manifest-response.md (CommandEntry.exit_codes)
Requirement-specific constraints on top of the base ExitCodeEntry schema:
{
"exit_codes": {
"type": "object",
"minProperties": 1,
"propertyNames": {
"pattern": "^(0|[1-9][0-9]*)$",
"description": "Keys are integer exit codes serialized as strings."
},
"additionalProperties": { "$ref": "exit-code-entry.json" },
"required": ["0"],
"description": "Must include an entry for ExitCode.SUCCESS (key '0')."
}
}
Wire Format
tool <cmd> --schema → .exit_codes:
{
"exit_codes": {
"0": { "name": "SUCCESS", "description": "Deployment completed", "retryable": false, "side_effects": "complete" },
"2": { "name": "ARG_ERROR", "description": "Invalid target environment", "retryable": false, "side_effects": "none" },
"5": { "name": "NOT_FOUND", "description": "Target cluster not found", "retryable": false, "side_effects": "none" },
"6": { "name": "CONFLICT", "description": "Version already deployed", "retryable": false, "side_effects": "none", "error_codes": ["ALREADY_DEPLOYED"] },
"10": { "name": "TIMEOUT", "description": "Deployment timed out — partial writes may have occurred", "retryable": false, "side_effects": "partial" }
}
}
Example
A command declares every exit code it may emit at registration time. The map key is the ExitCode named constant (serialized to its integer string in the wire format). Missing or incomplete declarations are hard errors.
register command "deploy":
exit_codes:
SUCCESS (0): description: "Deployment completed", retryable: false, side_effects: complete
ARG_ERROR(2): description: "Invalid target environment", retryable: false, side_effects: none
NOT_FOUND(5): description: "Target cluster not found", retryable: false, side_effects: none
CONFLICT (6): description: "Version already deployed", retryable: false, side_effects: none, error_codes: [ALREADY_DEPLOYED]
TIMEOUT (10): description: "Deployment timed out — partial writes may have occurred", retryable: false, side_effects: partial
register command "no-success":
exit_codes:
ARG_ERROR(2): description: "Bad argument", retryable: false, side_effects: none
→ framework error: exit_codes must include SUCCESS (key "0")
register command "bad-invariant":
exit_codes:
SUCCESS (0): description: "Done", retryable: false, side_effects: complete
TIMEOUT(10): description: "Timed out", retryable: true, side_effects: partial
→ framework error: retryable: true requires side_effects: "none"
register command "broken":
(no exit_codes)
→ framework error: exit_codes declaration is required
Related
| Requirement | Tier | Relationship |
|---|---|---|
| REQ-F-001 | F | Provides: ExitCode named constants used as map keys and name values |
| REQ-F-002 | F | Enforces: ARG_ERROR guarantees side_effects: none |
| REQ-C-015 | C | Composes: exit_codes is part of the --schema output |
| REQ-C-013 | C | Composes: error responses reference the codes declared here |
| REQ-O-041 | O | Aggregates: manifest collects exit code declarations from all commands |
| REQ-C-031 | C | Specializes: a passthrough command does not declare the delegated tool's codes |