Skip to main content

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.

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.
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, 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.
fallow audit auto-detects your base branch. Run it without arguments for a zero-config quality check.
fallow audit

Options

Base ref

FlagDescription
--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

FlagDescription
--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. 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

FlagDescription
--gate new-onlyDefault. 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 allStrict 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.
fallow audit --gate all

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

FlagDescription
-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, --quietSuppress progress and status output on stderr
--explainAdd metric explanations in JSON output (_meta objects with docs links)

Scoping

FlagDescription
-w, --workspace <NAME>Scope to a single workspace package
--productionExclude test/story/dev files (applies to dead-code, health, and dupes)
--production-dead-codeProduction mode for dead-code only. See global flags.
--production-healthProduction mode for health only.
--production-dupesProduction mode for duplication only.

Thresholds

FlagDescription
--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; 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

FlagDescription
--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:
{
  "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

VerdictExit codeWhenWhat to do
pass0No introduced issues in changed files (new-only) or no issues at all (all)Ship it.
warn0Issues found, all warn-severityCI passes, but consider fixing before they become errors.
fail1Error-severity issues foundFix the reported issues before merging.
error2Runtime 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 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.
Inline suppression comments (// fallow-ignore-next-line) work in audit. Findings in changed files are suppressed the same way as in fallow dead-code.

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:
FieldWhat it countsSeverity-aware?
verdictOverall outcome (pass / warn / fail) honoring per-rule severity from .fallowrc.jsonYes
attribution.dead_code_introduced, attribution.complexity_introduced, attribution.duplication_introducedFindings introduced by the changeset under gate: new-only, regardless of severityNo
summary.dead_code_issues, summary.complexity_findings, summary.duplication_clone_groupsAll findings in changed files (any gate), regardless of severityNo
Per-finding introduced: true | falseWhether each individual finding was introduced by the changesetNo (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

# 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

Example output

$ fallow audit (pass)
Audit scope: 8 changed files vs main (d4a2f91..HEAD)
 No issues in 8 changed files (1.18s)
$ fallow audit (warn)
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.
$ fallow audit (fail)
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/HEADmainmaster). 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, complexity, duplication.
  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

$ fallow audit --format json
{
  "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

FieldTypeDescription
verdict"pass" | "warn" | "fail"The audit result. Use this for CI gates.
changed_files_countintegerNumber of files changed between base and HEAD
base_refstringThe git ref used for comparison
summary.dead_code_issuesintegerTotal dead code issues in changed files
summary.dead_code_has_errorsbooleanWhether any dead code issues have error severity
summary.complexity_findingsintegerFunctions exceeding complexity thresholds
summary.max_cyclomaticinteger | nullHighest cyclomatic complexity found (null if none)
summary.duplication_clone_groupsintegerClone groups involving changed files
attribution.*_introducedintegerFindings 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.*_inheritedintegerFindings already present at the base ref. With gate=all, these stay 0 because audit skips the base-snapshot attribution pass.
dead_code.*[].introducedbooleanPresent 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, fallow health, and fallow dupes 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.
On exit code 2 (runtime error), JSON format emits {"error": true, "message": "...", "exit_code": 2} to stdout instead of the audit envelope.

MCP tool

The audit MCP tool wraps fallow audit --format json --quiet --explain:
Example request
{
  "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 for setup instructions.

See also

Dead code analysis

Full dead code analysis with issue-type filters.

Health analysis

Complexity metrics, file scores, hotspots, and targets.

MCP integration

Use fallow tools from AI coding agents.