# Machine-readable output format

- **Pattern:** `ab-000646` (`cli-quality.io-behavior.machine-output`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000646
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000646)

## Why it matters

A CLI without `--json` output is a CLI that cannot be scripted. Users pipe your tool into `jq`, feed it into CI, wrap it in Makefile recipes, and compose it with other tools — and all of that requires structured, decoration-free output on stdout. When `mytool list` prints a pretty table with emoji dividers, the user has to write a regex parser in bash to extract one field. They will not. They will switch tools. Mixing status messages into JSON output (`Loading...\n{...}`) is worse — it silently breaks `| jq` without any error.

## Severity rationale

High because missing machine-readable output blocks CI, automation, and composition with Unix pipelines.

## Remediation

Add a `--json` flag to every command that produces data, write JSON to stdout with no prefix or decoration, and route status/progress to stderr. Example in `src/cli/commands/list.ts`:

```ts
if (opts.json) {
  process.stdout.write(JSON.stringify(items) + '\n')
} else {
  console.log(formatTable(items))
}
```

Confirm with `mytool list --json | jq .`.

## Detection

- **ID:** `machine-output`
- **Severity:** `high`
- **What to look for:** List all commands that produce output. For each, check for a `--json`, `--format json`, `--output json`, or `--format=json` flag on commands that produce data output. Verify that the JSON output is valid JSON (not pretty-printed log-style text), written to stdout, and contains all the data from the human-readable output. Check that JSON mode suppresses non-JSON decorations (headers, dividers, color codes).
- **Pass criteria:** Commands that produce data output support at least one machine-readable format (JSON preferred). The machine-readable output is valid, parseable, and written cleanly to stdout without decorations or status messages mixed in — at least 1 machine-readable output format (--json, --csv, or --format) available. Report: "X output commands found, Y support --json or equivalent machine-readable format."
- **Fail criteria:** No machine-readable output option exists for commands that produce structured data, or `--json` flag exists but output contains non-JSON text mixed in.
- **Skip (N/A) when:** The CLI produces no structured data output — it only performs actions (e.g., `mytool deploy` or `mytool init`). All checks skip when no CLI entry point is detected.
- **Detail on fail:** Quote the actual output format showing the missing machine-readable option. Example: `"'list' command outputs a formatted table but has no --json or --format option for scripting"` or `"--json flag exists but output includes 'Loading...' text before the JSON object"`
- **Remediation:** Machine-readable output makes your CLI scriptable:

  ```ts
  program
    .command('list')
    .option('--json', 'Output as JSON')
    .action(async (opts) => {
      const items = await fetchItems()
      if (opts.json) {
        process.stdout.write(JSON.stringify(items, null, 2) + '\n')
      } else {
        // human-friendly table output
        console.log(formatTable(items))
      }
    })
  ```

  ```python
  @cli.command()
  @click.option('--json', 'output_json', is_flag=True, help='Output as JSON')
  def list_items(output_json):
      items = fetch_items()
      if output_json:
          click.echo(json.dumps(items, indent=2))
      else:
          for item in items:
              click.echo(format_item(item))
  ```

Taxons: user-experience

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