cli-design
Design CLIs for humans and LLM agents — subcommand shape, output streams, exit codes, JSON modes, TTY-aware color, structured errors, mutation safety. Use when building or refactoring a CLI, adding machine-readable output, writing --help, deciding stdout vs stderr, or making a tool agent-friendly.
What this skill does
# CLI Design
A CLI has two readers now: the human typing at a prompt and the LLM agent invoking it from a shell tool. Most production CLIs were designed only for the first, and the failure modes diverge sharply once an agent starts calling them. The `--help` text is the agent's tool description. The output format is the response schema. Exit codes are error codes. Designed poorly, a CLI costs an agent roughly 35× the tokens of a well-designed one on equivalent workflows (MindStudio, measured against MCP equivalents) — and that's before the agent burns retries on errors it can't parse.
The good news: most of the rules that make a CLI agent-friendly also make it script-friendly and pipeline-friendly. The Unix philosophy and agent-friendliness converge on the same answers. The mistakes are specific and well-cataloged.
For tool-specific patterns, principle citations, and a long-form anti-pattern catalog with GitHub issues, see [reference.md](reference.md).
## The Two-Reader Lens
Every output path on every command should have a default human form and a machine form available on demand. Don't pick one — design both.
Where the split shows up:
- **Output format**: `git status` for humans, `git status --porcelain` for scripts. Human format can evolve between versions; porcelain format is a versioned contract.
- **Color**: enabled in a TTY, automatically disabled when stdout is piped. Respect `NO_COLOR=1`; honor `FORCE_COLOR=1` as the override.
- **Prompts**: only when stdin is a TTY. In non-TTY contexts, fail with instructions or honor `--yes` / `--non-interactive`. A CLI that prompts in a pipe hangs an agent indefinitely — this is the single most common production break.
- **Progress**: spinners and bars in a TTY, nothing when piped. Or always to stderr, so capture is clean.
The cost of getting this wrong is concrete and well-documented. A CLI that emits ANSI in pipes corrupts downstream `grep`. A CLI that prompts in a non-TTY hangs CI and agent workflows. A CLI that decorates JSON output with table borders is unparseable. These bug reports exist against npm, yarn, AWS CLI, Claude Code, codex — every project relearns the lesson.
## Stream Discipline
**stdout is data the caller wants to capture. stderr is everything else.**
Progress, warnings, "fetching...", success confirmations — all stderr. The contract: `sis list -j | jq` should produce clean JSON even when the daemon prints "connecting to socket..." along the way. The diagnostic test: `cmd > /dev/null` should hide nothing the user wanted to see, and `cmd 2>/dev/null` should hide all decoration.
The Rule of Silence applies: when a command succeeds and has nothing useful to print, say nothing. "✓ Task completed" on stdout is decorative and breaks composition. Modern dev tools relax this for friendliness — fine, but route the friendly message to stderr.
## Machine Output Is a Contract
The moment you ship `--json` or `--porcelain`, the shape is a versioned API. Renaming a field breaks every script in the wild — and every agent that learned to parse it.
- **Include a `schema_version` field** (or use a versioned flag like `--porcelain=v2`, the way git does). Callers can branch on it; you can evolve safely.
- **Prefer JSONL for streams.** One complete JSON object per line. Partial reads don't break parsing, no closing bracket to wait for, cheaper to consume in pieces. Use a JSON array only when the entire result is bounded and small.
- **Make output deterministic.** Sort by a stable field; same input, same output. Random ordering or embedded timestamps break diffs and caching.
- **Field selection beats post-filtering.** `gh pr list --json number,title` is leaner than `--json '*' | jq '{number,title}'`. Save the caller a step and save tokens — agents pay per byte.
- **In `--json` mode, errors are structured too.** `{"error":"validation_failed","code":"INVALID_EFFORT","message":"...","valid_values":[...]}`. Agents branch on the code; humans read the message.
## Errors as Road Signs
An error is feedback the caller uses to correct itself. An opaque error produces retry loops; a road sign produces recovery. Every error needs three pieces: what was received, what was expected, and what to do next.
```
# Useless — agent loops on the same call
Error: invalid argument
# Recoverable — exact fix is implied
Error: --effort must be one of: low, medium, high, xhigh (got: 'xmedium')
# Recoverable with a path
Error: deck file not found: ./questions.json
Pass an absolute path, or run from the directory containing the file.
```
Exit codes are the second channel. **0 on success, non-zero on any failure** is universal. Beyond that, document any specific codes the caller should branch on: `git diff` exits 1 to signal "differences exist" (a useful condition, not an error). Don't invent codes unless callers will branch on them — most CLIs need only `0` and `1`. If you do specialize, write them down: `2` for usage error, `5` for conflict, `127` for not-found are the conventional choices.
## Command Shape
Past about seven top-level verbs, organize them. Three shapes work; mixing them doesn't.
- **Flat verbs** (`tar`, `curl`, `rg`, `jq`): fast to type, breaks down past ~10 commands. Right for a focused tool with one purpose.
- **Verb-noun** (`kubectl get pods`, `cargo build`): predictable when the same verbs apply to many objects. The shape is exploration-friendly — knowing `kubectl get` predicts that `kubectl describe` and `kubectl delete` exist. For agents, this is deterministic tree search through `--help`.
- **Noun-verb** (`docker container create`, `gh pr list`): better when objects have many distinct operations that don't share verbs across types. Pairs naturally with `--json field,field` projections.
Pick one and apply it uniformly. The worst CLIs mix shapes (`tool deploy --app foo` next to `tool config set key val` next to `tool users list`). Be deliberate about aliases — `npm install`, `npm add`, `npm i` look helpful in isolation but force scripts and agents to remember three names for one operation. Pick the canonical name and document the others as aliases, not equals.
## Inputs: Flags, Environment, Stdin
The standard precedence is **flags > env vars > project config > user config > defaults**. Flags always win, so scripts can inject overrides without touching state.
A few rules with sharp edges:
- **Accept stdin when content is the natural input.** Long prompts, file contents, queries. By convention, a bare `-` as a positional argument means "read from stdin"; pair it with an explicit `--stdin` flag when ambiguity matters.
- **Never accept secrets via flags.** `ps aux` reveals them; shell history saves them. Use `--password-file`, stdin, or a credentials file.
- **Respect standard env vars.** `NO_COLOR`, `FORCE_COLOR`, `PAGER`, `EDITOR`, `XDG_*`, `TMPDIR`. Don't reinvent these.
- **Don't smuggle state across invocations.** If `cmd-a` writes to `~/.cache/tool/state` and `cmd-b` silently depends on it, agents calling `cmd-b` in a fresh shell will fail. Pass state explicitly.
## Mutation Safety
For destructive or expensive operations, separate preview from execution. The pattern compounds: it makes agents safer (they can plan before acting) and humans saner (no surprise commits).
- **`--dry-run` for "show what would happen."** Should be cheap, side-effect-free, and structurally identical to the real run.
- **Plan/apply for complex changes.** `terraform plan -out=file` saves a plan; `terraform apply file` executes exactly that plan. No drift between preview and execute.
- **Confirmation prompts only in a TTY.** In non-TTY, require `--yes` or fail. Never assume.
- **Idempotency wherever possible.** Running `apply -f config.yaml` twice should converge to the same state as once. This is more valuable than perfect rollback.
## Help Is the Tool Description
For agents, `--help` is the only documentation that reliably gets read. Treat it the way you would a function description in a tool scheRelated in Design
contribute
IncludedLocal-only OSS contribution command center. Auto-refreshes the user's in-flight PR and issue state on invoke so conversations start with full context — no need to brief Claude on what's in flight. Helps the user find issues to contribute to on GitHub, builds per-repo dossiers of what each upstream expects (CLA, DCO, branch convention, AI policy, draft-first, review bots, issue templates), runs deterministic gates before any external action so AI-assisted contributions don't reach maintainers as slop. State is markdown-only: candidate files at ~/.contribute-system/candidates/, repo dossiers at ~/.contribute-system/research/, append-only event log at ~/.contribute-system/log.jsonl. No database, no cloud calls. Use when the user asks about their PRs / issues / contributions, wants to find new work to take on, claim an issue, build/refresh a repo's dossier, or draft a Design Issue or PR. Trigger with "/contribute", "what's my PR status", "find a contribution", "claim issue X", "draft a Design Issue for Y", "refresh dossier for Z".
architectural-analysis
IncludedUser-triggered deep architectural analysis of a codebase or scoped subtree across eight modes — information architecture, data flow, integration points, UI surfaces, interaction patterns, data model, control flow, and failure modes. This skill should be used when the user asks to "diagram this codebase," "map the architecture," "show the data flow," "give me an ERD," "trace control flow," "find the integration points," "verify the layout pattern," "audit the UX architecture," or any similar request whose primary deliverable is mermaid diagrams plus cited reports under docs/architecture/. Dispatches haiku/sonnet sub-agents in parallel for per-mode exploration, then verifies every citation mechanically before any node lands in a diagram. Not for one-off prose explanations of code (use code-explanation) or for high-level system design from scratch (use system-design).
mcp
IncludedModel Context Protocol (MCP) server development and tool management. Languages: Python, TypeScript. Capabilities: build MCP servers, integrate external APIs, discover/execute MCP tools, manage multi-server configs, design agent-centric tools. Actions: create, build, integrate, discover, execute, configure MCP servers/tools. Keywords: MCP, Model Context Protocol, MCP server, MCP tool, stdio transport, SSE transport, tool discovery, resource provider, prompt template, external API integration, Gemini CLI MCP, Claude MCP, agent tools, tool execution, server config. Use when: building MCP servers, integrating external APIs as MCP tools, discovering available MCP tools, executing MCP capabilities, configuring multi-server setups, designing tools for AI agents.
react-native-skia
IncludedDesign, build, debug, and optimise high-polish animated graphics in React Native or Expo using @shopify/react-native-skia, Reanimated, and Gesture Handler. Use when the user wants canvas-driven UI, shaders, paths, rich text, image filters, sprite fields, Skottie, video frames, snapshots, web CanvasKit setup, or performance tuning for custom motion-heavy elements such as loaders, hero art, cards, charts, progress indicators, particle systems, or gesture-driven surfaces. Also use when the user asks for fluid, glow, glass, blob, parallax, 60fps/120fps, or GPU-friendly animated effects in React Native, even if they do not explicitly say "Skia". Do not use for ordinary form/layout work with standard views.
plaid
IncludedProduct Led AI Development — guides founders from idea to launched product. Six capabilities: Idea (discover a product idea), Validate (pressure-test the idea against fatal flaws, problem reality, competition, and 2-week MVP feasibility), Plan (vision intake + document generation), Design (translate image references into a design.md spec), Launch (go-to-market strategy), and Build (roadmap execution). Use when someone says "PLAID", "plaid idea", "help me find an idea", "product idea", "idea from my business", "idea from my expertise", "plaid validate", "validate my idea", "pressure-test", "is this idea good", "find fatal flaws", "validate the problem", "plan a product", "define my vision", "generate a PRD", "product strategy", "plaid design", "design from image", "translate image to design", "create design.md", "extract design tokens", "plaid launch", "go-to-market", "launch plan", "GTM strategy", "launch playbook", "plaid build", "build the app", "start building", or "execute the roadmap".
nextjs-framer-motion-animations
IncludedAdds production-safe Motion for React or Framer Motion animations to Next.js apps, including reveal, hover and tap micro-interactions, whileInView, stagger, AnimatePresence, layout and layoutId transitions, reorder, scroll-linked UI, and lightweight route-content transitions. Use when the user asks to add, refactor, or debug Motion or Framer Motion in App Router or Pages Router codebases, especially around server/client boundaries, reduced motion, LazyMotion, bundle size, hydration, or route transitions. Avoid for GSAP-style timelines, WebGL or 3D scenes, heavy scroll storytelling, or CSS-only effects unless Motion is explicitly requested.