ax-check rule
AXC-C012: Version output is not plain
--version did not print a version number on its own first line, so a script cannot read it reliably.
ax-check is a checker being prepared for release. This page documents the rule ahead of that release; see all 50 rules.
| Severity | info |
| Kind | Observed. Depends on the program and environment at run time. |
| Mode | ax-check probe-cli |
| Applies to | Command-line programs, run as a subprocess |
| Pattern tags | non-interactive, drift |
| Fix in one line | Make --version print just the version, for example "1.4.2", and exit 0. |
--version either failed, printed no version number on its first line, or printed more than three lines. A script that wants to know which version it is talking to cannot read it reliably.
What it checks
The version probe runs <cmd> --version. The rule fires when any one of these is true: the exit status is not 0, the first line has no version number of the form digits.digits (for example 1.4), or the output is longer than three non-blank lines. A probe that timed out is skipped, because AXC-C001 reports it. Output on stderr is used when stdout is empty.
Why it matters
Versions are how instructions and tools stay in step. An agent reads a skill or an AGENTS.md file that says “use --status with invoicer 1.4 or later”, then needs to check what is installed. The GNU Coding Standards say every program should support --version and --help. When the output is a banner, a changelog, or a prompt to update, the agent has to guess which line holds the number. This is related to drift: the ax-check drift command compares claims in documents against what the program really reports.
Public issues show this is not only a theoretical concern. cloudflare/cf issue #105 listed --version not being machine-readable among its complaints, and the --version part was later fixed. This is context, not a measure of how common the problem is.
How to fix
Make --version print one short line with the program name and number, or just the number, and exit 0. Put the long banner, licence text and update notices elsewhere.
Example
Before
$ invoicer --version </dev/null; echo $?
___ _ ___ ___ ___ ___ ___
|_ _| | _ \/ _ \_ _/ __| __|
| || | / (_) | | (__| _|
|___|_|_|_\\___/___\___|___|
Build: stable
A new release is available!
Run "invoicer upgrade" to update.
0
After
$ invoicer --version </dev/null; echo $?
invoicer 1.4.2
0
A Node fix:
if (process.argv.includes('--version')) {
process.stdout.write(`invoicer ${pkg.version}\n`);
process.exit(0);
}
How ax-check detects it
ax-check looks for the pattern digits, a dot, digits in the first line, so 1.4.2, invoicer 1.4.2 and v2.0 all pass. It counts the non-blank lines and allows up to three, so a short licence line is fine. It does not check that the number is correct. It also does not check pre-release suffixes.
Known false positives: a program that identifies itself by a date or a single integer, for example build 20260901. Silence the rule with --disable AXC-C012 if you use such a scheme on purpose.
To reproduce by hand: invoicer --version </dev/null; echo $?, then count lines with invoicer --version </dev/null | grep -c ..
Safety note: This rule uses the default --version probe. probe-cli executes your program under your own OS account. The temporary working directory and HOME it uses are not a sandbox: the program can still read and write anything your account can, and use the network. Probe a CLI you have not reviewed only inside a container or a throwaway virtual machine. Run ax-check probe-cli --dry-run -- invoicer first to see the probes that would run, and see the “Probe safety” section of the ax-check README for what is and is not isolated.
Sources
- Guideline: GNU Coding Standards, Command-Line Interfaces. https://www.gnu.org/prep/standards/html_node/Command_002dLine-Interfaces.html . Says every program should support
--versionand--help. - Vendor issue: cloudflare/cf issue #105, “Output for scripts and agents: empty stdout with exit 0, –version not machine-readable, agent detection changes nothing”. https://github.com/cloudflare/cf/issues/105 . Context only; the
--versionpart was later fixed.
Related evidence
Records in the AX evidence register that share a pattern tag with this rule. A shared tag means the record is about the same pattern, not that it tests this rule. Read the evidence class before the number.
- EV-0036: A CLI exits 0 when a destructive command is refused (Independent measurement). Cloudflare's cf CLI documents that in a non-interactive session a destructive command without --force prints 'Aborted.' and exits with status 0, and a public issue reproduces this for workflows delete.
- EV-0039: Launch post and documentation disagree on agent output format (Independent measurement). Cloudflare's cf launch post says JSON output is 'condensed for agents', but the cf documentation says JSON output is indented whether or not output is a terminal, and a public issue reports byte-identical output with an agent detected.
- EV-0040: Agent skills recommended a package that does not exist (Vendor measurement). Merged pull requests in Vercel's agent plugin repository corrected skill instructions that recommended an npm package that is not published, and plugin guidance that advertised deployment cards the production MCP server does not expose.
