| name | create-cli |
| description | Use when creating or upgrading a repo-owned CLI, bootstrap script, or command runner. Define the command surface, install/update contract, structured output, dry-run and doctor behavior, distribution path, and quality gates before spreading ad hoc shell or Python entrypoints. |
Create CLI
Use this when the task is to add, refactor, or normalize a command-line tool in
charness or another repo that charness is helping with.
Borrow Jef Raskin-style discoverability and modelessness when shaping the
surface: make the next command obvious, keep state shifts explicit, and avoid
forcing operators or agents to memorize hidden lifecycle state.
Bootstrap
Read the smallest current surface that explains how the repo already ships and
tests commands.
sed -n '1,220p' README.md
sed -n '1,220p' docs/handoff.md 2>/dev/null || true
rg -n "argparse|click|typer|cobra|urfave|commander|subcommands|--detail|--help|dry-run|doctor|install|update" .
find . -maxdepth 3 \\( -name '*.sh' -o -name '*.py' -o -name 'main.go' \\) | sort
If the CLI already exists, inspect the entrypoint and one representative test
before changing behavior.
Missing-binary handling follows
../../shared/references/binary-preflight.md when the bootstrap or validation
steps call tools outside the baseline shell surface.
Workflow
- Define the operator contract first.
- who runs the CLI: user, maintainer, CI, agent
- what must be deterministic vs advisory
- what state must survive for a later agent or operator
- Shape the command surface.
- start with the user's workflow journey, not the implementation modules;
follow
references/intent-first-grammar.md to pick journey verbs first,
keep lifecycle verbs (init, doctor, update, reset, uninstall,
version) on their own axis, and decide which surface (binary vs agent
skill) owns each command before locking names
- stable nouns and verbs
- for multi-command CLIs, prefer a subcommand-first surface and follow
references/command-conventions.md for canonical lifecycle verbs and
version/help flag conventions
- one obvious install/bootstrap path
- explicit
doctor, update, reset, or uninstall commands when the
product owns lifecycle state
- if install materializes one host-visible target, treat that target as the
canonical lifecycle surface instead of inventing a registry first
- if the product needs one command that refreshes both itself and tracked
external/runtime surfaces, keep that aggregate path product-owned, such as
update all, instead of leaking harness-internal vocabulary
- for Charness-style commands whose primary caller is an agent, emit YAML by
default and use
--detail for the full evidence payload; for human-first
CLIs or third-party integrations, preserve the product's established
concise default and native structured-output mode
- if agents may call the CLI repeatedly, define at least one cheap read-only
startup probe such as
version, --version, or a lightweight inspect
command; keep that probe stable enough for standing latency measurement
- for workflow commands whose primary caller is another agent, explicitly
decide whether a prep/execute artifact split is the more stable contract
than a single thick command; see
references/command-surface.md
prep/execute split section
- public subcommands should expose a no-side-effect
--help contract unless
there is a strong documented reason not to
- mutating subcommands with required positionals should reject flag-looking
positional values such as
--help before any state change
- if wrappers or agents may probe the surface, separate machine-readable
command discovery such as
commands --detail or capabilities --detail from
human help text
- if the CLI lets agents interact with an external system, define the
external capability boundary separately from parser shape; see
references/external-capability-clis.md
- human-first default stdout should stay concise; agent-first Charness-style
commands may use compact YAML by default, with full evidence behind
--detail
- reserve
-v for verbose, not version; prefer canonical version
plus optional top-level --version alias when the parser surface is
already stable
- separate binary/runtime health from repo- or install-readiness instead of
overloading one
doctor
- if agent/plugin/materialized-surface discoverability matters, give it an
explicit readiness probe rather than smuggling it into generic health
- Decide mutation rules.
- help probes, command discovery, and healthchecks stay read-only
doctor stays read-only
- lifecycle mutations should expose a dry-run or plan path unless a concrete
product reason makes preview meaningless
- install and update commands must say what they changed
- long-running mutations should show phase progress so operators can tell
what is happening before the command finishes; if the command captures
child output for a final report or JSON payload, print phase start,
bounded heartbeat dots, and phase completion to stderr so stdout stays
machine-readable when needed
- if the product manages multiple install targets, make the registry or
manifest decision explicit and say who cleans up stale entries
- if
update has a wider aggregate variant, distinguish self-update from
tracked dependency refresh in both help text and structured output
- readiness commands may depend on repo or local install state, but they
should not pretend to be generic binary health probes
- partial manual steps should still leave machine-readable breadcrumbs
- when upgrade guidance depends on install channel, persist version
provenance and define when cached latest-version checks may run
- for external-capability CLIs, keep credentials and raw requests host-side;
worker commands should emit preflight status and audit-safe metadata until
an explicit host executor is available
- Pick the smallest honest distribution contract.
- single checked-in entrypoint when possible
- one canonical bootstrap script if first install is otherwise awkward
- if agents need a zero-state bootstrap, prefer a short pasteable contract in
the entrypoint docs over telling them to fetch a remote install doc and
"follow it"
- do not pretend update is automatic unless the host really owns it
- Keep implementation boring.
- prefer stdlib argument parsing unless the repo already standardizes on a
framework
- factor shared lifecycle logic instead of copying subcommand shapes
- keep environment detection and filesystem mutation explicit
- Add the right gates from the command capability seam already named above.
- choose proof from the operator contract, command surface, mutation rules,
and distribution contract before listing gate families
- cover the gate axes per
references/quality-gates.md: parser/--help smoke,
mutating-command side-effect probe fixtures (read-only help probes,
option-looking positional rejection, dry-run/plan coverage or waiver, watched
side effects), machine-state + command-discovery JSON validation,
external-capability log redaction tests, help/healthcheck/readiness-not-conflated
checks, a command-docs drift gate, and broad-verification worktree safety
(clean git status/HEAD)
- for external-capability mutating commands, require action-shaped self-tests,
not only readiness probes; reach
provider_roundtrip per
../../shared/references/external-capability-proof-ladder.md or record the
concrete reason the round-trip cannot run in CI
- stale generated-artifact failures must name the exact regeneration command in
the failure message, not only a "stale" diagnostic
- run the repo's standing lint gate against the new CLI source before
slice-complete and record the result in the
Lint Gate closeout field; the
lint survey and field shape are owned by
../prove/references/verification-ladder.md "Lint Gate Closeout Shape" and
references/quality-gates.md
Guardrails
- Do not create a CLI only to hide unclear product boundaries.
- Do not make install, update, or reset mutate hidden files without reporting
them.
- Do not force users to reverse-engineer the source of truth for installed
state.
- Do not return prose-only output when an agent must continue the workflow.
- Do not add a framework dependency just to avoid writing small parser glue.
- Do not split install methods across multiple equally-primary paths unless the
product truly supports them.
- Do not tell an agent to fetch a remote install document and execute it
verbatim; paste the contract or give explicit commands.
- Do not run automatic update checks in CI or other non-interactive paths by
default.
- Do not guess upgrade commands when the runtime has not recorded install
provenance honestly.
References
references/intent-first-grammar.md
references/command-surface.md
references/command-conventions.md
references/install-update.md
references/version-provenance.md
references/machine-readable-state.md
references/code-shape.md
references/external-capability-clis.md
references/quality-gates.md
references/case-studies.md
../prove/references/verification-ladder.md
../../shared/references/binary-preflight.md
../../shared/references/external-capability-proof-ladder.md