build-cli
Skill7 starsChanged 15 days agoMITView on GitHub
Use when creating or extending a command-line tool in TypeScript, Go, Python or Rust — subcommands, typed args, config precedence, stdout/stderr split, --json, exit codes, NO_COLOR/TTY handling, --dry-run, and spawn-the-binary tests.
- Installs packages
4 other projects use a version of this.
Adopted by
Most recently taken up by
- VelimirMueller/claude-skillsword for word, first seen Oct 11, 2026
- katanemo/archgwtheir own version, first seen Oct 8, 2026
- katanemo/planotheir own version, first seen Oct 8, 2026
- IvanMurzak/Unity-MCPtheir own version, first seen Mar 13, 2026
Other versions4 projects use a version of this.
Word for word · 1
- VelimirMueller/claude-skills★ 7100% same
Edited · 0
None found.
Wrote their own version · 3
- katanemo/archgw★ 7.1ksame name
- katanemo/plano★ 7.1ksame name
- IvanMurzak/Unity-MCP★ 4.6ksame name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository156 other files it gives its agents.
- skills/swift/swiftui-design-principles/AGENTS.mdAGENTS.md
- skills/swift/ios-code-audit/CLAUDE.mdCLAUDE.md
- skills/swift/swift-focusengine-pro/llms.txtllms.txt
- build-llm-seamSkill
- build-mcp-serverSkill
- build-rag-pipelineSkill
- secure-llm-featuresSkill
- set-up-llm-evalsSkill
- build-nextjs-backendSkill
- build-supabase-edge-functionSkill
- configure-backend-testsSkill
- design-http-apiSkill
- harden-backendSkill
- scaffold-fastapi-serviceSkill
- scaffold-go-serviceSkill
- scaffold-hono-serviceSkill
- secure-supabase-rlsSkill
- set-up-backend-authSkill
- set-up-background-jobsSkill
- set-up-databaseSkill
- set-up-nextjs-supabase-authSkill
- set-up-observabilitySkill
- set-up-supabaseSkill
- release-cliSkill
- set-up-dev-toolchainSkill
- audit-securitySkill
- audit-toolchainSkill
- extend-skillsetSkill
- promote-releaseSkill
- set-up-stack-profileSkill
- write-commit-messagesSkill
- write-pull-requestsSkill
- analyze-complexitySkill
- apply-algorithmsSkill
- apply-design-patternsSkill
- apply-design-principlesSkill
- apply-solidSkill
- choose-data-structureSkill
- debug-systematicallySkill
- enforce-dependency-ruleSkill
- refactor-safelySkill
- slice-and-estimateSkill
- write-clean-testsSkill
- write-readable-codeSkill
- clean-frontend-scaffoldingSkill
- configure-accessibilitySkill
- configure-analyticsSkill
- configure-ciSkill
- configure-error-trackingSkill
- configure-lintingSkill
- configure-test-stackSkill
- configure-typescriptSkill
- create-moduleSkill
- optimize-performanceSkill
- scaffold-frontend-projectSkill
- set-up-authSkill
- set-up-design-systemSkill
- set-up-document-headSkill
- set-up-error-boundariesSkill
- set-up-feature-flagsSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
3 rules. 0 are common, 2 are distinctive, and 1 is very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
2
Distinctive
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 31
No CLI yet → full scaffold (steps 3-7).
- Very specific: line 51
Run the live check first (npm view commander version, go list -m -versions github.com/spf13/cobra, PyPI JSON, crates.io), then add …
- Distinctive: line 87
Run the real binary, not the handler:
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Build CLI
A CLI is called by people and by scripts. This skill makes the same tool work for both: one entry, subcommands, typed arguments, a fixed config order, data on stdout, diagnostics on stderr, --json with a stable schema, documented exit codes.
Rules with reasons: cli-ux.md. Library choice and structure: cli-patterns.md. Tested code per language: cli-examples.md. Versions: stack-versions.md (verify live first, per version-protocol).
1. Audit current state
Change nothing yet. Read .claude/stack-profile.md (then ~/.claude/stack-profile.md); if absent, detect.
cat .claude/stack-profile.md 2>/dev/null | sed -n '1,30p'
ls package.json go.mod pyproject.toml Cargo.toml 2>/dev/null # language
grep -nE '"(commander|citty|yargs|cac|clipanion)"' package.json 2>/dev/null
grep -rnE 'spf13/cobra|urfave/cli|alecthomas/kong' go.mod 2>/dev/null
grep -nE '(typer|click|cyclopts|argparse)' pyproject.toml 2>/dev/null
grep -nE '^(clap|argh|lexopt)' Cargo.toml 2>/dev/null
ls src/cli* src/main.* cmd/*/main.go src/*/cli.py 2>/dev/null # existing entry
grep -rnE 'NO_COLOR|isatty|IsTerminal|isTTY|--json' src cmd internal 2>/dev/null | headRecord: language, existing parser (keep it, see step 3), whether an entry file exists, whether --json, exit codes, config loading, tests-by-spawning are present. A monorepo with several languages: build the CLI in the language of the package that owns it; one question only if two candidates remain.
2. Decide what to do
- No CLI yet → full scaffold (steps 3-7).
- CLI exists, contract gaps → apply only the missing seams (step 5). Name each gap you will close.
- Contract met (stdout/stderr split, exit codes documented,
--jsonschema, spawn tests) → say "already in place" and stop. - Existing parser differs from the default (Click, yargs, urfave v2, clap 3) → keep it. Do not migrate inside this task.
3. Detect the track
Pick from languages in the profile or from step 1:
| Language | Parser | Config | Tests |
| TypeScript | commander 15, ESM, Node >= 22.18 | smol-toml + env-paths | Vitest spawning dist/cli.mjs |
| Go | cobra, entry cmd/<name>/main.go, Run(args, out, err) int seam | go-toml/v2 | go test on Run + one built-binary test |
| Python | typer, uv_build, entry <pkg>.cli:main | tomllib + platformdirs | pytest + subprocess on python -m <pkg> |
| Rust | clap derive, thiserror | toml + serde + dirs | assert_cmd + insta help snapshot |
A profile with several languages gets one CLI per package, each following its own row. Lint and format come from the profile's lint_format.
4. Install only what is missing
Run the live check first (npm view commander version, go list -m -versions github.com/spf13/cobra, PyPI JSON, crates.io), then add dependencies with the package manager from the profile.
pnpm add commander env-paths smol-toml && pnpm add -D tsdown vitest # TypeScript
go get github.com/spf13/cobra github.com/pelletier/go-toml/v2 golang.org/x/term # Go
uv add typer platformdirs && uv add --dev pytest # Python
cargo add clap --features derive,env,wrap_help && cargo add serde --features derive && cargo add toml thiserror dirs # RustTypeScript: runtime libraries go in dependencies (tsdown bundles devDependencies). Python: also set requires = ["uv_build>=<current>,<next minor>"].
5. Generate the seams
Four seams per CLI, copied from cli-examples.md and renamed. Each owns one concern; nothing else touches it.
exit— an enum of codes (0 ok, 1 failure, 2 usage, domain codes from 3) and one typed error carrying a code and a hint.output— the only writer to stdout/stderr. Decides colour (NO_COLOR,TERM=dumb, TTY per stream) andinteractive()(stdin and stdout TTY,CIunset). Secrets are never passed to it.config— builds a typedConfigonce: flags > env (<NAME>_<KEY>) > project.<name>.toml> user$XDG_CONFIG_HOME/<name>/config.toml> defaults. Unknown keys and bad values fail with exit 2.cli(entry) — builds the parser, runs the command, mapsCliErrorto its code, prints throughoutput. The only place that exits.
Commands are thin: parse, call domain code, print through output. Then, for every command:
- Global flags
--json,--quiet,--verbose,--no-colorvalid before and after the subcommand;--version; exit codes listed in the root--help. --jsonprints one document{"schema": 1, ...}on stdout, nothing else.- Destructive commands:
--dry-run(shared planning step, final write skipped) and--yes; prompt only when interactive, else fail with exit 2 naming the flag. - Long options first; the same flag means the same thing everywhere.
6. Wire it
- Entry point: TypeScript
"bin": {"<name>": "./dist/cli.mjs"}+tsdown; Python[project.scripts]; Gocmd/<name>/main.go; Rust[[bin]](default). - Task verbs (
dev,test,build,check) go through the repo's runner: see set-up-dev-toolchain. Release: release-cli. - README: install, quick start, the config precedence table, the exit-code table, the JSON schema version. Link to
--help, do not copy it. - Completions: cobra and Typer have them built in, clap adds
clap_complete; seecli-patterns.md.
7. Verify
Run the real binary, not the handler:
mycli --help; echo "exit=$?" # exit=0, lists exit codes
mycli list --json | jq -e '.schema == 1' # stdout is pure JSON
mycli list --json >/dev/null 2>err.txt; test ! -s err.txt && echo clean # nothing leaked to stderr
mycli list --bogus >/dev/null; echo "exit=$?" # exit=2, stdout empty
NO_COLOR=1 mycli delete missing 2>&1 | grep -c $'\x1b' # 0 escape sequences; the command exits 3
mycli delete x </dev/null; echo "exit=$?" # not interactive: no hang
hyperfine --warmup 3 'mycli --version' # under ~100 msThen the project check (mise run check, pnpm test, go test ./..., uv run pytest, cargo test) and the spawn tests from cli-examples.md pass. Expected: all exit codes as documented, --help snapshot committed.
References
- cli-ux.md: the rules and their reasons (streams, exit codes, JSON schema, config order, colour/TTY, dry-run, errors, help, speed, tests).
- cli-patterns.md: library choice per language, seams, completions, prompts.
- cli-examples.md: the tested reference CLI in all four languages.
- ../_shared/stack-versions.md: verified versions.
- ../../core/_shared/engineering-principles.md, ../../core/_shared/security-baseline.md: seams, secrets.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
Reviews can't be read right now.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

