API设计
- 作者仓库星标 0
- 作者更新于 实时读取
- 作者仓库 skills-registry
- 领域
- 设计与多媒体
- 兼容 Agent
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- 信任分
- 88 / 100 · 社区维护
- 作者 / 版本 / 许可
- @tomevault-io · 未声明 license
- Token 消耗评级
- 中等消耗
- 接入复杂程度
- 需简单配置
- 是否需要外部 API Key
- 不需要
- 兼容的系统
- macOS · Linux · Windows
- 底层运行要求
- Node.js
- 文件与系统权限
-
- 只读
- 允许写入 / 修改
- Shell 执行
- 读取环境变量
- 网络行为
- 允许外网请求
- 安装命令数
- 26 条
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: cli-design
description: Unix-composable CLI design patterns. Use when building CLI tools, designing command trees, imple…
category: 设计与多媒体
runtime: Node.js
---
# cli-design 输出预览
## PART A: 任务判断
- 适用问题:视觉内容、演示材料、信息图或设计交付。
- 输入要求:目标材料、限制条件、期望输出和验收方式。
- 证据边界:围绕“When to Use / Core Principle / The Unix Stream Contract”读取原文规则,不把推断写成作者承诺。
## PART B: 执行结果
- **01** 任务判断:确认你的需求是否属于视觉内容、演示材料、信息图或设计交付,并标出输入、限制和预期结果。
- **02** 执行计划:优先按“When to Use / Core Principle / The Unix Stream Contract”拆成步骤,说明每一步会读取什么、修改什么、产出什么。
- **03** 交付结果:给出可复制的命令、文件改动、检查清单或内容草稿,并说明如何继续迭代。
- **04** 风险边界:结合 读取文件、写入/修改文件、执行终端命令、读取环境变量、会按任务需要访问外部网络、通常不需要额外 API Key 给出执行前确认项。
## Running Rules
- 读取文件、写入/修改文件、执行终端命令、读取环境变量;会按任务需要访问外部网络;通常不需要额外 API Key。
- 先小样例验证,再放大到真实任务。
- 交付时同时给结果、检查口径和下一步迭代建议。 原文没有稳定的斜杠命令要求。安装验证后通常全局生效,直接在对话里点名这个 Skill 并描述任务即可。
告诉 Agent 目标文件或材料、期望结果、不可改范围、是否允许联网或执行命令。本 Skill 的权限画像是:读取文件、写入/修改文件、执行终端命令、读取环境变量。
先用一个小任务确认它会围绕“When to Use / Core Principle / The Unix Stream Contract”工作;涉及文件或命令时,先看 diff、日志、预览或测试结果。
检查最终产物是否包含明确结果、必要证据和下一步动作;如果输出泛泛而谈,就补充输入、边界和验收标准后重跑。
---
name: cli-design
description: Unix-composable CLI design patterns. Use when building CLI tools, designing command trees, imple…
category: 设计与多媒体
source: tomevault-io/skills-registry
---
# cli-design
## 什么时候使用
- 用于组织测试、定位失败并形成修复闭环 适合处理界面、视觉、封面、信息图或演示材料交付,核心价值是把输入、判断、执行、验证和交付边界固定下来,避免 Agent 泛泛回答。 把任务拆成可执行、可检查、可继续迭代的步骤;通常不需要额外 API…
- 面向视觉内容、演示材料、信息图或设计交付,优先处理能明确输入、步骤和验收标准的工作。
## 需要提供什么
- 目标材料、目录范围、期望结果和不可改动内容。
- 是否允许联网、执行命令、读写文件或调用外部服务。
## 执行规则
- 围绕「When to Use / Core Principle / The Unix Stream Contract」组织步骤,不把推断写成作者事实。
- 读取文件、写入/修改文件、执行终端命令、读取环境变量;会按任务需要访问外部网络;通常不需要额外 API Key。
- 先跑小样例,确认结果可检查后再扩大任务范围。
## 输出要求
- 给出最终产物、关键证据、验证方式和下一步动作。
- 信息不足时标记 unknown,不编造命令、平台或依赖。 作者原文负责流程事实;仓库文件负责来源和命令;流狐只补充适用场景、限制和质量判断。
skill "cli-design" {
输入层 -> 用户目标 + 目标文件 + 禁止范围 + 验收标准
上下文层 -> When to Use / Core Principle / The Unix Stream Contract
规则层 -> SKILL.md 触发条件 / 执行顺序 / 输出格式
运行层 -> Node.js | 读取文件、写入/修改文件、执行终端命令、读取环境变量 | 会按任务需要访问外部网络
安全层 -> 通常不需要额外 API Key + 小任务验证 + diff / 日志复核
输出层 -> 可复制结果 + 检查清单 + 下一步迭代
} CLI Design: Unix-Composable Command-Line Interfaces
This skill covers language-agnostic CLI design principles. The rules about stream separation, exit codes, format flags, and composability apply regardless of implementation language.
For API contract stability and Hyrum's Law, see the api-design skill. For config, env vars, and graceful shutdown, see the twelve-factor skill.
TypeScript implementation patterns are in the resources/ directory. Load them on demand when building a CLI in TypeScript:
| Resource | Load when... |
|---|---|
output-architecture.md |
Implementing Result types, entry point wiring, formatters, logger, JSON envelope schemas |
testing-cli.md |
Writing Vitest tests for CLI behavior (streams, exit codes, pipes, contract tests) |
stream-contracts.md |
Understanding Node.js buffering, NDJSON, signal handling, crash-only design |
When to Use
- Building any command-line tool (any language)
- Designing command tree, flags, and I/O contracts
- Implementing the output layer (format detection, stream routing)
- Testing CLI behavior (stdout/stderr separation, exit codes)
- Reviewing a CLI for Unix composability
Core Principle
stdout is for DATA only — the product the user asked for. stderr is for EVERYTHING ELSE — diagnostics, progress, spinners, warnings, errors.
This separation is what makes mycli --json | jq ... work. One spinner character on stdout breaks every downstream pipe.
"Whatever software you're building, you can be absolutely certain that people will use it in ways you didn't anticipate. Your software will become a part in a larger system — your only choice is over whether it will be a well-behaved part." — clig.dev
The Unix Stream Contract
| Content | Stream | Why |
|---|---|---|
| Primary output (data, results, JSON) | stdout | Pipeable, buffered for throughput |
| Progress bars, spinners, status | stderr | Not data — must not corrupt pipes |
| Warnings, errors, diagnostics | stderr | Visible to user even when stdout is piped |
| Debug/verbose output | stderr | Diagnostic, never data |
Buffering behavior:
- stdout: line-buffered when connected to a TTY, block-buffered when piped (~2x faster than stderr)
- stderr: unbuffered — every write is a syscall (immediate but expensive)
- Check each stream independently — stdout being piped does not mean stderr is piped
When stdout is piped, the user doesn't want your status messages in their data. All non-data output must go to stderr.
For a deep dive on buffering behavior and performance implications, see resources/stream-contracts.md.
Keep Handlers Pure
The practical rule: functions that do the work should return data, not write to stdout. The CLI entry point handles all I/O.
Entry point (CLI main) Your logic (handlers)
───────────────────── ─────────────────────
parse args (input) → structured result
detect format (json/plain/human) no printing to stdout
call handler no writing to stderr
format the result no calling exit
write to correct stream just returns data
set exit code
This isn't an architecture mandate — it's just clean function design. The benefits are concrete:
- Testable without subprocess spawning — call the handler, assert on the returned value
- Format flexibility for free — same data renders as JSON, plain text, or coloured tables by swapping one function
- Reusable — the same handler works from a CLI, MCP server, HTTP API, or programmatic import
For simple CLIs where the "handler" is just calling a library, this separation already exists naturally — your library returns data, your CLI formats it. No extra layers needed.
If your project uses hexagonal architecture, the mapping is direct: the CLI entry point is a driving adapter, and the handler is a use case that returns a result through a port. See the hexagonal-architecture skill — the patterns reinforce each other, but hex arch is not required to benefit from keeping handlers pure.
For TypeScript implementation patterns (Result types, entry point wiring, formatters, logger interfaces), see resources/output-architecture.md.
Format Flag Contract
Three-tier output hierarchy:
Default: Human-Readable
- Colors, tables, formatted text
- Progress bars and spinners on stderr
- Output tailored for terminal width
- May change between versions — this is not a contract
--plain: Grep/Awk-Friendly
- One record per line, no formatting, no colors
- Stable between minor versions — this is a contract
- Flat table rows, no borders, no grouped sections
- Enables:
mycli list --plain | grep error | wc -l
"Encourage your users to use
--plainor--jsonin scripts to keep output stable." — clig.dev
--json: Structured Data
- stdout contains ONLY valid JSON — no spinners, no color, no progress
- stderr continues normally — human diagnostics still visible
- Errors are structured JSON too — not just success responses
- Schema is versioned — breaking changes to JSON output are breaking changes to the CLI
--jsonimplies non-interactive regardless of TTY
Consistent envelope:
{ "ok": true, "data": { ... } }
{ "ok": false, "error": { "code": "CONFIG_MISSING", "message": "...", "fix": "..." } }
NDJSON for Streaming
For large datasets, use NDJSON (one JSON object per \n):
- Each line is independently parseable
- Include a
typefield per record for multiplexing events - Final line can be a summary record
- Enables:
mycli run --format ndjson | while read -r line; do ...; done
For NDJSON specification details, see resources/stream-contracts.md.
Exit Codes
| Code | Meaning | When |
|---|---|---|
| 0 | Success | Operation completed as expected |
| 1 | Domain failure | Tool-specific failure (e.g. quality threshold not met) |
| 2 | Invalid usage | Bad flags, missing required args, validation error |
| 78 | Configuration error | Invalid config file, missing required config |
| 75 | Temporary failure | Network timeout, service unavailable — retry may help |
| 130 | SIGINT | User pressed Ctrl-C (128 + 2) |
| 143 | SIGTERM | Process terminated (128 + 15) |
Rules:
- Non-zero exit code MUST have a stderr explanation
- Document exit codes in
--help - Never use codes above 125 for application errors (reserved for signals: 128 + signal number)
- Exit code 75 (transient) is critical — it tells retry logic the failure may be temporary
- Map non-zero codes to the most important failure modes for your tool
TTY Detection
Check priority order (first match wins):
| Priority | Condition | Effect |
|---|---|---|
| 1 | --format json or --json flag |
Non-interactive, no color, no animation |
| 2 | --no-color flag |
Disable color (output may still be interactive) |
| 3 | NO_COLOR env (non-empty) |
Disable color |
| 4 | FORCE_COLOR env |
Enable color regardless |
| 5 | TERM=dumb |
Disable color and animations |
| 6 | CI=true |
No interactive prompts |
| 7 | stdout is not a TTY (!isatty(stdout)) |
Plain output, no animations on stdout |
| 8 | Default | Full interactive with colors |
Check stdout and stderr independently. When stdout is piped but stderr is a TTY, you can still show spinners on stderr while keeping stdout clean for the pipe consumer.
Optionally support MYCLI_NO_COLOR for app-specific color override.
Input Design
Flags Over Arguments
- 1 positional arg: acceptable (the "main thing")
- 2 positional args: suspicious — consider flags instead
- 3+ positional args: never acceptable
Flags are self-documenting, order-independent, and future-proof.
# Bad — which is source, which is destination?
mycli copy myapp backup
# Good — explicit
mycli copy --from myapp --to backup
Standard Flags
Always provide long forms. Short flags only for the most common operations.
| Flag | Meaning |
|---|---|
-h, --help |
Show help (this should only mean help) |
--version |
Print version to stdout |
-q, --quiet |
Suppress non-essential output |
-v, --verbose |
More detail in human output |
-d, --debug |
Diagnostic output to stderr |
-f, --force |
Skip confirmation prompts |
-n, --dry-run |
Show what would happen without doing it |
--json |
Structured JSON output |
--plain |
Stable, grep-friendly plain text |
--no-color |
Disable color output |
--no-input |
Disable all prompts/interactivity |
-o, --output |
Output file |
Prompts and Interactivity
- All prompts MUST be bypassable via flags for scriptability
- Confirmation →
--yesor--force - Selection →
--type=value - Text input →
--name=value - Passwords →
--password-file=pathor stdin pipe - If stdin is not a TTY, never prompt — fail with a clear error or use defaults
- Secrets via files/stdin/env only — never via flag values (they leak to
psoutput and shell history)
Conventions
- Support
--to stop flag parsing:mycli run -- --flag-for-child-process - Support
-for stdin/stdout file arguments:curl ... | mycli process - - Accept both
--flag=valueand--flag value - If stdin is expected but is an interactive terminal, display help immediately (don't hang like
cat)
Config Precedence
Highest to lowest priority:
- Flags — per-invocation overrides
- Environment variables —
MYCLI_*prefix, per-session - Project config —
.myclirc,mycli.config.ts, or inpackage.json - User config —
~/.config/mycli/(follow XDG spec) - Defaults — sensible built-in values
Rules:
- Follow the XDG Base Directory Specification for config file locations
- Env var naming:
MYCLI_*prefix, uppercase letters + digits + underscores - Never accept secrets via flags — use env vars, files, or stdin
- Read
.envwhere appropriate, but don't use it as a substitute for proper config - If you modify configuration that belongs to another program, ask consent first
Error Design
Every error needs:
- Machine-readable code —
UPPER_SNAKE_CASE(e.g.CONFIG_MISSING,AUTH_EXPIRED) - What went wrong — context: which resource, operation, input
- How to fix it — exact command or action the user should take
- Reference — docs URL or
mycli help <topic>(optional)
Human Mode
Error: CONFIG_MISSING — Configuration file not found
No configuration file found at ./mycli.config.ts or ~/.config/mycli/config.ts
Fix: Run `mycli init` to create a default configuration file
Docs: https://mycli.dev/docs/configuration
- Put the most important information last (the eye is drawn to the end)
- Use red sparingly and intentionally
- Suggest corrections for typos ("Did you mean 'deploy'?")
- Group similar errors under one header — don't repeat 50 similar-looking lines
- Write debug logs to a file, not the terminal (unless
--debug)
JSON Mode
Errors are structured too — not just success responses:
{
"ok": false,
"error": {
"code": "CONFIG_MISSING",
"message": "No configuration file found at ./mycli.config.ts",
"fix": "Run `mycli init` to create a default configuration file",
"transient": false
}
}
The transient boolean tells retry logic whether the failure may be temporary.
Composability Patterns
Design for real-world pipes:
# Filter structured output
mycli list --json | jq '.data[] | select(.status == "failed")'
# Stream results for large datasets
mycli run --format ndjson | while read -r line; do echo "$line" | jq '.file'; done
# Feed stdin
cat previous-results.json | mycli report --format markdown
# Combine with other tools
mycli run --json | mycli diff --baseline previous.json
# Silent mode for CI — only exit code matters
mycli check --quiet || echo "Check failed!"
# Chain: create outputs an identifier, next command uses it
mycli create --json | jq -r '.data.id' | xargs mycli deploy --id
# Column selection for efficiency
mycli list --json --fields name,status,id | jq '.data[]'
# Parallel processing
mycli list --json --fields id | jq -r '.data[].id' | xargs -P4 mycli process --id
Key patterns:
- Create commands output identifiers so subsequent commands can chain
- List commands support
--fieldsfor column selection (reduces output size, critical for agent efficiency) --quietfor CI scripts that only care about the exit code- NDJSON for streaming large datasets without buffering everything in memory
--dry-runwith--jsonoutputs planned changes as structured data
Subcommand Design
- noun verb pattern is most common:
mycli config set,mycli report generate - Be consistent across all subcommands — same flag names for same things
- No ambiguous pairs (
updatevsupgradeis confusing) - No catch-all subcommands (you can never add subcommands with conflicting names)
- No arbitrary abbreviations — aliases must be explicit and stable
- With no args: list subcommands (multi-command CLI) or show help (single-command CLI)
Help
mycli --help— top-level helpmycli help <subcommand>— subcommand helpmycli <subcommand> --help— same as above- If run with missing required args, show concise help + 1-2 examples + "use --help for more"
- Examples are the most-read section — lead with them
- Include flag types, defaults, and allowed values for finite sets
Output Stability Contract
Stdout is a public API. Breaking changes to stdout format are breaking changes to the CLI.
| Change | Impact |
|---|---|
| Adding new optional JSON fields | Safe (additive) |
| Adding new subcommands | Safe |
| Adding new flags with preserving defaults | Safe |
| Removing or renaming flags | Breaking |
| Removing or renaming JSON fields | Breaking |
| Changing exit codes | Breaking |
| Changing default behavior | Breaking |
| Changing human-readable output | Usually OK (not a contract) |
When in doubt, add alongside — don't modify. Deprecate with stderr warnings before removing.
Anti-Patterns
| # | Anti-Pattern | Why It's Wrong |
|---|---|---|
| 1 | Mixing data and diagnostics on stdout | Breaks every pipe: mycli list | jq . fails if warnings are on stdout |
| 2 | Colors/ANSI in piped output | ANSI sequences corrupt downstream parsing. Check isatty(stdout) + NO_COLOR |
| 3 | Interactive prompts with no flag bypass | Agents can't type 'y'. Every prompt needs --yes/--force. Non-TTY without bypass = hang |
| 4 | Printing nothing on success | Silence is ambiguous — show brief confirmation. Offer -q for scripts that want silence |
| 5 | Designing for humans OR machines, not both | Detect context (TTY vs pipe), adapt automatically |
| 6 | Output that doesn't guide the next action | Every output is a signpost: success = next command, failure = fix command |
| 7 | Breaking existing CLI contracts | Flag names, exit codes, output shape are contracts. Add alongside, never modify |
| 8 | console.log anywhere except the CLI adapter |
Handlers must return data; only the presentation layer writes to streams |
| 9 | Handlers that exit the process directly | Let the entry point decide. Handlers return errors as data |
| 10 | Non-zero exit without stderr explanation | Scripts need both the code and the reason |
| 11 | Verbose default output | A single test run can generate 419KB. Support --fields, --quiet, --json |
Verification Checklist
After designing or reviewing a CLI:
- stdout has ONLY data; stderr has everything else
- Every command supports
--jsonwith consistent envelope - Exit codes are semantic and documented in
--help - Every prompt has a
--yes/--force/--flagbypass - Errors include: code, message, fix suggestion
-
--dry-runavailable for mutating commands - Progress/spinners go to stderr, never stdout
-
NO_COLOR,TERM=dumb, and--no-colorrespected - Piped output contains zero ANSI escape codes
- Success output includes next-action guidance
- Existing flags, exit codes, output fields never removed or renamed
- JSON schema is versioned (additions safe, removals breaking)
- Config follows flags > env > project > user > defaults
- Secrets accepted only via files/stdin/env, never via flags
- Startup < 500ms, print something in < 100ms
- Ctrl-C exits fast with bounded cleanup
-
--helpincludes 2-3 realistic examples - Human output is grep-parseable (flat rows, no table borders)
Quick Reference
Stream Routing
stdout ← data, results, JSON, NDJSON
stderr ← progress, spinners, warnings, errors, debug, prompts
Format Hierarchy
Default (TTY) → colors, tables, formatted text
--plain → one record per line, stable, grep-friendly
--json → structured JSON, versioned schema
--format ndjson → streaming, one JSON object per line
Exit Codes
0 success
1 domain failure
2 invalid usage
75 temporary failure (retry)
78 config error
130 SIGINT (Ctrl-C)
143 SIGTERM
Config Precedence
flags > env vars > project config > user config > defaults
Flags Cheat Sheet
-h --help Show help
--version Print version
-q --quiet Less output
-v --verbose More output
-d --debug Diagnostic output
-f --force Skip prompts
-n --dry-run Preview changes
--json Structured JSON
--plain Grep-friendly text
--no-color Disable color
--no-input No prompts
-o --output Output file
--fields Select columns
Source: citypaul/.dotfiles — distributed by TomeVault.
先判断是否适合
作者设计意图
作者的方法与取舍
边界和复核