claude/agentic-engineering-principles-plugin/skills/cli-tools-for-agents/SKILL.md
Design a purpose-built project CLI as the primary tool surface for AI coding agents, instead of in-process tool or MCP servers. Covers the exit-code taxonomy, structured errors, file-based payloads with a validate verb, job-shaped long operations, identity resolution, a doctor self-check, and build-parity stamps. Use when building a CLI for agents, migrating away from in-process tool servers, designing tool output and error contracts, or deciding how agents should invoke project actions.
npx skillsauth add amhuppert/my-ai-resources cli-tools-for-agentsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
A custom CLI invoked through the shell is the most reliable and portable way to give agents tools. In-process tool servers need a babysitting subsystem (rebinds, keepalives, kill escalation); a CLI has no binding to break — failures become ordinary non-zero exits with readable errors, which agents recover from well. Design the CLI for a calling agent, not a human, and every downstream decision (exit codes, error shape, payload format) falls out of that inversion.
Ranked motivation:
--file payload.json plus a validate verb inverts this: payloads become files the agent writes, validates, and iterates on cheaply.The primary consumer is a program that must branch on results, not a person reading a terminal. That inverts the human-CLI defaults. State this design target explicitly at the top of the tool's docs.
--json envelope available on every command.Reserve a small, stable set of exit codes that answer "whose fault is it?" from $? alone, without parsing text. Publish the table in the tool's help and skill doc so recovery advice can key off it.
| Code | Meaning | Whose fault | |---|---|---| | 0 | Success | — | | 1 | Operation failed (the server said no) | The request's semantics | | 2 | Usage or validation error (bad flags, invalid payload) | The caller — fixable in one edit | | 3 | Connection or auth failure (server unreachable, bad token) | The environment | | 4 | Version mismatch (reserved; normally warn-only) | The deployment |
Every exit-3 error message points at the doctor command (below) — one recovery entry point, not scattered advice.
Everything checkable without the network — flag names, file readability, payload parse, identity resolution — fails locally and fast with a distinct exit code (2), before any request is sent. The agent gets a stable, reproducible failure fixable in one edit, instead of an ambiguous server error that may be transient.
Server-side validation remains the source of truth for semantics: schema validation at the route boundary produces the real errors. The CLI's local checks are the cheap deterministic layer in front of it.
When the server has computed per-field validation issues, it returns them as structured data ({ error, code?, issues? }) — never concatenated into one sentence. The CLI forwards code and issues into its --json envelope rather than flattening them.
<path>: <message>).In one real audit, structured issues were being extracted by the error classifier and then dropped at the rendering seam — JSON callers got less information than text callers. Treat that class as a defect.
Any payload beyond a couple of scalars is passed as a file (--file <path>, - for stdin), not a proliferation of flags. Agents are good at writing JSON with an editor tool and iterating against validation errors; they are bad at long shell quoting.
Pair every complex create/replace verb with a persist-nothing validate verb that runs the full server-side validation without creating anything. This turns a complex command into an author → validate → retry loop with a persistent artifact:
payload.json with its editor tool.yourcli thing validate --file payload.json — exit 2 lists issues one per line.yourcli thing create --file payload.json.Operations that outlive a comfortable shell-tool timeout are server-side jobs:
--wait [--timeout <dur>] long-polling and a separate status <id> verb.status <id> resumes observation.--wait flows aren't truncated by a default.Give the agent's environment its ambient identity via injected env vars, with a documented resolution order: explicit flags > env vars > file.
Do not name the binary something already on PATH. If the environment contract prepends your bin directory to PATH, a name collision silently shadows the existing tool for every agent session (a two-letter name collided with the system C compiler in one real design; the longer -ctl style name avoided it).
Ship one self-diagnostic command — doctor — that reports connectivity, auth, identity resolution, and version parity in one pass. It is the single recovery entry point:
doctor and gets a green handshake.When the CLI talks to a long-running service and agents work in per-branch worktrees, a client built from worktree code silently drifts from the service's API. Make the service the single source of the binary:
doctor surfaces it explicitly.Structure the CLI core as a pure function of (argv, env, injectedClient) → { exitCode, stdout, stderr }, with the HTTP client injected. Behavior is then testable without a server; a thin contract-test layer runs the real CLI against real route handlers in-process.
When the only consumers of an output shape are agents plus a skill doc updated in the same change, prefer clean replacement over dual-shape back-compat. A dual shape doubles the surface and teaches agents that two formats exist. Update the output contract and its skill doc atomically; rollback is a revert.
code field.progressive-disclosure-tooling — help as a navigable disclosure graph derived from one typed registryagent-feedback-tiers — hint/reminder/instruction output tiers and the reminder admission ruleai-readable-tool-output — configure linters, compilers, and test runners for low-noise agent consumptionagent-offloading — offload deterministic work from agents onto code; reserve agents for judgmentdevelopment
Debug a running web app via the web-debugger SDK: app logs, application state, runtime snapshots, React state, query cache.
development
Thoroughly understand a software development objective before implementation: research, identify ambiguities, ask clarifying questions. Use before starting implementation of a non-trivial or ambiguously specified feature, or when requirements leave open design decisions.
development
Locate the on-disk Claude Code transcript file (.jsonl under ~/.claude/projects/) for the current or a specified conversation.
development
Reflect on codebase navigation effectiveness at end of conversation. Surfaces dead ends, inefficiencies, missing context. Does not write files — pair with /kiro:steering-custom to persist.