CLI tools MUST integrate cleanly with pipes, scripts, and other tools. That means handling SIGPIPE, detecting TTY for
color and formatting decisions, supporting stdin for piped input, and maintaining a consistent, predictable subcommand
structure.
Why Agents Need It
Agents compose CLI tools into pipelines:
tool list --output json | jaq '.[] | .id' | xargs tool get
Every link in that chain has to behave predictably. A tool that panics on SIGPIPE when piped to head breaks the
pipeline. A tool that emits ANSI color codes into a pipe pollutes downstream JSON parsing. A tool with inconsistent
subcommand naming forces the agent to memorize exceptions rather than apply patterns. Composability is what makes a CLI
tool a building block rather than a dead end.
Requirements
Evidence
libc::signal(libc::SIGPIPE, libc::SIG_DFL) (or the equivalent in the target language) as the first statement of
main().
IsTerminal trait usage (std::io::IsTerminal or the is-terminal crate).
NO_COLOR and TERM=dumb checks.
clap_complete in Cargo.toml.
A completions subcommand in the CLI enum.
Tiered match arms in main() separating meta-commands from config-dependent commands.
Anti-Patterns
Missing SIGPIPE handler: cargo run -- list | head panics with "broken pipe".
Hard-coded ANSI escape codes without TTY detection.
Color output in JSON mode: ANSI codes inside JSON string values break downstream parsing.
A completions command that requires auth or config to run.
No stdin support on commands where piped input is a natural use case.
Measured by audit IDs p6-sigpipe, p6-no-color, p6-completions, p6-timeout, p6-agents-md. Run anc audit --principle 6 . against the CLI under test to see each.