CLI Exit Codes and HTTP Status Mapping¶
agent-bom exposes the same domain through a CLI, an HTTP API, an MCP server, and a
GitHub Action. CI gates and shell pipelines branch on agent-bom's exit code; HTTP
clients branch on the API's status code. This page is the single contract that
documents both, so a script writer never has to read the source to know what an
exit code means.
CLI exit-code contract¶
The contract covers ok, findings, usage, auth, and server failures explicitly so automation can distinguish caller mistakes from control-plane outages.
| Code | Name | Meaning | Typical sources |
|---|---|---|---|
0 |
success | Command completed; no findings or all findings under the configured severity threshold. | Any subcommand that finished cleanly. |
1 |
operational failure | A precondition failed: missing config, unreachable backend, missing required env var, dependency not present. | --clickhouse-url missing, NVD unreachable, optional dependency not installed. |
2 |
usage or empty | Invalid arguments, no input to act on, or report contained no rows after filtering. | Click UsageError (auto), agent-bom skills audit with no skill files, empty result rendering. |
3 |
(reserved) | Reserved for "policy gate failed" — declared so future policy commands have a stable code to use. | Not yet emitted. |
4 |
(reserved) | Reserved for "auth required" / "auth invalid" on commands that talk to an authenticated control plane. | Not yet emitted. |
5 |
(reserved) | Reserved for "remote control-plane error" (5xx response from the API). | Not yet emitted. |
130 |
interrupted | Process received SIGINT (Ctrl-C) — POSIX convention, kept for shell idiom compatibility. |
Long-running agent-bom proxy / agent-bom serve / agent-bom agents. |
* |
subprocess passthrough | When agent-bom shells out (e.g. native scanner binaries), the child's non-zero exit code is propagated. | agent-bom shield, agent-bom run proxy invocations. |
The unreserved codes (0, 1, 2, 130) are stable today. Codes 3, 4, 5 are
reserved so future product growth has a clean place to land without re-numbering
existing codes — operators may rely on if [ "$rc" -eq 0 ] and on the
rc != 0 family without further branching today.
API status-code contract¶
| Status | Meaning | Where it's raised |
|---|---|---|
200 |
Success. | All successful reads and writes. |
201 |
Created. | POST /v1/scan, POST /v1/auth/keys, SCIM POST /Users//Groups. |
204 |
Deleted. | DELETEs that succeed without a body. |
400 |
Bad request — payload validation passed Pydantic but failed business-rule validation. | Tenant-quota update with negative caps, invalid filter combinations. |
401 |
Unauthenticated — no valid API key, OIDC bearer, SAML session, or trusted-proxy attestation. | Middleware before route resolution. |
403 |
Authenticated but not authorized — RBAC scope rule rejected the call. | Cross-tenant access attempt, viewer role attempting admin operation. |
404 |
Resource not found. | Scan job, agent, registry server, key, or graph node not present in tenant. |
409 |
Conflict — idempotency clash, duplicate key creation, concurrent state mutation. | API key rotation, scan-job lifecycle conflicts. |
422 |
Pydantic validation failure — payload shape rejected. | FastAPI request-body validation. |
429 |
Rate limited — per-tenant quota or global rate limit hit. | Middleware PostgresRateLimitStore. |
500 |
Server error — unexpected exception inside route logic. | Bugs, downstream timeouts that escape retry budgets. |
502 |
Upstream bad-gateway — proxied call (e.g. external scanner) returned an unparseable response. | External scanner adapters. |
503 |
Backend unavailable — Postgres, ClickHouse, or another required dependency is down. | Health probes, dependency-aware routes. |
All errors return {"detail": "<message>"} per FastAPI default. The UI client at
ui/lib/api.ts parses detail, message, and error so that any of those keys
surface to operators with a useful string.
How CLI codes correspond to API statuses¶
This is the explicit mapping that the CLI applies when it talks to the API and needs to translate an HTTP outcome into a process exit code. It's not a reflexive 1:1 mapping — several HTTP codes collapse into a single CLI code because shells care about families, not individual semantics.
| CLI exit code | HTTP status family | Why |
|---|---|---|
0 |
2xx |
The command did what it asked. |
2 |
400 422 |
Caller sent something invalid — usage error, fix the input. |
4 (reserved) |
401 403 |
Caller is not (or not yet) authorized — fix credentials, not the input. |
1 |
404 409 |
Operational state issue — resource missing, conflict — retryable after correcting state. |
1 |
429 |
Throttled — retry with backoff. Today flattens to 1; future revisions may use a dedicated code. |
5 (reserved) |
5xx |
Control-plane fault — agent-bom is not at fault, retry or escalate. |
130 |
n/a | Operator pressed Ctrl-C; never originates from an HTTP response. |
Until reserved codes (3/4/5) are emitted, the safe shell idiom is:
agent-bom agents -p ./project --format sarif > out.sarif
rc=$?
case "$rc" in
0) echo "ok" ;;
2) echo "usage / empty"; exit 0 ;; # treat empty as non-failure in some pipelines
130) echo "interrupted"; exit 130 ;; # propagate Ctrl-C semantics
*) echo "failed (rc=$rc)"; exit "$rc" ;;
esac
GitHub Action action.yml outputs¶
The composite action surfaces both the CLI exit code and a parsed-status output so
downstream steps can branch without re-parsing logs. When agent-bom finds findings
above the configured severity floor the step still exits 0 — the action sets
outputs.findings for the caller to gate on. Hard failures (rc != 0 and not an
empty/usage outcome) bubble up so the workflow turns red.
| Output | Type | Source | Notes |
|---|---|---|---|
findings |
string | parsed from JSON / SARIF | "true" when at least one finding crosses the configured severity floor. |
report-path |
string | computed | Absolute path to the JSON / SARIF / HTML report inside the runner workspace. |
sarif-path |
string | computed | Absolute path to the SARIF report when --output sarif was selected. |
exit-code |
string | propagated CLI exit code | Same value documented in CLI exit-code contract. |
Stability guarantees¶
0,1,2,130, and the subprocess passthrough are stable and will not be re-numbered within a major version.3,4,5are reserved and will be assigned only to the meanings declared above.- The HTTP status mapping is a binding contract for shell pipelines; future status
codes added to the API will fold into the same families described above unless a
new CLI code is introduced (in which case it will be drawn from the reserved set,
not allocated above
5).