| name | add-agent-friendly-output |
| description | Make a CLI's output agent-friendly — stdout=data only, stderr=context only, semantic exit codes (80-119), typed errors with suggestions, help-json introspection, no internal retries, non-interactive by default. Use when asked to "make this CLI agent-friendly", "add agent-friendly output", "add semantic exit codes", or audit a tool's output contract. |
Make a CLI agent-friendly (cli-output-spec convention)
Apply the six rules from PROTOCOL.md to a CLI so its output is safe
for programmatic consumption by AI agents. Full how-to in RECIPE.md.
This skill is the checklist.
The six rules
-
Stream separation: stdout = data only (JSON or line-based, parseable, no ANSI when
piped). stderr = context only (progress, logs, warnings — never data). Never mix.
-
Semantic exit codes: 0 success. 80-89 input/validation. 90-99
precondition/resource. 100-109 external/integration. 110-119 internal/bug. Agents
branch on $?.
-
Typed errors: {"ok":false,"error":{"code":90,"type":"not_authenticated","message":"...","recoverable":false,"suggestions":["myapp signup"]}}.
Code matches exit code. recoverable tells agent whether to retry. suggestions gives
the agent the exact fix command.
-
No internal retries: report the error once, exit. The agent decides whether to
retry, back off, or escalate.
-
help-json introspection: machine-readable command catalog (commands, args, flags,
auth requirements, exit codes, env vars).
-
Non-interactive by default: --no-interactive / --yes / --json flags disable
prompts. Credentials from flags/env/config, never stdin on the happy path.
The four edits
-
Stream separation + JSON output: add log() → stderr, relay() → stdout. Add
--json flag. Check [ -t 1 ] for ANSI colors.
-
Semantic exit codes + typed errors: add fail(code, type, msg, ...suggestions)
function. Map HTTP status to exit code.
-
help-json: add help_json() function with the command catalog. Add help-json
to dispatch.
-
Non-interactive flags + no retries: accept/ignore --json/--no-interactive/
--yes/--no-color. Remove internal retry loops.
Verify
myapp leads --json 2>/dev/null | jq '.leads | length'
myapp leads --json 2>&1 1>/dev/null | head -1
myapp leads --json; echo $?
myapp help-json | jq '.commands | keys'
myapp leads --no-interactive --yes
Gotchas
- Don't print data to stderr "for context" — stdout is the single source of truth.
- Don't use exit code 1 for everything — use the 80-119 ranges.
- Don't retry internally — report once, exit, let the agent decide.
- Don't print ANSI when piped — check
[ -t 1 ].
- Bash: avoid
( in usage strings inside case patterns.