Developer Tools

Good CLI output is a kind of API

2 min read

CLI output has more than one reader.

A person sees the terminal. A shell script reads stdout. CI reads the exit code. An agent may inspect the tail of a log and decide whether to retry, stop, or ask for help. Later, someone pastes the failure into an issue and reconstructs state from whatever survived.

That makes a few boring contracts important:

good:
  stdout: machine-readable result
  stderr: progress and warnings
  exit code: 0 success, nonzero failure

bad:
  stdout: mixed status text and JSON
  stderr: silent
  exit code: 0 when the command failed

Keep stdout parseable when another tool needs it. Keep diagnostics on stderr. Give the same failure the same exit code. If structured output exists, keep its shape stable across releases.

Failure messages are part of the interface too. “Permission denied” may be technically accurate. “Permission denied while reading secrets.json; use –scope repo or move the file under the workspace” gives the next action.

Progress output should also have a stable mode. A human-readable stream can show phases. A JSON mode can expose records such as:

{"status":"done","path":"dist/app.tar.gz"}

The best command works for a person and a pipeline without making either one guess whether a warning is data or whether success actually means success.

Jeremy London

About Jeremy London

Engineering leader and builder in Denver. I write about AI platforms, agents, security, reliability, homelab infrastructure, and the parts of engineering work that have to survive production.