3a. Parameter rules
Source 03a-parameters.md
These apply to every CLI and to the router. They keep calls readable in logs and examples.
- No single-character aliases.
-ifor-idis not allowed. Every parameter has exactly one name, and it is a word. A reader of a log line should not need a lookup table. - One canonical spelling per parameter, across all CLIs. Pick one word for a concept and use it everywhere.
-output, not-format.-id, not-identifierin one CLI and-keyin another. The shared names live in the registry below. A CLI may not accept a synonym alongside the canonical name. - Abbreviations only where obvious.
-envis fine. A name that a new reader would have to guess is spelled out. The CLI author judges what is obvious. Once a name is used by more than one CLI it goes in the registry, and the registry spelling is the only one accepted (an abbreviation is not accepted next to its long form, see rule 2). - No implicit behaviour where it affects security. A small set of parameters is sensitive (see below). A sensitive parameter must be passed explicitly on every call: no default, no “current context”, no env var, no config. If it is missing the command fails with exit code 3 and names the parameter. Other parameters, including the ones that choose the target (environment, tenant, organization, project, namespace), follow the normal precedence of section 9: a setting, overridden by an env var, overridden by a parameter.
- Prefer the single dash prefix.
-name valueis the encouraged form, and all docs, examples,-helptext, and logs use it. The traditional--name valueis discouraged but not forbidden. A CLI may accept it, and the spec does not require it to. This is a strong convention, not a hard rule. - Bare
--marks the boundary between parameters and a body. Everything after it is passed on untouched and is never read as a parameter. Use it for a command to pass through (for example a futurerunverb:tracker run -id T-12 -- git status). Accepted by every CLI. - Standard input is
-stdin. A boolean parameter that says “read the input body from stdin”. A bare-as a value never means stdin.-stdinand-filecannot be given together (input error). A CLI that takes a body documents it indescribe. - Names are singular. Commands and parameters use singular nouns:
task, nottasks.-field, not-fields.-id, not-ids. To give several values, repeat the parameter (-id A -id B), wheredescribeallows it. This covers command and parameter names. It does not cover keys or text inside output (changes,next, anditemsare data). Folder and file names are singular too (section 9).
Syntax details
- Value form: a space between name and value (
-name value) is the standard, and all docs, examples, and logs use it. The spec makes no rule about-name=value. A CLI may accept it or not. - Names are lowercase, with hyphens between words (
-dry-run,-no-input). - Boolean parameters are given by name alone (
-quiet). There is no-quiet=false. To turn one off, leave it out. - Repeated parameters (
-id A -id B) are allowed only wheredescribesays so. Otherwise it is an input error.
Sensitive parameters (rule 4)
-confirmis always sensitive. It is never taken from config, env, or a default.- Account or identity is sensitive on any command that queries or changes security elements: access, policy, roles, permissions, and the like. The caller must say explicitly which account or identity the command acts as or on. [The exact parameter name goes in the registry when the first such CLI is designed.]
- Nothing else is sensitive by default. A CLI that wants to mark another parameter sensitive says so in
describeand explains why. describemarks sensitivity per command, so a permission system and an agent can see it without running the command.
Scope parameters are not sensitive. -env, tenant, organization, project, and namespace are often needed for a command to work at all. They resolve in the usual order (section 9): a setting in config, overridden by an env var, overridden by a parameter. If none gives a value, the command fails with invalid_input, names the parameter, and the fix says how to set it. describe marks these required.
- Because the value may come from a setting or an env var the caller did not type, a mutation shows the resolved value of every scope parameter in its
changesoutput (section 6), so the human sees where the change will land.
Parameter registry. It starts with the list below and grows as CLIs are designed. A CLI that needs a shared name adds it here in the same change.
| Name | Meaning | Notes |
|---|---|---|
-id |
exact ID of one resource | never a name or wildcard |
-output |
result format | text, json, yaml, md. -format is not accepted |
-field |
limit the returned fields | repeat for several: -field id -field status |
-verbose |
extra human-readable diagnostics on stderr | boolean, no alias, see section 12 |
-env |
target environment | a scope parameter (setting, env var, or parameter). Canonical spelling is -env, not -environment |
-confirm |
confirm a mutation | sensitive, always explicit. Boolean, given by name alone |
-dry-run |
preview a mutation | |
-if-version |
precondition on version | |
-lock-timeout |
seconds to wait for a lock | whole seconds, 0 fails at once |
-file |
read input from a file | not with -stdin |
-stdin |
read input body from standard input | boolean |
Consequences
- No separate
-jsonshortcut. Use-output json. This follows rule 2. - Standard single-letter flags from clig.dev (
-h,-q,-v,-f,-n) are not used. - Many argument parsers assume
--namefor long names and do not support single-dash long names. That is accepted. It is a cost to the implementer, who handles it in whatever way suits their language. It is not a reason to drop the single-dash convention.