Every agent that can run shell commands can use fallow. The CLI is the primary interface. MCP is an optional structured layer on top.
Why agents need fallow
Codebase analysis means building and traversing a graph, not reading files in a context window.| What agents can’t do | What fallow does |
|---|---|
| Build a complete module graph across 5,000+ files | Builds the full graph in ~200ms |
| Track re-export chains through barrel files | Resolves export * chains through unlimited levels |
| Know if an export is used somewhere outside their context window | Exhaustively checks every import in the entire codebase |
| Detect code duplication across files they haven’t seen | Suffix array algorithm catches clones across all files |
Determine which package.json dependencies are actually unused | Traces imports and script binaries to actual usage |
| Guarantee completeness (no missed files, no false negatives) | Deterministic: same input always produces same output |
Static analysis requires building and traversing a module graph. No amount of context window makes an LLM equivalent to a graph algorithm.
CLI: the primary agent interface
Every AI coding agent can run shell commands. No MCP required:Agent workflow examples
After generating code:MCP: structured tool calling
For agents that support ,fallow-mcp exposes analysis as structured tools. Agents get typed inputs and outputs instead of parsing CLI text.
The MCP server uses and wraps the fallow CLI binary. Set the FALLOW_BIN environment variable to point to the fallow binary (defaults to fallow in PATH).
- Claude Code
- Cursor
- Other MCP clients
Add to your
.claude/settings.json:Available MCP tools
| Tool | Description |
|---|---|
analyze | Full dead code analysis (fallow dead-code --format json). Detects unused files, exports, types, dependencies, enum/class members, unresolved imports, unlisted dependencies, duplicate exports, circular dependencies, re-export cycles (barrel files that form a structural loop, silently breaking re-exports), boundary violations, stale suppressions, unused pnpm catalog entries, empty pnpm catalog groups, and unresolved pnpm catalog references (consumer package.json references a catalog that does not declare the package; pnpm install would fail). Private type leaks are opt-in via issue_types: ["private-type-leaks"]. |
check_changed | Incremental analysis of changed files (fallow dead-code --changed-since) |
security_candidates | Unverified local security candidates, not confirmed vulnerabilities (fallow security --format json). Read security_findings[] for category, CWE, evidence, and trace; verify trace and evidence before editing code. Supports root, config, workspace, changed_since, changed_workspaces, no_cache, and threads; inherits FALLOW_DIFF_FILE from the server environment for line-level diff scoping; raise FALLOW_TIMEOUT_SECS for large repos. |
find_dupes | Code duplication detection (fallow dupes --format json). Each clone_groups[] entry (plus nested clone_families[].groups[] and the per-bucket --group-by output) carries a stable fingerprint, usually dup:<8hex> and widened only on rare report collisions; pass it to trace_clone to deep-dive that group. |
fix_preview | Dry-run auto-fix preview (fallow fix --dry-run --format json) |
fix_apply | Apply auto-fixes (fallow fix --yes --format json) |
check_health | Complexity metrics, file health scores, hotspots, and refactoring targets (fallow health --format json). Set file_scores: true for maintainability index, hotspots: true for churn analysis, targets: true for ranked recommendations sorted by efficiency, trend: true for per-metric deltas against the most recent snapshot. Set runtime_coverage to merge a V8 or Istanbul coverage dump; tune it with min_invocations_hot (default 100), min_observation_volume (default 5000), and low_traffic_threshold (default 0.001). Set group_by to owner, directory, package, or section to partition results: each group gets its own vital_signs, health_score, and optional coverage_source_consistency recomputed from the group’s files (top-level metrics stay project-wide), SARIF results gain properties.group, CodeClimate issues gain a top-level group field. Findings include a bucketed coverage_tier (none/partial/high) and coverage_source for CRAP-triggered entries; summary.coverage_source_consistency reports whether those sources are uniform or mixed. Actions pick add-tests / increase-coverage when coverage can still clear CRAP, or refactor-function when cyclomatic >= maxCrap, see “Structured actions” below. |
check_runtime_coverage | Merge runtime-coverage data into the health report. Required coverage param accepts a V8 coverage directory, a single V8 coverage JSON, or an Istanbul coverage-final.json. A single local capture is free and runs without a license; continuous or multi-capture runtime monitoring (a V8 directory containing multiple JSON files) requires an active license JWT. Tunable via min_invocations_hot (default 100), min_observation_volume (default 5000), low_traffic_threshold (default 0.001), max_crap (default 30.0), top, and group_by. Protocol-0.3+ sidecars emit a summary.capture_quality block flagging short-window captures. Cloud runtime rows can expose resolutionStatus / mappingQuality on function-list JSON and resolution_status / mapping_quality in runtime-context JSON. Use the confidence table below before acting on file-level runtime signals. Can exceed the default 120s timeout on large dumps; raise FALLOW_TIMEOUT_SECS accordingly. Pick this over check_health when you have a coverage dump. |
get_hot_paths | Runtime-context slice over the same local runtime coverage pipeline. Same input schema and free-vs-paid contract as check_runtime_coverage; read runtime_coverage.hot_paths for production hot paths sorted by percentile and invocation count. |
get_blast_radius | Runtime-context slice for blast-radius review. Same input schema and free-vs-paid contract as check_runtime_coverage; read runtime_coverage.blast_radius for stable fallow:blast:<hash> IDs, caller counts, traffic-weighted caller reach, optional cloud deploy touch counts, and low/medium/high risk bands. |
get_importance | Runtime-context slice for production-importance review. Same input schema and free-vs-paid contract as check_runtime_coverage; read runtime_coverage.importance for stable fallow:importance:<hash> IDs, invocations, cyclomatic complexity, owner count, 0-100 score, and templated reason. |
get_cleanup_candidates | Runtime-context slice for cleanup review. Same input schema and free-vs-paid contract as check_runtime_coverage; read runtime_coverage.findings for safe_to_delete, review_required, low_traffic, and coverage_unavailable verdicts. |
audit | Audit changed files for dead code, complexity, and duplication (fallow audit --format json). Returns a verdict (pass/warn/fail). Set base to specify the comparison ref, gate to new-only or all, and include_entry_exports=true to also catch typos in entry-file exports (meatdata vs metadata). Set coverage to an Istanbul coverage-final.json path (and absolute coverage_root when paths need rebasing for CI / Docker checkouts) for accurate per-function CRAP scoring in the health sub-analysis. Set runtime_coverage (V8 dir / V8 JSON / Istanbul JSON) to fold runtime-coverage findings into the same audit invocation; tune with min_invocations_hot (default 100). When FALLOW_DIFF_FILE or FALLOW_CHANGED_SINCE is set in the agent’s env, runtime_coverage.verdict promotes hot-path-touched over cold-code-detected for PR-review contexts. |
fallow_explain | Explain one issue type without running analysis (fallow explain <issue-type> --format json). Returns rationale, example, fix guidance, and docs URL. |
project_info | Project metadata, including plugins, files, and entry points (fallow list --format json). Set entry_points, files, plugins, or boundaries to true to request specific sections. |
feature_flags | Detect feature flag patterns in the codebase (fallow flags --format json). Identifies environment variable flags, SDK calls from common providers, and config object patterns. Set top to limit results. |
list_boundaries | Architecture boundary zones and access rules (fallow list --boundaries --format json). Returns zone definitions, access rules, per-zone file counts, and logical_groups[] (pre-expansion autoDiscover parents with verbatim paths, discovered children, a status enum (ok / empty / invalid_path), summed file_count, optional authored_rule, optional fallback_zone cross-reference for the Bulletproof case, optional merged_from for duplicate parent declarations, optional original_zone_root echo for monorepo subtree scopes, and optional child_source_indices attribution for multi-path autoDiscover). Returns {"configured": false} if no boundaries are configured. |
trace_export | Trace why an export is used or unused (fallow dead-code --trace FILE:EXPORT_NAME --format json). Required file and export_name params. Returns file reachability, entry-point status, direct references, re-export chains, and a reason string. Use before deleting a supposedly-unused export. |
trace_file | Trace all graph edges for a file (fallow dead-code --trace-file PATH --format json). Required file param. Returns reachability, entry-point status, exports, imports-from, imported-by, and re-exports. Use to decide whether a file is isolated, barrel-only, or imported by live entry points. |
trace_dependency | Trace where a dependency is imported (fallow dead-code --trace-dependency PACKAGE --format json). Required package_name param. Returns importing files, type-only importers, total import count, used_in_scripts (true when invoked from package.json scripts or CI configs like .github/workflows/*.yml / .gitlab-ci.yml), and is_used (combined import + script signal, mirrors the unused-deps detector so build tools like microbundle or vitest invoked only via scripts are correctly classified as used). Use before removing a dependency or moving it between dependencies and devDependencies. |
trace_clone | Deep-dive a duplicate-code clone group (fallow dupes --trace <spec> --format json). Address it by exactly one of: file + line (a source location), or fingerprint (a dup:<id> from a prior find_dupes clone_groups[].fingerprint, usually dup:<8hex> and widened only on rare report collisions). Returns the matched clone instance plus every clone group containing it; each traced group carries its fingerprint, a group-level extract-function suggestion with estimated savings, and a best-effort suggested_name (omitted when no confident name; advisory). Supports mode, min_tokens, min_lines, threshold, skip_local, cross_language, ignore_imports. Use to consolidate duplication when you need exact sibling locations and a refactor target; the fingerprint form lets an agent deep-dive a find_dupes result directly. |
impact | Read the local, opt-in Fallow Impact value report (fallow impact --format json). Runs no analysis: reports current surfacing counts, the trend since the last recorded run, pre-commit gate containment, and (on impact v1.5+) resolved/suppressed attribution. Read-only and root-only (no config / no_cache / threads); the mutating enable / disable lifecycle is not exposed. On a project where tracking was never enabled it returns a populated {"enabled": false, ...} report (never {}), so an agent branches on enabled then record_count and recommends the user run fallow impact enable rather than toggling it. Local-developer signal: in ephemeral CI runners it returns an empty report, so it is not a CI metric. |
Runtime source-map confidence
Cloud runtime tools can include source-map confidence metadata when the responsecapabilities array contains function_identity_v2. Function list responses use resolutionStatus and mappingQuality; runtime-context responses use resolution_status and mapping_quality. These fields describe source-map confidence, not whether the function ran.
| Values | Meaning | Agent action |
|---|---|---|
resolved + high | The source map resolved the generated position to original source. | Trust the file path and line number. Reference the original source confidently. |
fallback + medium | A source map exists, but it did not cover this generated position. | Treat the file-level signal as approximate. Ask the developer to rebuild with denser source maps before making a precise edit. |
unresolved + low | No matching source map was uploaded for this bundle and commit. | Ask the operator to upload the source map before acting on file-level coverage signals. |
null + null | The row does not include source-map confidence metadata. | Treat the row as missing confidence metadata. Do not downgrade it to low without other evidence. |
Notable tool parameters
Some tools accept additional parameters beyond the commonroot, config, no_cache, and threads:
| Tool | Parameter | Type | Description |
|---|---|---|---|
analyze | boundary_violations | bool | Convenience alias for issue_types: ["boundary-violations"] |
find_dupes | changed_since | string | Only report duplication in files changed since a git ref |
find_dupes / trace_clone | min_occurrences | integer (≥ 2) | Minimum number of occurrences before a clone group is reported. Default 2. Raise to skip pair-only clones and focus on widespread copy-paste worth refactoring. JSON output gains stats.clone_groups_below_min_occurrences when the filter hides anything. |
audit | gate | string | new-only gates only introduced findings; all gates every finding in changed files |
audit / check_health | coverage | string | Path to Istanbul-format coverage-final.json for accurate per-function CRAP scores. Falls back to FALLOW_COVERAGE when the param is omitted. |
audit / check_health | coverage_root | string | 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. |
analyze / check_changed / audit | include_entry_exports | bool | Also report unused exports in entry files. Catches typos in framework-convention exports (e.g. meatdata vs metadata). ORs with the includeEntryExports config value. |
fallow_explain | issue_type | string | Issue type token or rule id to explain |
project_info | entry_points | bool | Request detected entry points |
project_info | files | bool | Request all discovered source files |
project_info | plugins | bool | Request active framework plugins |
project_info | boundaries | bool | Request architecture boundary zones and rules |
analyze | group_by | string | Group output by owner (CODEOWNERS), directory (first path component), package (workspace), or section (GitLab CODEOWNERS [Section] headers, with owners metadata per group) |
Structured actions in tool responses
All tools now return structuredactions arrays on every finding, enabling agents to programmatically apply fixes or suppressions:
- Dead code (
analyze,check_changed): fix action (e.g.remove-export) + suppress action. Agents can use theauto_fixableflag to decide whether to callfix_applyor handle the suggestion manually. See the dead-code CLI reference for action type details. - Health (
check_health,audit): findings carry anactionsarray whose primary entry is selected by a formula-aware rule keyed off thecoverage_tierfield (none/partial/high) andcyclomaticvsmax_crap_threshold. Possible action types:refactor-function,add-tests(CRAP triggered, no coverage, coverage can still clear CRAP),increase-coverage(CRAP triggered, some coverage exists, coverage can still clear CRAP),suppress-line. The first non-suppress-lineentry is primary. When--baseline/--save-baselineis passed ORhealth.suggestInlineSuppression: false,suppress-lineis omitted and a top-levelactions_meta: { suppression_hints_omitted: true, reason }breadcrumb is added (underhealth.actions_metain combined-mode and audit output). Targets getapply-refactoring+ suppress (when evidence exists). Hotspots getrefactor-file+add-tests. - Duplication (
find_dupes,audit):extract-shared+ suppress actions on clone families and groups. - Audit (
audit): inherits actions from all three sub-analyses (dead code, health, duplication).
value_schema on add-to-config actions
add-to-config actions (emitted for unused-dependency, type-only-dependency, test-only-dependency, duplicate-export, and similar findings where the resolution is “add an entry to the fallow config”) carry an optional value_schema field alongside value:
value_schema URL is a JSON Pointer fragment into fallow’s published schema.json. Agents that want to validate value before writing it into a user’s config (for example, to reject a malformed { file, exports } rule object on the ignoreExports action) can fetch the linked schema and apply it locally. The field is strictly additive: actions that did not have a schema before continue to work without one, and agents that ignore the field keep working unchanged.
Combined output from bare fallow
Running bare fallow (no subcommand) executes all analyses in one pass and returns a combined JSON object with dead_code, duplication, and health sections:
CLI vs MCP: when to use which
| CLI | MCP | |
|---|---|---|
| Works with | Any agent that can run shell commands | Agents with MCP support |
| Setup | None (just install fallow) | MCP server configuration needed |
| Output | Any format (JSON, SARIF, human, compact, markdown) | JSON only (structured) |
| Best for | Universal compatibility, CI-like workflows | Typed tool calling, agent frameworks |
Environment variables
| Variable | Description |
|---|---|
FALLOW_BIN | Path to the fallow CLI binary. The MCP server checks, in order: this env var, a sibling binary next to fallow-mcp, then fallow in PATH. |
FALLOW_TIMEOUT_SECS | Subprocess timeout in seconds (default: 120). If the CLI does not exit within this window, the MCP server kills the process and returns a structured error. Increase for very large codebases. |
Error handling
The MCP server returns structured JSON errors when the underlying CLI fails:- Exit code 1: treated as success (issues found, not an error). The full JSON output is returned.
- Exit code 2+: the server passes through the CLI’s structured JSON error from stdout when available. If no JSON is available, it constructs
{"error": true, "message": "...", "exit_code": N}from stderr. - Subprocess timeout: if the CLI does not exit within
FALLOW_TIMEOUT_SECS(default 120s), the server kills the process and returns a timeout error.
Architecture
The MCP server is a thin subprocess wrapper. All analysis logic stays in the CLI binary. The MCP crate only handles protocol framing and argument mapping, built withrmcp (Rust MCP SDK).
- CLI and MCP always produce identical results
- Any fallow CLI update automatically improves MCP
- Install with
cargo install fallow-mcpor grab a binary from GitHub Releases
See also
Agent Skills
Install fallow skills for Claude Code, Cursor, Windsurf, and more.
CI integration
Catch what agents and humans miss in CI.
VS Code extension
Real-time feedback for human developers.
All analysis areas
Dead code, duplication, complexity, and boundaries.