cli-for-agents
Agent-Friendly CLI Design Best Practices
Prescriptive design and review standards for Command-Line Interface Design targeting AI agents and scripts, not just humans typing at a prompt. Human-oriented CLIs often block agents: interactive prompts, huge upfront docs, help text without copy-pasteable examples, error messages without fixes, no dry-run mode. This skill prioritizes rules by blast radius — from "the agent cannot use this CLI at all" (CRITICAL) to "the agent has to read help one extra time" (MEDIUM).
Use this skill both when building a new CLI and when reviewing an existing one for agent-friendliness.
This skill contains 45 rules across 8 categories.
When to Apply
Reference these guidelines when:
- Writing
--helptext for any subcommand - Designing new flags, arguments, or subcommands
- Crafting error messages or exit codes
- Adding destructive operations that need dry-run or confirmation
- Choosing between interactive prompts and flag-only inputs
- Shaping success output so agents can chain commands
- Reviewing an existing CLI for headless-usability regressions
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Non-interactive Operation | CRITICAL | interact- |
| 2 | Help Text Design | HIGH | help- |
| 3 | Error Messages | HIGH | err- |
| 4 | Destructive Action Safety | HIGH | safe- |
| 5 | Input Handling | HIGH | input- |
| 6 | Output Format | MEDIUM-HIGH | output- |
| 7 | Idempotency & Retries | MEDIUM-HIGH | idem- |
| 8 | Command Structure | MEDIUM | struct- |
Note: help-examples-in-help is rated CRITICAL within the HIGH help- category because its specific failure — help text without examples — makes every other help rule moot. The category label reflects the average, not the worst case.
Quick Reference
1. Non-interactive Operation (CRITICAL)
interact-flags-first— Express every input as a flag first; prompts are TTY-only fallbackinteract-detect-tty— Checkisatty()before promptinginteract-no-arrow-menus— Replace arrow-key menus with flag-selected choicesinteract-no-input-flag— Support--no-inputto force non-interactive modeinteract-no-timed-prompts— Never use timed prompts or press-any-key screensinteract-no-hang-on-stdin— Don't block on stdin when a TTY is attached
2. Help Text Design (HIGH)
help-examples-in-help— Include copy-pasteable examples in every--helphelp-per-subcommand— Every subcommand owns its own--helphelp-no-flag-required— Show help when invoked with zero argumentshelp-layered-discovery— Top-level help is a navigational indexhelp-flag-summary— List both short and long forms for every flaghelp-suggest-next-steps— Suggest what to run next in help and success output
3. Error Messages (HIGH)
err-exit-fast-on-missing-required— Exit fast on missing required flagserr-actionable-fix— Include a concrete fix in every error messageerr-stderr-not-stdout— Send errors to stderr, not stdouterr-non-zero-exit-codes— Use distinct non-zero exit codes for distinct failureserr-include-example-invocation— Include a correct example invocation in errorserr-no-stack-traces-by-default— Reserve stack traces for--debugmode
4. Destructive Action Safety (HIGH)
safe-dry-run-flag— Provide--dry-runfor every destructive commandsafe-force-bypass-flag— Provide--yes/--forceto skip confirmationssafe-confirm-by-typing-name— Require typing the resource name for irreversible actionssafe-no-prompts-with-no-input— Never prompt when--no-inputis setsafe-idempotent-cleanup— Exit successfully when delete targets are already gonesafe-crash-only-recovery— Design multi-step commands for crash-only recovery
5. Input Handling (HIGH)
input-accept-stdin-dash— Accept-as filename for stdin and stdoutinput-flags-over-positional— Prefer named flags over positional argumentsinput-stdin-for-secrets— Accept secrets through stdin or file, never as flag valuesinput-env-var-fallback— Accept common flags through environment variablesinput-no-prompt-fallback— Never fall back to a prompt when a flag is missing
6. Output Format (MEDIUM-HIGH)
output-json-flag— Provide--jsonfor stable machine-readable outputoutput-ndjson-streaming— Stream large result sets as NDJSONoutput-bounded-by-default— Bound default output size with--limitand--alloutput-machine-ids-on-success— Return chainable values on success, not just "Done"output-respect-no-color— Disable ANSI color whenNO_COLORor non-TTYoutput-no-decorative-only— Avoid relying on decorative output to convey stateoutput-one-record-per-line— One record per line for grep-able human output
7. Idempotency & Retries (MEDIUM-HIGH)
idem-retry-safe— Make running the same command twice safeidem-create-or-skip— Make create commands skip when target already existsidem-stable-output-on-skip— Return the same output shape whether acting or skippingidem-state-reconciliation— Prefer "ensure state" semantics over delta applicationidem-stable-identifiers— Accept user-provided names instead of auto-generating IDs
8. Command Structure (MEDIUM)
struct-resource-verb— Use a consistent resource-verb command shapestruct-flag-order-independent— Parse flags in any position relative to subcommandsstruct-no-hidden-subcommand-catchall— Avoid catch-all handlers for unknown subcommandsstruct-standard-flag-names— Use standard flag names (--help,--version,--verbose,--quiet)
How to Use
When building a new CLI
Start at CRITICAL and walk down. The first two categories (interact- and help-) are non-negotiable — if any rule in these is violated, the CLI is unusable by agents regardless of how good the rest is. After those, work through err-, safe-, and input- — these are where most real-world friction lives. output-, idem-, and struct- are polish that compounds across many invocations.
When reviewing an existing CLI
Run through this checklist in priority order:
- Non-interactive path — invoke every subcommand with
--no-inputor under</dev/nulland see which hang - Layered help — does
mycli --helplist subcommands only, or dump everything? - Examples on
--help— every subcommand's help should end with a runnable Examples section - Error messages with invocations — does every error tell the caller exactly which flag to add?
- stdin/pipeline story — can you pipe output into input? Does
-mean stdin? - Exit codes — are usage errors (2), runtime failures (1), and transient failures (69) distinct?
- Dry-run — every destructive command has
--dry-run(or equivalent) - Confirmation bypass — every destructive command has
--yes/--force - Consistent command structure — do
service list,deploy list,config listall exist and work the same way? - Structured success output — does
deployreturn adeploy_idthe agent can use next?
Individual rules
Read individual reference files for detailed explanations and code examples:
- Section definitions — Category structure and impact levels
- Rule template — Template for adding new rules
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for new rules |
| metadata.json | Version and reference information |