# Version flag outputs version string

- **Pattern:** `ab-000640` (`cli-quality.command-structure.version-flag`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000640
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000640)

## Why it matters

Automation scripts, CI pipelines, and package managers all query `--version` to verify which release is installed before running. Without a working version flag, a script cannot confirm it's using the correct build, which leads to silent version mismatches in production. A hardcoded version string that drifts from `package.json` (or `pyproject.toml` / `Cargo.toml`) compounds the problem: tools report a version they are not. ISO 25010:2011 usability.learnability directly penalizes discoverable interfaces that omit this basic contract.

## Severity rationale

High because a missing or stale `--version` flag breaks automated upgrade checks and CI gating, causing silent version drift in production.

## Remediation

Wire the version flag directly to your package manifest so it can never drift. In commander, read from `package.json` at startup:

```ts
import { readFileSync } from 'fs'
const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
program.version(pkg.version, '-v, --version')
```

In click, pull from `importlib.metadata`:

```python
from importlib.metadata import version
@click.group()
@click.version_option(version=version('my-tool'))
def cli(): pass
```

In cobra, set the version at build time via ldflags so it never needs a runtime read:

```go
var rootCmd = &cobra.Command{Version: version}
```

## Detection

- **ID:** `version-flag`
- **Severity:** `high`
- **What to look for:** List all entry points for the CLI. For each, check that `--version` (and ideally `-v` or `-V`) outputs the version string to stdout and exits with code 0. In commander, check for `.version()` call. In yargs, check for `.version()`. In click, check for `@click.version_option()`. In cobra, check the `Version` field on the root command. In clap, check for `#[command(version)]` or `.version()`.
- **Pass criteria:** Running with `--version` outputs a version string (just the version number or `tool-name vX.Y.Z`) to stdout and exits 0. The version value should come from `package.json`, `pyproject.toml`, `Cargo.toml`, or a version constant — not be hardcoded as a duplicate string — at least 1 --version flag must output a semver-compatible version string. Report: "X entry points found, all Y respond to --version."
- **Fail criteria:** No `--version` flag is registered, or the version is hardcoded as a string literal that could drift from the package version, or `--version` writes to stderr instead of stdout.
- **Skip (N/A) when:** All checks skip when no CLI entry point is detected.
- **Detail on fail:** `"No .version() call on the commander program — --version flag not available"` or `"Version is hardcoded as '1.2.0' string literal instead of reading from package.json"`
- **Remediation:** Users and scripts need to check which version is installed. Wire up the version from your package manifest:

  ```ts
  // commander (Node.js)
  import { readFileSync } from 'fs'
  const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'))
  program.version(pkg.version, '-v, --version')
  ```

  ```python
  # click (Python)
  from importlib.metadata import version
  @click.group()
  @click.version_option(version=version("my-tool"))
  def cli():
      pass
  ```

  ```go
  // cobra (Go) — set at build time via ldflags
  var rootCmd = &cobra.Command{
      Use:     "mytool",
      Version: version, // var version string, set by -ldflags
  }
  ```

## External references

- iso-25010 usability.learnability

Taxons: user-experience, code-quality

HTML version: https://auditbuffet.com/patterns/ab-000640
