---
title: @specdiff/cli
description: The specdiff command — compare documents, list rules, and gate CI on breaking changes.
url: https://pr-1-7abef52380a8.thally.app/specdiff-cli
---

# @specdiff/cli

The specdiff command — compare documents, list rules, and gate CI on breaking changes.

`@specdiff/cli` provides the `specdiff` command for local checks, CI
pipelines, and scripts.

```bash
npm install -D @specdiff/cli
npx specdiff --help
```

## Commands

```text
specdiff <before> <after> [options]   Compare two documents (.json, .yaml, .yml)
specdiff rules [--json]               List every rule with its default severity
specdiff explain <code>               Describe one rule and how to remediate it
specdiff --help | --version
```

## Comparison options

| Flag | Values | Default | Description |
| --- | --- | --- | --- |
| `--format` | `text`, `json`, `markdown` | `text` | Report format. |
| `--fail-on` | `breaking`, `warning`, `info`, `none` | `breaking` | Exit `1` when a change at or above this severity exists. |
| `--ignore-rule <code>` | any rule code, repeatable | | Drop changes produced by the rule. |
| `--ignore-path <pointer>` | JSON pointer prefix, repeatable | | Drop changes at or beneath the pointer (e.g. `#/paths/~1internal`; the leading `#` is optional). |
| `--kind` | `auto`, `openapi`, `json-schema` | `auto` | Force the document kind. `auto` treats a document with an `openapi` key as OpenAPI. |
| `--direction` | `request`, `response`, `neutral` | `neutral` | Direction for plain JSON Schema diffs (ignored for OpenAPI). |
| `--output <file>`, `-o` | path | | Write the report to a file instead of stdout. |
| `--no-color` | | | Disable ANSI colour in text output. |
| `--color` | | | Force colour on (colour is auto-detected via TTY by default). |

Input files are parsed as JSON or YAML by extension; unknown extensions try JSON
first, then YAML.

## Exit codes

| Code | Meaning |
| --- | --- |
| `0` | No change at or above the `--fail-on` threshold. |
| `1` | Threshold exceeded. |
| `2` | Usage error (unknown flag, missing argument, unknown rule code). |
| `3` | An input document could not be read or parsed. |

## Examples

```bash
# Compare two OpenAPI specs, fail on breaking changes (default)
npx specdiff before.yaml after.yaml

# Markdown report for a pull-request comment, never fail
npx specdiff before.yaml after.yaml --format markdown --fail-on none

# JSON Schema pair, machine-readable output
npx specdiff user-v1.json user-v2.json --format json --fail-on none

# Ignore description-only changes
npx specdiff before.yaml after.yaml --ignore-rule description-changed

# Ignore everything under an internal endpoint
npx specdiff before.yaml after.yaml --ignore-path "#/paths/~1internal"

# What does a rule mean?
npx specdiff explain required-parameter-added

# List all rules as JSON
npx specdiff rules --json
```

## Programmatic use

`@specdiff/cli` exports `runCli` so other tools can embed the CLI without
spawning a subprocess:

```ts
import { runCli, EXIT_CODES, type CliIo } from "@specdiff/cli";

const io: CliIo = {
  stdout: (text) => process.stdout.write(text),
  stderr: (text) => process.stderr.write(text),
  cwd: process.cwd(),
  isTty: process.stdout.isTTY === true,
};

const code = await runCli(["before.yaml", "after.yaml", "--format", "json"], io);
process.exitCode = code;
```

### Exported API

| Export | Description |
| --- | --- |
| `runCli(argv, io)` | Main entry point. Returns the exit code. |
| `parseArgs(argv)` | Parses argv into a `ParsedCommand`. Throws `UsageError` on malformed input. |
| `loadDocument(filePath, cwd)` | Reads and parses a JSON or YAML file. |
| `parseDocumentText(text, fileName)` | Parses text as JSON or YAML based on file extension. |
| `EXIT_CODES` | `{ ok: 0, thresholdExceeded: 1, usage: 2, inputError: 3 }` |
| `HELP_TEXT` | The full help string printed by `--help`. |
| `createDocumentLoadError(filePath, message)` | Creates a `DocumentLoadError`. |
| `isDocumentLoadError(error)` | Type guard for `DocumentLoadError`. |