burgee

The floor

The 74 requirements every CLI on the layer meets, and who holds each — runtime, lint, or both.

Each requirement is held by the runtime (the commander-* / yargs-* extensions), by the lint plugin (eslint-plugin-cli-floor), or both. A rule with neither is a suggestion, and suggestions are not a floor. Evidence for every line is an open issue in a leading CLI library — see Research.

Discoverability

IDRequirementHolds
F1--schema prints the full command tree — commands, options, types, defaults, env bindings, examples, deprecations, exit codes — as JSONruntime
F2--help --json prints help as data; text help is rendered from that dataruntime
F3Every command declares a description and at least one single-line examplelint
F4Commands may be grouped and hidden; groups are stable in the schemaruntime

Output

IDRequirementHolds
O1--json on every command, one envelope { ok, data, error?, meta }both
O2No ANSI, spinners, redraws or prompts when stdout is not a TTY or NO_COLOR is set; FORCE_COLOR overridesboth
O3Command code writes through the output layer, never console.*lint
O4Colour via util.styleText; no chalk dependencyboth
O5stdout is flushed before every exit pathruntime

Errors and lifecycle

IDRequirementHolds
E1Exit codes are a contract: 0 ok, 1 runtime, 2 usage, 3 config, 4 cancelled, 130 SIGINTboth
E2A runtime failure never prints help; a usage error never prints a stackboth
E3Every error carries code, message, hint and, where possible, fixruntime
E4Explicit lifecycle: parse → config → validate → run → render → exit; validation failure stops the handler; async handlers are awaitedruntime
E5SIGINT restores the terminal and exits 130runtime

Values and precedence

IDRequirementHolds
V1Flags > env > config file > default, per command, without leaking env into unrelated commandsruntime
V2Any option may declare an env name; env-bound options appear in help and schemaboth
V3--explain <option> reports where each value came fromruntime
V4name, version, description come from the owning package.json, not the monorepo rootruntime
V5Reserved option names cannot be redefinedlint

Validation

IDRequirementHolds
S1Options and positionals are declared once as a schema; types and help are derivedruntime
S2Relationships are first-class: exactly-one-of, at-least-one-of, implies, conflictsruntime
S3Invalid numbers fail validation, never NaN; invalid types fail at definition timeruntime
S4- means stdin for file positionals; -- pass-through reaches child processes intactruntime

Prompts

IDRequirementHolds
P1Every prompt is backed by a flag; a flag value skips the promptlint
P2In a non-TTY the prompt becomes an error naming the flag, exit 2runtime

Deprecation and testing

IDRequirementHolds
D1Deprecating anything requires a replacement, shown in help, schema and the warningboth
D2Completions for bash, zsh, fish and PowerShell are generated statically from the schemaruntime
T1A CLI runs in-process with injected argv, env, stdin, cwd and TTY-ness, returning { code, stdout, stderr, json }runtime

Validation, continued

IDRequirementHolds
S5Every option has one declared type and one canonical camelCase key; kebab-case is derivedruntime
S6Relations are validated before choices and before the handlerruntime
S7A flag type never consumes a valueruntime
S8multiple options accept repetition and a declared separatorruntime

Values, continued

IDRequirementHolds
V6Config discovery order is fixed, documented, and shown by --explainruntime
V7extends merges deeply and resolves from the extending file's node_modulesruntime

Help

IDRequirementHolds
H1Help is rendered from the manifest onlyruntime
H2Examples are single-line and copy-pasteableboth
H3Width comes from the runtime, default 100 in non-TTYruntime
H4Command options render before global optionsruntime
H5Deprecations and env names render inlineruntime
H6Type hints are off by defaultruntime

Completions, continued

IDRequirementHolds
D3Completions never execute the CLI unless an option is marked dynamicruntime
D4Every shell script is snapshot-pinned and exercised by that shell in CIruntime
D5A Fig spec is exported from the same noderuntime

Prompts, continued

IDRequirementHolds
P3Cancellation exits CANCELLED (4), never RUNTIMEruntime

Modularity

IDRequirementHolds
M1Every command carries a groupruntime
M2The manifest is complete before any handler module loadsruntime
M3Every plugin's contributions are attributed in the manifestruntime
M4Shared options are declared once and copied per commandruntime
M5A deprecated command names its replacement in help, schema and warningboth
M6resolveCommand and runCommand are publicruntime

Packaging

IDRequirementHolds
K1Zero runtime dependencies in every layer package; hosts and UI libraries are peerslock
K2ESM only, Node 24 or newerlock
K3Node natives over packagesboth
K4An artifact gate runs on the built output before publishrelease
K5Per-package size budget, ratchetedlock
K6Weight is paid per import: compatibility and host quirks live behind their own specifiers, never behind a runtime flaglock

Compatibility

Every claim about a host is graded by that host's own test suite, so "compatible" is a number rather than an adjective. The rate is published on every release.

IDRequirementHolds
C1Every package declares a supported host range; the host's own suite runs against it at every supported majorCI
C2A compatibility front-end is graded by the host's own suite through a one-line shim; the rate is published per releaseCI
C3Every package is tested on every Node LTS in its engines range, across Linux, macOS and WindowsCI
C4Every intentional divergence has an id, a written reason, and a test asserting it — an unlisted failure is a buglock
C5Pass rates ratchet; lowering one requires editing the baseline with a reasonCI
C6Vendored suites record their upstream commit; a scheduled job opens a pull request when the count changesworkflow

Benchmarks

Four axes, because there are four kinds of public claim. Every number the project cites anywhere links back to the generated benchmarks page.

IDRequirementHolds
B1Agent cost: tokens, turns and success per task, layer on versus offband
B2Performance: cold start p50/p95 over 30 or more spawns, always including a bare-node floor rowband
B3Compatibility: per-host pass rate, read from the oracle, never recomputedband
B4Weight: bundled size per entry point against a published target; a core-only import pulls zero front-end bytesband
B5Every axis emits one JSON shape, so one collector reads all of themlock
B6Performance, compatibility and weight gate every pull request; agent cost runs weeklyCI
B7Every public number links to the generated benchmarks pagelock

Agent interface

The manifest already carries everything an MCP tool definition needs. These requirements turn it into a served interface rather than a document.

IDRequirementHolds
N1--mcp serves the CLI over MCP stdio; tool definitions are generated from the manifest, never hand-writtenruntime
N2A command appears as a tool only if it opts in; destructive commands default to absentboth
N3Zero runtime dependencies: JSON-RPC over stdio against node:readlinelock
N4Tool results are the standard envelope, so MCP and --json callers see identical payloadsruntime
N5--mcp implies non-TTY: no prompts, no colour, structured errorsruntime

On this page