README.md

June 30, 2026 · View on GitHub

fallow

Deterministic codebase intelligence for TypeScript and JavaScript.
Quality, risk, architecture, dependencies, duplication, and safe cleanup evidence for humans, CI, and agents.
Static analysis is free and open source. Optional runtime intelligence (Fallow Runtime) adds production execution evidence.
Rust-native. Zero config. Sub-second. No AI inside the analyzer.

CI Coverage CodSpeed GitHub stars npm npm downloads MIT License Documentation


Fallow turns a JS/TS repository into a trusted quality report: health score, changed-code risk, hotspots, duplication, architecture issues, dependency hygiene, and cleanup opportunities. It helps you answer:

  • What changed?
  • What got riskier?
  • What should I review?
  • What should I refactor?
  • What can be safely removed?

Fallow is built for maintainers, CI pipelines, editors, and AI agents that need structured evidence instead of guesses. No AI inside the analyzer. Fallow produces deterministic findings, typed output contracts, and traceable explanations that downstream tools can trust.

Fallow dogfoods its shipped JavaScript and TypeScript surfaces in CI: the VS Code extension and npm wrapper package are analyzed with fallow on every relevant change.

Quick start

Run a changed-code audit:

npx fallow audit

Example output:

Audit scope: 7 changed files vs main

-- Dead Code ---------------------------------------

x 7 unused dependencies · 14 dev/optional dependencies
  21 issues · 1 suppressed · 0 stale suppressions

-- Duplication -------------------------------------

x 3 clone families touching changed files

-- Complexity --------------------------------------

! 2 changed functions above threshold

Cleanup opportunities include unused files, unused exports, unused dependencies, stale suppressions, and other code that no longer appears to carry product value.

For machine-readable output:

npx fallow audit --format json

For quality scoring and refactor targets:

npx fallow health --score --hotspots --targets

For cleanup-specific findings:

npx fallow dead-code

123 framework plugins. No Node.js runtime required for static analysis. No config needed for the first run.

What is Fallow?

Fallow is a codebase intelligence engine for TypeScript and JavaScript projects.

It analyzes your repository as a system, not just as a list of files. It connects static structure, dependency relationships, duplication, complexity, architecture boundaries, package hygiene, and optional runtime evidence into one quality report.

Fallow helps teams:

  • review risky pull requests before they merge
  • track quality trends over time
  • find architectural hotspots
  • understand dependency hygiene
  • detect duplicated logic
  • explain why code is used, unused, risky, or safe to remove
  • provide structured repo context to AI agents and editor tools

Linters check files. TypeScript checks types. Fallow checks the codebase. Fallow does not use AI to invent findings. It produces deterministic evidence that humans and agents can inspect.

Install

npm install --save-dev fallow   # or: pnpm add -D fallow / yarn add -D fallow / bun add -d fallow

Installs the CLI, LSP server, MCP server, and version-matched Agent Skill into node_modules. For one-off CLI use, run npx fallow; Rust users can also run cargo install fallow-cli.

Interactive human runs can show a one-line upgrade hint when a cached latest-version check says the local fallow is stale. Machine formats, CI, quiet runs, and non-TTY agent paths never show the hint; set FALLOW_UPDATE_CHECK=off to disable the hint and background check.

Parsing fallow --format json in TypeScript? import type { CheckOutput } from "fallow/types" gives you the full output contract, version-pinned to your installed CLI.

Docker

Build the local CLI image from this repository:

docker build -t fallow:local .

Run fallow against a project by mounting it at /workspace:

cd /path/to/project
docker run --rm -v "$PWD:/workspace" --user "$(id -u):$(id -g)" fallow:local audit --format json --quiet

The --user mapping keeps .fallow/ caches and generated reports owned by your host user. It also lets fallow audit use git base detection without Git's dubious-ownership guard blocking the mounted repository. The image includes git, Node.js, npm, and Corepack; fallow does not install your project dependencies automatically.

For Compose, copy examples/docker/compose.yaml into the target project after building the image, then run:

docker compose run --rm fallow audit --format json --quiet

Fallow is a one-shot CLI, not a long-running service. In Portainer or other stack tools, use a one-shot run command instead of deploying it as an always-on service, or override the command for an interactive shell. Container exit codes are the fallow process exit codes, so CI can gate on the docker run or docker compose run result directly.

On Linux and WSL, the commands above work as written. On Windows outside WSL, pass an absolute project path accepted by Docker Desktop and keep the mounted working directory at /workspace. For containerized runtime coverage inventory, use the container path prefix:

docker run --rm -v "$PWD:/workspace" --user "$(id -u):$(id -g)" fallow:local coverage upload-inventory --path-prefix /workspace --format json --quiet

Programmatic Node API:

npm install @fallow-cli/fallow-node   # or: pnpm/yarn/bun add @fallow-cli/fallow-node
import { detectDeadCode, detectDuplication, computeHealth } from '@fallow-cli/fallow-node';

const findings = await detectDeadCode({ root: process.cwd() });
const dupes = await detectDuplication({ root: process.cwd(), mode: 'mild', minTokens: 30 });
const health = await computeHealth({ root: process.cwd(), score: true, ownershipEmails: 'handle' });

What Fallow reports

Quality score

A compact health score for the current state of the repository, with targets for maintainability, complexity, duplication, dependency hygiene, and architecture.

PR risk

Changed-code analysis (fallow audit) that highlights files and symbols most likely to need review before merge. Returns a verdict (pass / warn / fail) and an attribution split between findings the PR introduced and pre-existing ones.

Hotspots

Functions, files, and packages that combine complexity, churn, size, coupling, and (with the runtime layer) runtime importance.

Duplication

Clone families and duplicated implementation patterns that increase maintenance cost. Four detection modes from exact token match to semantic clones with renamed variables. Covers JS, TS, CSS-family stylesheets, Vue and Svelte template and style regions, and Astro template and style regions.

Architecture

Circular dependencies, boundary violations across layers and modules, re-export chains, and other dependency-graph issues. Zero-config presets for bulletproof, layered, hexagonal, and feature-sliced architectures. Framework correctness checks catch Next.js "use client" files that export a server-only or route-segment config name (such as metadata, revalidate, or a route HTTP method) before the build does. They also flag barrels that re-export both client and server-only modules, and "use client" / "use server" directives placed below an import where the bundler silently ignores them. Whole-project App Router checks catch route collisions (two files resolving to the same URL across route groups, a next build failure) and dynamic-segment name conflicts ([id] vs [slug] at the same position), scoped per app-root so monorepos with multiple Next apps are not false-flagged. They also flag Server Actions exported from a "use server" file that no code in the project calls (no import-and-call, no action={fn} binding, no <form action={fn}>), the cross-file dead-action direction eslint-plugin-next cannot see.

Dependency hygiene

Unused dependencies, unresolved imports, duplicate exports, unlisted imports, type-only production deps, test-only production deps, and pnpm catalog and overrides hygiene.

Cleanup opportunities

Unused files, unused exports, unused types, unused enum members, unused class members, unused Pinia store members, unprovided Vue/Svelte/Angular injects, unused Angular component inputs and outputs, Svelte component events dispatched but listened to nowhere, stale suppression comments, and code paths that appear safe to review for removal. Opt-in API hygiene checks such as private type leaks live here too.

Runtime intelligence (optional)

Static analysis answers what is connected. Runtime intelligence answers what actually ran in production. Hot paths, cold code, runtime-weighted health, stale flags, runtime-backed PR review. See the Runtime intelligence section below.

Agent-ready context

Structured JSON, an MCP server, and an LSP for answering "what depends on this?", "why is this used?", "what changed?", and "what action is safest?".

Built for agents

Fallow gives AI agents structured repo truth instead of forcing them to infer everything from grep.

Agents can ask:

  • Who imports this symbol?
  • Why is this export considered used?
  • Why is this export considered unused?
  • What changed in this PR?
  • Which files are risky to touch?
  • Which files are architectural hotspots?
  • What duplicate siblings exist?
  • What cleanup action is safest?
  • What evidence supports this finding?

Fallow exposes this through JSON output, typed output contracts (import type { CheckOutput } from "fallow/types"), the MCP server, and the LSP. Every issue in --format json carries a machine-actionable actions array with an auto_fixable flag so agents can self-correct.

Run fallow init --agents to scaffold a starter AGENTS.md for project-specific navigation, command, architecture, and safety guidance. The file is guidance for agents, not a readiness score, and fallow will not overwrite an existing guide.

Common agent workflow:

  1. generate or edit code
  2. run fallow audit --format json
  3. inspect findings and per-issue actions
  4. apply safe fixes or adjust the patch before opening a PR
  5. hand the result to a human reviewer with better evidence
npx fallow audit --format json
npx fallow --format json
npx fallow inspect --file src/api.ts --format json
npx fallow --coverage coverage/coverage-final.json --format json
npx fallow fix --dry-run --format json

For full adoption instead of one-off review, see the Fallow compliance happy path. It defines the end state and includes a copy-paste agent onboarding prompt.

See Agent integration for MCP setup and the full list of structured tools.

Use fallow inspect --file <path> or fallow inspect --symbol <file>:<export> when an agent needs one evidence bundle before editing. The MCP server exposes the same flow as inspect_target, combining trace, dead-code, duplication, complexity, and security signals without inventing a new analysis pass.

The MCP server also exposes code_execute, a bounded read-only Code Mode tool for composing multiple fallow analysis calls in one JavaScript snippet. It can call analysis helpers such as fallow.projectInfo, fallow.audit, and fallow.checkHealth, but it does not expose mutating fix tools.

For security review loops, see the Security agent verification recipe. It shows how to combine fallow security --format json --surface, candidate evidence, and MCP security_candidates output without adding model calls to fallow core.

Run fallow impact to see what fallow has done for you: how many issues it is surfacing, the trend since your last recorded run, and how many commits its pre-commit gate caught before they shipped. Run fallow impact --all to roll every tracked project into one cross-repo view. It is opt-in (fallow impact enable) and entirely local: history lives in your user config directory (never written into the repo, so nothing to gitignore) and is never uploaded.

Product telemetry for improving agent, CI, MCP, and editor workflows is off by default. Run fallow telemetry inspect --example to see the payload, or FALLOW_TELEMETRY=inspect fallow audit --format json --quiet to inspect a real run without sending it. Run fallow telemetry enable only when you want to help improve these integrations. See Telemetry.

Why teams using AI need Fallow

AI accelerates code creation. It does not eliminate review, cleanup, or architecture drift.

When Claude Code, Codex, Cursor, or other tools generate changes, teams still need to know:

  • did this introduce risky complexity?
  • did it duplicate logic that already existed?
  • did the change cross an architectural boundary it should not cross?
  • did it leave behind unused code or stale dependencies?
  • is this code on a hot path or a cold one?
  • what should the reviewer read closely first?

Fallow answers those questions with deterministic, graph-based analysis and structured output, so both humans and agents can act on facts instead of guesses.

More static commands

fallow                       # Full codebase analysis: cleanup + duplication + health
fallow audit                 # Audit changed files (verdict: pass/warn/fail)
fallow review                # Advisory review brief over changed files (always exits 0)
fallow decision-surface      # Ranked structural decisions a change embeds
fallow trace src/utils.ts:formatDate  # Symbol-level call chains (callers up, callees down)
fallow health                # Complexity + refactor targets
fallow health --css          # + structural CSS analytics (specificity, !important, nesting)
fallow dupes                 # Repeated logic
fallow dead-code             # Cleanup candidates
fallow security              # Security candidates, hardcoded-secret needs explicit category include
fallow security survivors    # Render verifier-filtered survivor candidates
fallow security blind-spots  # Group unresolved security callees
fallow explain unused-export # Explain a rule without analyzing
fallow watch                 # Re-analyze on file changes
fallow fix --dry-run         # Preview automatic cleanup

Combined mode (fallow) and fallow audit support per-analysis production mode. Precedence is CLI flags, then environment variables, then config:

{
  "production": {
    "health": true,
    "deadCode": false,
    "dupes": false
  }
}

Use --production-health, --production-dead-code, or --production-dupes for one invocation, or FALLOW_PRODUCTION_HEALTH=true and related env vars in CI. The global --production flag still enables production mode for every analysis.

fallow security remains opt-in and ranks reachable active-code candidates first. It includes source-backed ReDoS regex candidates for risky literal patterns applied to untrusted input, while safe literal patterns and source-free uses stay quiet. When a sink is also reported as dead code, JSON includes dead_code context and the command points agents toward deleting the unused file or removing the unused export before hardening that sink. Use fallow security --gate new --changed-since <ref> for changed-line candidate gating, or fallow security --gate newly-reachable --changed-since <ref> when an existing sink becoming entry-reachable should block the change for review. Use fallow security survivors --candidates fallow-security.json --verdicts verdicts.json to render verifier-filtered survivors, and fallow security blind-spots to group unresolved callee blind spots. See the Security agent verification recipe for the full workflow.

Precedence (highest to lowest): CLI flags, per-analysis env var, global FALLOW_PRODUCTION, config. CLI flags only enable; env vars and config can also disable. Worked examples:

# Run health in production mode, dead-code and dupes on the full tree
fallow --production-health

# Same, via env var (useful in CI templates that pass env-only)
FALLOW_PRODUCTION_HEALTH=true fallow

# Per-analysis env wins over the global env, so this runs health in production mode
# even though the global env says off (the typical CI-template defaults case)
FALLOW_PRODUCTION=false FALLOW_PRODUCTION_HEALTH=true fallow

# CLI flags beat env vars; this turns ALL three on regardless of any FALLOW_PRODUCTION_* env
fallow --production

Cleanup opportunities

Cleanup opportunities are code that no longer appears to carry product value: unused files, exports, dependencies, types, enum members, class members, Pinia store members, unprovided Vue/Svelte/Angular injects, unused Angular component inputs and outputs, Svelte component events listened to nowhere, unresolved imports, unlisted dependencies, duplicate exports, circular dependencies (including cross-package cycles in monorepos), boundary violations, type-only dependencies, test-only production dependencies, and stale suppression comments. Workspace package dependencies are checked like external packages, so unused or undeclared internal package edges are visible in monorepos. Entry points are auto-detected from package.json fields, package scripts, framework conventions, and plugin patterns. Public class members on classes exposed from non-private package entry points or exportless source subpath indexes are treated as library API surface, while reachable internal classes still get member-level checks. Arrow-wrapped dynamic imports (React.lazy, loadable, defineAsyncComponent) and proven local child_process.fork() runner targets are tracked as references. Script multiplexers (concurrently, npm-run-all) are analyzed to discover transitive script dependencies. JSDoc tags (@public, @internal, @beta, @alpha, @expected-unused) control export visibility. Private type leaks are currently opt-in API hygiene findings via --private-type-leaks or the private-type-leaks rule.

fallow dead-code                          # All dead code issues
fallow dead-code --unused-exports         # Only unused exports
fallow dead-code --private-type-leaks     # Opt-in private type leak API hygiene
fallow dead-code --circular-deps          # Only circular dependencies
fallow dead-code --boundary-violations    # Only boundary violations
fallow dead-code --stale-suppressions     # Only stale suppression comments
fallow dead-code --production             # Exclude test/dev files
fallow dead-code --changed-since main     # Only changed files (for PRs)
fallow dead-code --file src/utils.ts       # Single file (lint-staged integration)
fallow dead-code --include-entry-exports  # Also check exports from entry files
fallow dead-code --group-by owner         # Group by CODEOWNERS for team triage
fallow dead-code --group-by directory     # Group by first directory component
fallow dead-code --group-by package       # Group by workspace package (monorepo)
fallow dead-code --group-by section       # Group by GitLab CODEOWNERS section

Duplication

Finds copy-pasted code blocks across your codebase, including CSS-family stylesheets and authored template/style regions in Vue, Svelte, and Astro files. Suffix-array algorithm -- no quadratic pairwise comparison. Repeated atomic function calls are filtered by default, so long calls to an existing shared abstraction do not show up as refactoring work.

fallow dupes                              # Default (mild mode)
fallow dupes --mode semantic              # Catch clones with renamed variables
fallow dupes --skip-local                 # Only cross-directory duplicates
fallow dupes --group-by owner             # Partition clone groups by CODEOWNERS team
fallow dupes --group-by directory         # Partition clone groups by directory
fallow dupes --format compact             # One parseable line per clone instance
fallow dupes --trace src/utils.ts:42      # Show all clones of code at this location
fallow dupes --trace dup:7f3a2c1e         # Deep-dive a clone group by its dup:<id> fingerprint

Clone fingerprints are usually short dup:<8hex> ids and widen only when a rare report collision requires it.

Four detection modes: strict (exact tokens), mild (default, AST-based), weak (different string literals), semantic (renamed variables and literals).

Complexity

Surfaces the most complex functions in your codebase and identifies where to spend refactoring effort. Angular, Vue, and Svelte templates are included as synthetic <template> entries when they use control flow or complex bindings, covering Angular external templateUrl files and inline @Component({ template: \...` })decorators as well as the