Skip to content

CONCEPT Cited by 1 source

Exit code semantics

Exit code semantics is the commitment that a CLI's exit codes and error shapes are documented, consistent, and load-bearing for agent control flow — agents branch on $? instead of parsing stderr strings.

Why it matters for agents

Agents don't read stderr the way humans do. A human sees "Error: could not connect to api.example.com: connection refused" and knows to retry. An agent that has to parse that string into a plan of action is burning tokens on a stderr-interpretation exercise that should be a constant-time switch.

The canonical framing from the gcx launch post:

"Exit codes and error shapes are documented and consistent, so an agent can branch on failure and recover on its own instead of guessing from a stderr string."

The doubled commitment — exit codes AND error shapes — is the load-bearing detail. Exit codes alone signal success/failure broadly; error shapes (a stable JSON envelope with {code, message, retriable, ...}) let the agent programmatically categorise the failure without LLM-level parsing.

What the commitment covers

Axis Commitment
Success Exit 0, zero ambiguity
Retryable failure Distinct non-zero code (typically in a documented range)
Non-retryable (input) failure Distinct non-zero code
Authentication / authorisation failure Distinct code so agent knows to refresh creds vs retry
Destructive-confirmation-required Distinct code so agent can re-invoke with confirmation
Version mismatch Distinct code so agent knows to upgrade

The documented contract lets the agent plan the recovery: - Retryable → back off + retry - Auth → refresh creds, retry once - Confirmation-required → prompt the human or apply policy - Version mismatch → abort the session with a clear message

Why the "documented" adjective matters

Undocumented exit codes are nearly as bad as no exit codes. The POSIX convention (0 = success, 1 = general error, 2 = misuse) is inadequate because nearly everything collapses to "1" and the agent has to string-parse stderr anyway. The Grafana commitment is to go beyond POSIX-baseline and publish the code table as part of the tool's contract — typically in the machine-readable catalog (concepts/machine-readable-command-catalog).

Contrast with the sibling structured-output contract

  • concepts/json-output-stability — stable field names on the happy path.
  • Exit code semantics — stable exit codes + error shapes on the failure path.

Both are needed. A CLI with stable JSON on success but exit 1 + ad-hoc stderr on failure is a half-contract — the agent's success-path parsing works, but its recovery logic stays LLM-mediated.

  • Git: documented exit codes with stable semantics (git merge: 0 clean, 1 conflict, 128 fatal).
  • kubectl: documented codes per subcommand.
  • curl: famously 70+ documented exit codes, each with a specific failure category.

The agent-ergonomic-CLI generation (Cloudflare's cf, Fly.io's flyctl, Grafana's gcx) extends this tradition explicitly for agent use — the stability is the point.

Seen in

Last updated · 433 distilled / 1,256 read