> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fallow.tools/llms.txt
> Use this file to discover all available pages before exploring further.

# fallow audit

> CLI reference for fallow audit. Combined dead code, complexity, and duplication analysis scoped to changed files, with a pass/warn/fail verdict for PR quality gates and AI-generated code review.

Audit changed files for dead code, complexity, and duplication. Returns a **pass**, **warn**, or **fail** verdict based on the severity of issues found. Scoping to changed files keeps signal-to-noise high: by default only issues introduced by the current PR or commit fail the gate; inherited findings in touched files are shown as context.

<Note>
  `fallow audit` is the PR-time gate. For the initial full-repo cleanup on an existing codebase, start with [Adopt Fallow in an existing repo](/adoption), which walks through `fallow`, `fallow dead-code`, `fallow dupes`, and `fallow health`, and hands the actual cleanup to an AI agent before turning `audit` on in CI.
</Note>

<Tip>
  `fallow audit` auto-detects your base branch. Run it without arguments for a zero-config quality check.
</Tip>

```bash theme={null}
fallow audit
```

## Options

### Base ref

| Flag           | Description                                                                                                                                 |
| :------------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
| `--base <REF>` | Git ref to compare against (e.g., `main`, `HEAD~5`, a commit SHA). Alias for `--changed-since`. Auto-detects the default branch if omitted. |

### Diff scoping

| Flag                 | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| :------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--diff-file <PATH>` | Path to a pre-computed unified diff (e.g. `git diff --unified=0 main...HEAD > /tmp/pr.diff`). When supplied, the `hot-path-touched` runtime-coverage verdict is scoped to lines actually inside the diff, not just whole files. Mirrors [`fallow health --diff-file`](/cli/health). Falls back to the `FALLOW_DIFF_FILE` env var. The bundled GitHub Action and GitLab CI template pre-compute the diff and pass it automatically; you only need this flag for non-PR pipelines or local invocations. |

### Gate

| Flag              | Description                                                                                                                                                                                        |
| :---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--gate new-only` | Default. Compare against the base ref and fail only on findings introduced by the current changeset. Inherited findings are reported in JSON `attribution` and annotated with `introduced: false`. |
| `--gate all`      | Strict mode. Fail on every finding in changed files, including findings inherited from the base ref. Skips the extra base-snapshot attribution pass for lower latency.                             |

The gate has three surface forms. They all accept the same values (`new-only`, `all`) and the precedence is CLI flag > config > MCP param > default.

<CodeGroup>
  ```bash CLI theme={null}
  fallow audit --gate all
  ```

  ```toml fallow.toml theme={null}
  [audit]
  gate = "all"
  ```

  ```jsonc MCP theme={null}
  // fallow_audit tool params
  {
    "gate": "all"
  }
  ```
</CodeGroup>

#### Docs-only-diff fast path

Under `--gate new-only`, audit normally runs every analysis twice: once on the current tree and once on a temporary worktree at the base ref so it can attribute each finding as introduced or inherited. When every changed file is either a non-behavioral doc (`.md`, `.markdown`, `.txt`, `.rst`, `.adoc`) or token-equivalent at the base ref (a comment-only or whitespace-only edit on a `.ts`/`.tsx`/`.js`/`.jsx`/`.mjs`/`.mts`/`.cjs`/`.cts` source file), audit reuses the current run's findings as the base snapshot, classifies everything as inherited, and skips the second worktree analysis entirely. Common case: docs-only PRs and formatter sweeps complete in roughly one analysis pass instead of two.

Run `fallow audit --base main --gate new-only --performance` to see whether the fast path fired: the JSON output includes `base_snapshot_skipped: true|false` and the human output prints the same on stderr. The optimization activates automatically whenever every entry in the diff qualifies; there is no flag to opt in or out.

### Output

| Flag                    | Description                                                                                                                                                                               |
| :---------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-f, --format <FORMAT>` | Output format: `human` (default), `json`, `sarif`, `compact`, `markdown`, `codeclimate`, `gitlab-codequality`, `pr-comment-github`, `pr-comment-gitlab`, `review-github`, `review-gitlab` |
| `-q, --quiet`           | Suppress progress and status output on stderr                                                                                                                                             |
| `--explain`             | Add metric explanations in JSON output (`_meta` objects with docs links)                                                                                                                  |

### Scoping

| Flag                     | Description                                                                                             |
| :----------------------- | :------------------------------------------------------------------------------------------------------ |
| `-w, --workspace <NAME>` | Scope to a single workspace package                                                                     |
| `--production`           | Exclude test/story/dev files (applies to dead-code, health, and dupes)                                  |
| `--production-dead-code` | Production mode for dead-code only. See [global flags](/cli/global-flags#per-analysis-production-mode). |
| `--production-health`    | Production mode for health only.                                                                        |
| `--production-dupes`     | Production mode for duplication only.                                                                   |

### Thresholds

| Flag                     | Description                                                                                                                                                                                                                                                                                                                                                    |
| :----------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--max-crap <N>`         | Maximum CRAP score before the audit fails (default: 30.0, configurable via `health.maxCrap`). Functions meeting or exceeding this score contribute to the fail verdict alongside dead-code and complexity findings. Pair with `--coverage` for accurate per-function CRAP; without Istanbul data fallow estimates coverage from the module graph.              |
| `--coverage <PATH>`      | Path to Istanbul-format coverage data (`coverage-final.json`) for accurate per-function CRAP scores in the health sub-analysis. Also configurable via `FALLOW_COVERAGE`. Same format and semantics as [`fallow health --coverage`](/cli/health#coverage); without it, fallow falls back to the static-estimate model. Relative paths resolve against `--root`. |
| `--coverage-root <PATH>` | Absolute prefix to strip from file paths in coverage data before prepending the project root. Use when coverage was generated under a different checkout root in CI or Docker (e.g., `/home/runner/work/myapp` on GitHub Actions).                                                                                                                             |

### Baselines

| Flag                          | Description                                                                                                                           |
| :---------------------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
| `--dead-code-baseline <PATH>` | Baseline file produced by `fallow dead-code --save-baseline`. Dead-code issues present in the baseline are excluded from the verdict. |
| `--health-baseline <PATH>`    | Baseline file produced by `fallow health --save-baseline`. Complexity findings present in the baseline are excluded from the verdict. |
| `--dupes-baseline <PATH>`     | Baseline file produced by `fallow dupes --save-baseline`. Clone groups present in the baseline are excluded from the verdict.         |

The global `--baseline` / `--save-baseline` flags are **rejected** on `audit` (exit 2) because audit runs three analyses with incompatible baseline formats. Use the per-analysis flags above, or configure defaults in `.fallowrc.json`:

```jsonc theme={null}
{
  "audit": {
    "deadCodeBaseline": "fallow-baselines/dead-code.json",
    "healthBaseline":   "fallow-baselines/health.json",
    "dupesBaseline":    "fallow-baselines/dupes.json"
  }
}
```

Store committed baselines outside `.fallow/`, because `fallow init` adds that directory to `.gitignore` for machine-local cache.

CLI flags override config. Baselines are a no-op if unset; any subset (e.g. dead-code only) is allowed.

## Verdict

| Verdict   | Exit code | When                                                                           | What to do                                                                                          |
| :-------- | :-------- | :----------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------- |
| **pass**  | 0         | No introduced issues in changed files (`new-only`) or no issues at all (`all`) | Ship it.                                                                                            |
| **warn**  | 0         | Issues found, all warn-severity                                                | CI passes, but consider fixing before they become errors.                                           |
| **fail**  | 1         | Error-severity issues found                                                    | Fix the reported issues before merging.                                                             |
| **error** | 2         | Runtime error (invalid ref, not a git repo, config error)                      | Check the error message. In JSON format, emits `{"error": true, "message": "...", "exit_code": 2}`. |

Dead code issues follow your [rules configuration](/configuration/rules) severity (error/warn/off). Complexity findings above configured thresholds are always errors; thresholds are inherited from your `fallow health` config (defaults: cyclomatic 20, cognitive 15). Duplication is a warning unless a `--threshold` is configured. With the default `new-only` gate, inherited error-severity findings can appear in the report while the audit exits 0.

<Info>
  Inline suppression comments (`// fallow-ignore-next-line`) work in audit. Findings in changed files are suppressed the same way as in `fallow dead-code`.
</Info>

### JSON contract: which fields are severity-aware

Audit emits three counts that look interchangeable but answer different questions. CI integrations and downstream consumers must gate on the right one:

| Field                                                                                                         | What it counts                                                                              | Severity-aware?                            |
| :------------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------ | :----------------------------------------- |
| `verdict`                                                                                                     | Overall outcome (`pass` / `warn` / `fail`) honoring per-rule severity from `.fallowrc.json` | **Yes**                                    |
| `attribution.dead_code_introduced`, `attribution.complexity_introduced`, `attribution.duplication_introduced` | Findings introduced by the changeset under `gate: new-only`, regardless of severity         | No                                         |
| `summary.dead_code_issues`, `summary.complexity_findings`, `summary.duplication_clone_groups`                 | All findings in changed files (any gate), regardless of severity                            | No                                         |
| Per-finding `introduced: true \| false`                                                                       | Whether each individual finding was introduced by the changeset                             | No (severity is per-rule, not per-finding) |

**Rule of thumb for CI gating**: branch on `verdict == "fail"` (or check the exit code, which mirrors the verdict). Counting introduced findings re-introduces the bug `command: audit` was designed to fix: a project with `unused-exports: warn` would fail CI on every PR that introduces a warn-tier finding, even though the verdict correctly says `warn` ("do not fail"). The official GitHub Action and GitLab CI template already do this; third-party wrappers should mirror the same contract.

**Rule of thumb for AI agents**: read `verdict` first to know whether the run passed or failed, then read `attribution` for new-vs-inherited counts and walk the per-category finding arrays for actionable details. Use `introduced: true` to filter to changes the current PR is responsible for.

## Examples

<CodeGroup>
  ```bash Basic usage theme={null}
  # Auto-detect base branch
  fallow audit

  # Explicit base ref
  fallow audit --base main

  # Audit last 3 commits
  fallow audit --base HEAD~3

  # Strict mode: fail on inherited findings too
  fallow audit --gate all
  ```

  ```bash CI integration theme={null}
  # JSON for pipelines (verdict field at top level)
  fallow audit --format json --quiet

  # Environment variables work too (useful when flags can't be passed)
  FALLOW_FORMAT=json FALLOW_QUIET=1 fallow audit

  # Fail CI if audit fails
  fallow audit --base main || exit 1

  # SARIF for GitHub Code Scanning
  fallow audit --format sarif > audit.sarif

  # CodeClimate for GitLab CI
  fallow audit --format codeclimate > gl-code-quality-report.json
  ```

  ```bash Scoping theme={null}
  # Only production code
  fallow audit --production

  # Production health only (dead-code and dupes still cover the full tree)
  fallow audit --production-health

  # Single workspace package
  fallow audit --workspace @app/core

  # Explicit base with workspace
  fallow audit --base develop --workspace @app/api
  ```

  ```bash Baselines theme={null}
  # Save baselines once on the default branch
  fallow dead-code --save-baseline fallow-baselines/dead-code.json
  fallow health    --save-baseline fallow-baselines/health.json
  fallow dupes     --save-baseline fallow-baselines/dupes.json

  # Audit only new issues (pre-existing issues on touched files are ignored)
  fallow audit \
    --dead-code-baseline fallow-baselines/dead-code.json \
    --health-baseline    fallow-baselines/health.json \
    --dupes-baseline     fallow-baselines/dupes.json

  # Or set baselines in config and run audit with no flags
  fallow audit
  ```
</CodeGroup>

## Example output

```bash title="$ fallow audit (pass)" theme={null}
Audit scope: 8 changed files vs main (d4a2f91..HEAD)
✓ No issues in 8 changed files (1.18s)
```

```bash title="$ fallow audit (warn)" theme={null}
Audit scope: 8 changed files vs main (d4a2f91..HEAD)
■ dead code 0 · complexity 2 (warn, max cyclomatic: 12) · duplication 0
✓ dead code: 0 issues · complexity: 2 findings (warn) · 8 changed files (1.18s)
```

The `■` summary line appears only on warn verdicts, before any detail sections. It is suppressed with `--quiet`.

```bash title="$ fallow audit (fail)" theme={null}
Audit scope: 12 changed files vs main (d4a2f91..HEAD)

── Dead Code ──────────────────────────────────────

● Unused exports (2)
  src/components/Button.tsx (2)
    :42 OldButton
    :67 deprecatedHelper
  Exported symbols not imported by any reachable file — https://docs.fallow.tools/explanations/dead-code#unused-exports

── Duplication ────────────────────────────────────

● Duplicates (1 clone group)

    23 lines  2 instances
    src/utils/helpers.ts:10-32
    src/legacy/compat.ts:5-27

── Complexity ─────────────────────────────────────

● High complexity functions (1)
  src/parser.ts
    :45 parseExpression
         28 cyclomatic  32 cognitive  80 lines
  Functions exceeding thresholds — https://docs.fallow.tools/explanations/health#complexity-metrics

✗ dead code: 2 issues · complexity: 1 finding · duplication: 1 clone group · 12 changed files (2.14s)
```

## How it works

1. **Resolve base ref**: uses `--base` if provided, otherwise auto-detects the default branch (`git symbolic-ref refs/remotes/origin/HEAD` → `main` → `master`). Hard-errors if no base can be determined.
2. **Find changed files**: runs `git diff --name-only <base>...HEAD` (three-dot diff, showing changes since the merge base).
3. **Run three analyses** scoped to changed files: [dead code](/cli/dead-code), [complexity](/cli/health), [duplication](/cli/dupes).
4. **Compute attribution**: with `new-only`, runs the same analyses at the base ref and compares structural issue keys.
5. **Compute verdict**: `new-only` gates only introduced findings; `all` gates every finding in changed files without the extra base-snapshot analysis.

## JSON output

```json title="$ fallow audit --format json" theme={null}
{
  "schema_version": 3,
  "version": "2.75.0",
  "command": "audit",
  "verdict": "fail",
  "changed_files_count": 12,
  "base_ref": "main",
  "head_sha": "d4a2f91",
  "elapsed_ms": 2140,
  "summary": {
    "dead_code_issues": 2,
    "dead_code_has_errors": true,
    "complexity_findings": 1,
    "max_cyclomatic": 28,
    "duplication_clone_groups": 0
  },
  "attribution": {
    "gate": "new-only",
    "dead_code_introduced": 2,
    "dead_code_inherited": 0,
    "complexity_introduced": 1,
    "complexity_inherited": 0,
    "duplication_introduced": 0,
    "duplication_inherited": 0
  },
  "dead_code": {
    "schema_version": 3,
    "total_issues": 2,
    "unused_exports": [
      { "path": "src/components/Button.tsx", "export_name": "OldButton", "introduced": true, "actions": [...] }
    ]
  },
  "complexity": {
    "findings": [...]
  },
  "duplication": {
    "clone_groups": [],
    "stats": { "duplication_percentage": 0.0 }
  }
}
```

### Key fields

| Field                              | Type                             | Description                                                                                                                                          |
| :--------------------------------- | :------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------- |
| `verdict`                          | `"pass"` \| `"warn"` \| `"fail"` | The audit result. Use this for CI gates.                                                                                                             |
| `changed_files_count`              | integer                          | Number of files changed between base and HEAD                                                                                                        |
| `base_ref`                         | string                           | The git ref used for comparison                                                                                                                      |
| `summary.dead_code_issues`         | integer                          | Total dead code issues in changed files                                                                                                              |
| `summary.dead_code_has_errors`     | boolean                          | Whether any dead code issues have error severity                                                                                                     |
| `summary.complexity_findings`      | integer                          | Functions exceeding complexity thresholds                                                                                                            |
| `summary.max_cyclomatic`           | integer \| null                  | Highest cyclomatic complexity found (null if none)                                                                                                   |
| `summary.duplication_clone_groups` | integer                          | Clone groups involving changed files                                                                                                                 |
| `attribution.*_introduced`         | integer                          | Findings whose structural key did not exist at the base ref. With `gate=all`, these stay `0` because audit skips the base-snapshot attribution pass. |
| `attribution.*_inherited`          | integer                          | Findings already present at the base ref. With `gate=all`, these stay `0` because audit skips the base-snapshot attribution pass.                    |
| `dead_code.*[].introduced`         | boolean                          | Present in audit JSON sub-results when base attribution is available. `true` means the finding is new relative to the base ref.                      |

The `dead_code`, `complexity`, and `duplication` sub-objects contain full results in the same format as [`fallow dead-code`](/cli/dead-code#json-output), [`fallow health`](/cli/health#json-output), and [`fallow dupes`](/cli/dupes#json-output) respectively. These are omitted when no files changed. In audit output, individual findings and clone groups include an optional `introduced` boolean when the base ref comparison is available.

<Note>
  On exit code 2 (runtime error), JSON format emits `{"error": true, "message": "...", "exit_code": 2}` to stdout instead of the audit envelope.
</Note>

## MCP tool

The `audit` MCP tool wraps `fallow audit --format json --quiet --explain`:

```json title="Example request" theme={null}
{
  "tool": "audit",
  "arguments": {
    "base": "main",
    "gate": "new-only"
  }
}
```

Auto-detects the base branch if `base` is not specified. Set `gate` to `all` for strict mode. The response always includes `_meta` explanatory metadata (the MCP wrapper enables `--explain` by default). Returns the same JSON envelope as the CLI.

`audit` creates a temporary git worktree to compare against the base ref. When the current checkout has `node_modules`, audit links it into the base worktree so tsconfig `extends` chains into installed packages and path aliases resolve like the working tree. The worktree is removed on normal exit. If the process is force-killed, run `git worktree prune` to clean up stale `.git/worktrees/fallow-audit-base-*` entries.

See [MCP integration](/integrations/mcp) for setup instructions.

## See also

<CardGroup cols={3}>
  <Card title="Dead code analysis" icon="skull-crossbones" href="/cli/dead-code">
    Full dead code analysis with issue-type filters.
  </Card>

  <Card title="Health analysis" icon="heart-pulse" href="/cli/health">
    Complexity metrics, file scores, hotspots, and targets.
  </Card>

  <Card title="MCP integration" icon="robot" href="/integrations/mcp">
    Use fallow tools from AI coding agents.
  </Card>
</CardGroup>
