CLI Styles
Draft. This page is a proposal. Its rule ids (CS-n) are provisional and may change before the page is marked stable. Only the strict style can be claimed today.
|
A style is a named contract for how a tool turns input into action. Every style has its own behaviour contract; a tool declares which style each command uses, and users can rely on that contract.
The key words MUST, SHOULD and MAY follow BCP 14unchecked.
Rules for all styles
- CS-1
-
Strict is the default. A tool that does not declare a style is strict, and MUST meet every rule in CLI Dispatch.
- CS-2
-
A non-strict style MUST be announced: declared in the tool’s help, in reference docs, and in the
--jsonresult ("style": "<name>"). - CS-3
-
A non-strict style changes how a command’s arguments are resolved (for example the target of
install), never the tool’s top-level dispatch. Unknown top-level command tokens remain CD-1 errors in every style. - CS-4
-
No style MAY silently fetch, build or run anything. Each style only changes how a request is resolved, and always reports the resolution.
- CS-9
-
A CLI MUST declare exactly one style for its whole command surface, and MUST NOT mix styles across its commands or subcommands. A tool that wants the other style’s behaviour MUST ship it as a separate tool.
The strict and resolver styles are philosophically incompatible: one promises that input is taken literally or rejected, the other promises that loose input is interpreted. A tool that mixes them leaves the user unable to predict which promise applies to the command in front of them, which breaks their mental model of the whole tool.
- CS-10
-
The resolver (natural-language) style SHOULD be used only by tools whose name is a verb. A tool named with a noun SHOULD use the strict style, with verbs as its subcommands.
Implicit dispatch reads well when the tool name is the verb:
install foo,open fooandmake targetare sentences, with the leftover token as the verb’s object. A tool named with a noun, such asgit,cargoorredub, puts the verb in the first-argument slot. Filling that slot with an object, as inredub foo, leaves the command with no verb, so the user has to guess whetherfoois a verb or an object. That guess is the mental-model violation. Because CS-9 gives a tool one style for its whole surface, the choice is made once, per tool, and the tool’s name is the first thing to check.A name’s grammatical role is judged by its usage role to the people who use the tool, not by its spelling or origin. To downstream developers
dubis a noun, the tool they invoke with verb subcommands such asdub buildanddub run, even though it happens to look like an English verb.
Strict style (default)
The contract is CLI Dispatch as written: a closed command table, unknown input rejected with exit 2, no implicit resolution.
Resolver style (natural-language)
A resolver-style tool accepts a loose name or phrase and resolves it to a concrete target, for example install ripgrep searching several system and language package managers.
- CS-5
-
The tool MUST print what it resolved before acting: each candidate with its source (package manager or registry), exact name, version and publisher where known.
- CS-6
-
When more than one candidate matches, the tool MUST print disambiguation output and MUST NOT act until the user picks one. Non-interactive runs (no TTY, CI,
--json) MUST exit2with the candidate list instead of picking. - CS-7
-
Even with a single candidate, the tool MUST ask for confirmation before any fetch, install or run, unless the user passed an explicit flag such as
--yestogether with a fully qualified target (for examplewinget:BurntSushi.ripgrep.MSVC). - CS-8
-
Resolution MUST be reproducible from its output: the printed resolution includes the fully qualified strict command that does the same thing, so the user can run it directly next time.
Example:
$ ix install ripgrep
style: resolver (install)
3 candidates for 'ripgrep':
1) winget BurntSushi.ripgrep.MSVC 14.1.1
2) scoop ripgrep 14.1.1
3) cargo ripgrep 14.1.1 (builds from source)
choose 1-3, or rerun with a qualified name (e.g. ix install winget:BurntSushi.ripgrep.MSVC):
Prior art in OpenShellOrg
No OpenShellOrg repository yet describes a universal install <anything> tool.
The closest existing idea is nu-require Install Offer, a one-shot install hint (winget / brew / docs) when Nushell is missing, which already follows CS-4 in spirit: fail loudly rather than degrade silently.
The essay Intents, not shell translationunchecked (linked from Ecosystem) is related background on intent-level commands.