Skip to content

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_codes declaration raises a framework error
  • Attempting to register a command whose exit_codes map does not include key "0" (SUCCESS) raises a framework error
  • Attempting to register an entry with retryable: true and side_effects not equal to "none" raises a framework error
  • The --schema output for every command includes an exit_codes object keyed by code string, each value conforming to ExitCodeEntry
  • 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 an error.code from 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

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