{"id":47636290,"url":"https://github.com/fallow-rs/fallow","last_synced_at":"2026-05-16T10:04:55.792Z","repository":{"id":345027322,"uuid":"1184090452","full_name":"fallow-rs/fallow","owner":"fallow-rs","description":"Codebase intelligence for TypeScript and JavaScript. Free static layer: unused code, duplication, circular deps, complexity hotspots, architecture boundaries. Optional paid runtime layer: hot-path review and cold-path deletion evidence from real production traffic. Rust-native, sub-second, 90 framework plugins.","archived":false,"fork":false,"pushed_at":"2026-05-12T16:29:52.000Z","size":18753,"stargazers_count":2279,"open_issues_count":15,"forks_count":55,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-05-12T16:34:16.093Z","etag":null,"topics":["cli","code-duplication","code-quality","codebase-intelligence","copy-paste-detection","dead-code","developer-tools","duplicate-code","javascript","jscpd","knip","linter","oxc","runtime-intelligence","rust","static-analysis","typescript","unused-code","unused-dependencies","unused-exports"],"latest_commit_sha":null,"homepage":"https://docs.fallow.tools","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fallow-rs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":"ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["bartwaardenburg"]}},"created_at":"2026-03-17T08:40:57.000Z","updated_at":"2026-05-12T15:33:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"6e0199ca-df2d-4716-b75c-9b7715c9442b","html_url":"https://github.com/fallow-rs/fallow","commit_stats":null,"previous_names":["bartwaardenburg/fallow","fallow-rs/fallow"],"tags_count":170,"template":false,"template_full_name":null,"purl":"pkg:github/fallow-rs/fallow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fallow-rs%2Ffallow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fallow-rs%2Ffallow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fallow-rs%2Ffallow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fallow-rs%2Ffallow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fallow-rs","download_url":"https://codeload.github.com/fallow-rs/fallow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fallow-rs%2Ffallow/sbom","scorecard":{"id":1245769,"data":{"date":"2026-04-07T22:09:21Z","repo":{"name":"github.com/fallow-rs/fallow","commit":"621225af0cf364089b9b1684068b9ec7a4c5f794"},"scorecard":{"version":"v5.3.0","commit":"c22063e786c11f9dd714d777a687ff7c4599b600"},"score":5.7,"checks":[{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dependency-update-tool"}},{"name":"Maintained","score":0,"reason":"project was created within the last 90 days. Please review its contents carefully","details":["Warn: Repository was created within the last 90 days."],"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 1/26 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#code-review"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: SECURITY.md:1","Info: Found linked content: SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: SECURITY.md:1","Info: Found text in security policy: SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#security-policy"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: jobLevel 'contents' permission set to 'write': .github/workflows/allocs.yml:35","Warn: jobLevel 'deployments' permission set to 'write': .github/workflows/allocs.yml:37","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/bench-real-world.yml:20","Warn: jobLevel 'deployments' permission set to 'write': .github/workflows/bench-real-world.yml:21","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/bench.yml:34","Warn: jobLevel 'deployments' permission set to 'write': .github/workflows/bench.yml:36","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/bloat.yml:37","Warn: jobLevel 'deployments' permission set to 'write': .github/workflows/bloat.yml:39","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:67","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:113","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:150","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:164","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:177","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:189","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:202","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:215","Info: jobLevel 'pull-requests' permission set to 'read': .github/workflows/ci.yml:26","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:25","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:99","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:125","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ci.yml:232","Info: found token with 'none' permissions: .github/workflows/ci.yml:1","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/conformance.yml:20","Warn: jobLevel 'deployments' permission set to 'write': .github/workflows/conformance.yml:21","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/coverage.yml:21","Warn: jobLevel 'deployments' permission set to 'write': .github/workflows/coverage.yml:22","Info: jobLevel 'contents' permission set to 'read': .github/workflows/cross-arch.yml:29","Info: jobLevel 'contents' permission set to 'read': .github/workflows/ecosystem.yml:34","Info: jobLevel 'contents' permission set to 'read': .github/workflows/release.yml:19","Info: jobLevel 'contents' permission set to 'read': .github/workflows/release.yml:82","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release.yml:223","Info: jobLevel 'contents' permission set to 'read': .github/workflows/release.yml:254","Info: jobLevel 'contents' permission set to 'read': .github/workflows/release.yml:346","Info: jobLevel 'contents' permission set to 'read': .github/workflows/scorecard.yml:17","Info: jobLevel 'actions' permission set to 'read': .github/workflows/scorecard.yml:20","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:17","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:28","Warn: jobLevel 'security-events' permission set to 'write': .github/workflows/test-action.yml:29","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:131","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:180","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:229","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:315","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:80","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:278","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-action.yml:359","Info: found token with 'none' permissions: .github/workflows/allocs.yml:1","Info: found token with 'none' permissions: .github/workflows/bench-real-world.yml:1","Info: found token with 'none' permissions: .github/workflows/bench.yml:1","Info: found token with 'none' permissions: .github/workflows/bloat.yml:1","Info: found token with 'none' permissions: .github/workflows/ci.yml:1","Info: found token with 'none' permissions: .github/workflows/conformance.yml:1","Info: found token with 'none' permissions: .github/workflows/coverage.yml:1","Info: found token with 'none' permissions: .github/workflows/cross-arch.yml:1","Warn: topLevel 'contents' permission set to 'write': .github/workflows/dependabot-auto-merge.yml:8","Info: topLevel 'contents' permission set to 'read': .github/workflows/ecosystem-full.yml:10","Info: found token with 'none' permissions: .github/workflows/ecosystem.yml:1","Info: found token with 'none' permissions: .github/workflows/release.yml:1","Info: found token with 'none' permissions: .github/workflows/scorecard.yml:1","Warn: no topLevel permission defined: .github/workflows/test-action.yml:1"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":7,"reason":"dependency not pinned by hash detected -- score normalized to 7","details":["Warn: npmCommand not pinned by hash: action/scripts/install.sh:14","Warn: npmCommand not pinned by hash: action/scripts/install.sh:16","Warn: npmCommand not pinned by hash: benchmarks/bench-ci.sh:108","Warn: npmCommand not pinned by hash: tests/conformance/run-all.sh:133","Warn: npmCommand not pinned by hash: tests/conformance/run.sh:118","Warn: npmCommand not pinned by hash: .github/workflows/release.yml:268","Warn: npmCommand not pinned by hash: .github/workflows/release.yml:268","Info:  64 out of  64 GitHub-owned GitHubAction dependencies pinned","Info:  16 out of  16 third-party GitHubAction dependencies pinned","Info:   0 out of   7 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#cii-best-practices"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: all commits (5) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#sast"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#license"}},{"name":"Fuzzing","score":10,"reason":"project is fuzzed","details":["Info: RustCargoFuzzer integration found: fuzz/fuzz_targets/fuzz_astro.rs:2","Info: RustCargoFuzzer integration found: fuzz/fuzz_targets/fuzz_css.rs:2","Info: RustCargoFuzzer integration found: fuzz/fuzz_targets/fuzz_mdx.rs:2","Info: RustCargoFuzzer integration found: fuzz/fuzz_targets/fuzz_scripts.rs:2","Info: RustCargoFuzzer integration found: fuzz/fuzz_targets/fuzz_sfc.rs:2"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v2.19.1 not signed: https://api.github.com/repos/fallow-rs/fallow/releases/306258416","Warn: release artifact v2.19.0 not signed: https://api.github.com/repos/fallow-rs/fallow/releases/306221062","Warn: release artifact v2.18.3 not signed: https://api.github.com/repos/fallow-rs/fallow/releases/306136729","Warn: release artifact v2.18.2 not signed: https://api.github.com/repos/fallow-rs/fallow/releases/306120456","Warn: release artifact v2.19.1 does not have provenance: https://api.github.com/repos/fallow-rs/fallow/releases/306258416","Warn: release artifact v2.19.0 does not have provenance: https://api.github.com/repos/fallow-rs/fallow/releases/306221062","Warn: release artifact v2.18.3 does not have provenance: https://api.github.com/repos/fallow-rs/fallow/releases/306136729","Warn: release artifact v2.18.2 does not have provenance: https://api.github.com/repos/fallow-rs/fallow/releases/306120456"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#signed-releases"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/release.yml:249"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#packaging"}},{"name":"CI-Tests","score":10,"reason":"5 out of 5 merged PRs checked by a CI test -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#ci-tests"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"13 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-f886-m6hf-6m8v","Warn: Project is vulnerable to: GHSA-3v7f-55p6-f55p","Warn: Project is vulnerable to: GHSA-c2c7-rcm5-vvqj","Warn: Project is vulnerable to: GHSA-v3rj-xjv7-4jmq","Warn: Project is vulnerable to: GHSA-48c2-rrv3-qjmp","Warn: Project is vulnerable to: GHSA-73rr-hh4g-fpgx","Warn: Project is vulnerable to: GHSA-f23m-r3pf-42rh","Warn: Project is vulnerable to: GHSA-r5fr-rjxr-66jc","Warn: Project is vulnerable to: GHSA-5c6j-r48x-rmvq","Warn: Project is vulnerable to: GHSA-qj8w-gfj5-8c6v","Warn: Project is vulnerable to: GHSA-4w7w-66w2-5vf9","Warn: Project is vulnerable to: GHSA-p9ff-h696-f583","Warn: Project is vulnerable to: GHSA-v2wj-q39q-566r"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#vulnerabilities"}},{"name":"Contributors","score":10,"reason":"project has 4 contributing companies or organizations","details":["Info: found contributions from: bart waardenburg development, entropy-co, minvws, recursive-rewind"],"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#contributors"}}]},"last_synced_at":"2026-04-08T00:06:27.434Z","repository_id":345027322,"created_at":"2026-04-08T00:06:27.434Z","updated_at":"2026-04-08T00:06:27.434Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33098340,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-16T04:41:52.686Z","status":"ssl_error","status_checked_at":"2026-05-16T04:41:52.009Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","code-duplication","code-quality","codebase-intelligence","copy-paste-detection","dead-code","developer-tools","duplicate-code","javascript","jscpd","knip","linter","oxc","runtime-intelligence","rust","static-analysis","typescript","unused-code","unused-dependencies","unused-exports"],"created_at":"2026-04-02T00:09:27.826Z","updated_at":"2026-05-16T10:04:55.777Z","avatar_url":"https://github.com/fallow-rs.png","language":"Rust","funding_links":["https://github.com/sponsors/bartwaardenburg"],"categories":["QA Tools","Tools"],"sub_categories":["Runner","Optimization"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/fallow-rs/fallow/main/assets/logo-dark.svg\"\u003e\n    \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/fallow-rs/fallow/main/assets/logo.svg\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/fallow-rs/fallow/main/assets/logo.svg\" alt=\"fallow\" width=\"290\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eCodebase intelligence for TypeScript \u0026 JavaScript.\u003c/strong\u003e\u003cbr\u003e\n  Free static analysis for unused code, duplication, complexity, and architecture drift.\u003cbr\u003e\n  Optional runtime intelligence for hot paths, cold paths, and runtime-backed code decisions.\u003cbr\u003e\n  \u003cstrong\u003eBuilt for AI-assisted development. No AI inside.\u003c/strong\u003e\u003cbr\u003e\n  \u003cstrong\u003eRust-native. Zero config. Sub-second.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/fallow-rs/fallow/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/fallow-rs/fallow/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/fallow-rs/fallow/actions/workflows/coverage.yml\"\u003e\u003cimg src=\"https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/fallow-rs/fallow/badges/coverage.json\" alt=\"Coverage\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://crates.io/crates/fallow-cli\"\u003e\u003cimg src=\"https://img.shields.io/crates/v/fallow-cli.svg\" alt=\"crates.io\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.npmjs.com/package/fallow\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/fallow.svg\" alt=\"npm\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/fallow-rs/fallow/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"MIT License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://docs.fallow.tools\"\u003e\u003cimg src=\"https://img.shields.io/badge/docs-docs.fallow.tools-blue.svg\" alt=\"Documentation\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n```bash\nnpx fallow --summary\n```\n\n```\nDead Code Summary\n\n      12  Unused files\n      47  Unused exports\n       8  Unused types\n       3  Unused dependencies\n       2  Circular dependencies\n\n      72  Total\n\nDuplication Summary\n\n      18  Clone families\n      53  Clone groups\n   2,140  Duplicated lines\n    4.2%  Duplication rate\n\nHealth Summary\n\n     612  Functions analyzed\n       9  Above threshold\n    89.4  Average maintainability (good)\n```\n\n**Static analysis is free and open source. Runtime intelligence is optional.**\n\n95 framework plugins. No Node.js runtime required for static analysis. No config needed for the first run.\n\nFallow builds a project-wide understanding of your TS/JS codebase instead of checking one file at a time. Use it to review AI-generated changes faster, clean up dead code, reduce duplication, find risky complexity, and enforce architecture boundaries. Add the runtime layer when you want to know what actually executed in production.\n\n**Fallow is the codebase truth layer your coding agent can call. It is not an AI assistant.**\n\n## Install\n\n```bash\nnpm install --save-dev fallow   # or: pnpm add -D fallow / yarn add -D fallow / bun add -d fallow\n```\n\nInstalls 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`.\n\nParsing `fallow --format json` in TypeScript? `import type { CheckOutput } from \"fallow/types\"` gives you the full output contract, version-pinned to your installed CLI.\n\nProgrammatic Node API:\n\n```bash\nnpm install @fallow-cli/fallow-node   # or: pnpm/yarn/bun add @fallow-cli/fallow-node\n```\n\n```ts\nimport { detectDeadCode, detectDuplication, computeHealth } from '@fallow-cli/fallow-node';\n\nconst deadCode = await detectDeadCode({ root: process.cwd() });\nconst dupes = await detectDuplication({ root: process.cwd(), mode: 'mild', minTokens: 30 });\nconst health = await computeHealth({ root: process.cwd(), score: true, ownershipEmails: 'handle' });\n```\n\n## Start here\n\n```bash\nfallow                      # Dead code + duplication + health\nfallow dead-code            # Cleanup candidates\nfallow dupes                # Repeated logic\nfallow health               # Complexity + refactor targets\nfallow fix --dry-run        # Preview automatic cleanup\n```\n\n## What it finds\n\n- **Dead code**: unused files, exports, dependencies, types, cycles, boundaries, stale suppressions, unused pnpm `catalog:` entries, empty named pnpm catalog groups, unresolved pnpm `catalog:` references (a `package.json` references a catalog that does not declare the package, so `pnpm install` would fail), unused or misconfigured pnpm `overrides:` entries (an override forces a version no workspace package declares or resolves in `pnpm-lock.yaml`, or an override key/value is malformed), GraphQL documents linked by `#import`, plus opt-in API hygiene checks such as private type leaks\n- **Duplication**: repeated blocks from exact to semantic clones\n- **Complexity**: high-risk functions, file scores, hotspots, and refactor targets\n- **Architecture drift**: boundary violations across layers and modules\n\n## Why Fallow exists\n\nLinters check files. TypeScript checks types. Fallow checks the codebase.\n\nIt builds a module graph across the whole project so it can find problems that file-local tools cannot:\n\n| What | Linter | Fallow |\n|---|---|---|\n| Unused variable in a function | yes | no |\n| Unused export that nothing imports | no | yes |\n| File that nothing imports | no | yes |\n| Circular dependency across modules | no | yes |\n| Duplicate code blocks across files | no | yes |\n| Dependency in package.json never imported | no | yes |\n\n[Full comparison: fallow vs ESLint, Biome, knip, ts-prune](https://docs.fallow.tools/explanations/fallow-vs-linters)\n\n## Why teams using AI need Fallow\n\nAI accelerates code creation. It does not eliminate review, cleanup, or architecture drift.\n\nWhen Claude Code, Codex, Cursor, or other tools generate changes, teams still need to know:\n\n- did this introduce dead code?\n- did it duplicate logic that already existed?\n- did complexity get worse?\n- did the change cross a boundary it should not cross?\n- is this code on a hot path or a cold one?\n- what should the reviewer read closely first?\n\nFallow answers those questions with deterministic, graph-based analysis and structured output, so both humans and agents can act on facts instead of guesses.\n\n## How agents use Fallow\n\nAgents do not need to guess from limited context. They can call Fallow directly via the CLI or MCP.\n\nCommon agent workflow:\n\n1. generate or edit code\n2. run `fallow --format json`\n3. inspect dead code, duplication, health findings, and per-issue `actions`\n4. apply safe fixes or adjust the patch before opening a PR\n5. hand the result to a human reviewer with better evidence\n\n```bash\nnpx fallow --format json\nnpx fallow audit --format json\nnpx fallow fix --dry-run --format json\n```\n\nFor full adoption instead of one-off review, see the [Fallow compliance happy path](https://github.com/fallow-rs/fallow/blob/main/docs/fallow-compliance.md). It defines the end state clearly: repo-wide dead code and duplication findings are fixed or explicitly documented, `fallow health` reaches `Above threshold: 0` for the repo's chosen thresholds, and `fallow audit` becomes the change-set gate once adoption is wired in. It also includes a copy-paste agent onboarding prompt.\n\nSee [Agent integration](https://docs.fallow.tools/integrations/mcp) for MCP setup and the full list of structured tools.\n\n## More static commands\n\n```bash\nfallow audit                 # Audit changed files (verdict: pass/warn/fail)\nfallow explain unused-export # Explain a rule without analyzing\nfallow --production-health   # Combined mode: production health, full dead-code/dupes\nfallow watch                 # Re-analyze on file changes\nfallow fix                   # Apply automatic cleanup after previewing\n```\n\nCombined mode and `fallow audit` support per-analysis production mode. Precedence is CLI flags, then environment variables, then config:\n\n```jsonc\n{\n  \"production\": {\n    \"health\": true,\n    \"deadCode\": false,\n    \"dupes\": false\n  }\n}\n```\n\nUse `--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.\n\nPrecedence (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:\n\n```bash\n# Run health in production mode, dead-code and dupes on the full tree\nfallow --production-health\n\n# Same, via env var (useful in CI templates that pass env-only)\nFALLOW_PRODUCTION_HEALTH=true fallow\n\n# Per-analysis env wins over the global env, so this runs health in production mode\n# even though the global env says off (the typical CI-template defaults case)\nFALLOW_PRODUCTION=false FALLOW_PRODUCTION_HEALTH=true fallow\n\n# CLI flags beat env vars; this turns ALL three on regardless of any FALLOW_PRODUCTION_* env\nfallow --production\n```\n\n## Dead code\n\nFinds unused files, exports, dependencies, types, enum members, class members, 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, framework conventions, and plugin patterns. Arrow-wrapped dynamic imports (`React.lazy`, `loadable`, `defineAsyncComponent`) 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.\n\n```bash\nfallow dead-code                          # All dead code issues\nfallow dead-code --unused-exports         # Only unused exports\nfallow dead-code --private-type-leaks     # Opt-in private type leak API hygiene\nfallow dead-code --circular-deps          # Only circular dependencies\nfallow dead-code --boundary-violations    # Only boundary violations\nfallow dead-code --stale-suppressions     # Only stale suppression comments\nfallow dead-code --production             # Exclude test/dev files\nfallow dead-code --changed-since main     # Only changed files (for PRs)\nfallow dead-code --file src/utils.ts       # Single file (lint-staged integration)\nfallow dead-code --include-entry-exports  # Also check exports from entry files\nfallow dead-code --group-by owner         # Group by CODEOWNERS for team triage\nfallow dead-code --group-by directory     # Group by first directory component\nfallow dead-code --group-by package       # Group by workspace package (monorepo)\nfallow dead-code --group-by section       # Group by GitLab CODEOWNERS section\n```\n\n## Duplication\n\nFinds copy-pasted code blocks across your codebase. 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.\n\n```bash\nfallow dupes                              # Default (mild mode)\nfallow dupes --mode semantic              # Catch clones with renamed variables\nfallow dupes --skip-local                 # Only cross-directory duplicates\nfallow dupes --group-by owner             # Partition clone groups by CODEOWNERS team\nfallow dupes --group-by directory         # Partition clone groups by directory\nfallow dupes --trace src/utils.ts:42      # Show all clones of code at this location\n```\n\nFour detection modes: **strict** (exact tokens), **mild** (default, AST-based), **weak** (different string literals), **semantic** (renamed variables and literals).\n\n## Complexity\n\nSurfaces the most complex functions in your codebase and identifies where to spend refactoring effort. Angular templates are included as synthetic `\u003ctemplate\u003e` entries when they use control flow or complex bindings, both for external `templateUrl` files and inline `@Component({ template: \\`...\\` })` decorators.\n\n```bash\nfallow health                             # Functions/templates exceeding thresholds\nfallow health --score                     # Project health score (0-100) with letter grade\nfallow health --min-score 70              # CI gate: fail if score drops below 70\nfallow health --top 20                    # 20 most complex functions\nfallow health --file-scores               # Per-file maintainability index (0-100)\nfallow health --hotspots                  # Riskiest files (git churn x complexity)\nfallow health --hotspots --ownership      # Add bus factor, owner, drift signals\nfallow health --workspace @scope/app      # Scope vital signs + score to one package\nfallow health --group-by package --score  # Per-package vital signs + score (monorepos)\nfallow health --targets                   # Ranked refactoring recommendations\nfallow health --targets --effort low      # Only quick-win refactoring targets\nfallow health --coverage-gaps             # Static test coverage gaps\nfallow health --coverage coverage/coverage-final.json\nfallow health --coverage artifacts/coverage.json --coverage-root /home/runner/work/myapp\nfallow health --runtime-coverage ./coverage\nfallow health --runtime-coverage ./coverage --min-invocations-hot 250\nfallow health --trend                     # Compare against saved snapshot\nfallow health --changed-since main        # Only changed files\n```\n\n## Runtime intelligence (optional)\n\nStatic analysis answers: **what is connected to what?**\n\nRuntime intelligence answers: **what actually ran?**\n\nFallow Runtime is the optional paid team layer. It uses runtime coverage as the collection engine (V8 dumps via `NODE_V8_COVERAGE=...` and Istanbul `coverage-final.json` files), then merges that evidence into `fallow health` so teams and coding agents can:\n\n- review changes on hot production paths more carefully\n- delete cold code with stronger evidence\n- prioritize refactors by runtime importance\n- spot stale feature-flag branches and stale runtime code\n- give agents factual usage data instead of assumptions\n\n```bash\nfallow license activate --trial --email you@company.com\nfallow coverage setup\nfallow health --runtime-coverage ./coverage\nfallow coverage analyze --cloud --repo owner/repo --format json\n```\n\nStatic `coverage_gaps` and runtime `runtime_coverage` are separate layers in the same `health` surface:\n\n| Surface | Flag | Input | Answers | License |\n|:--|:--|:--|:--|:--|\n| Static test reachability | `--coverage-gaps` | none | which runtime files/exports have no test dependency path | no |\n| Exact CRAP scoring | `--coverage` | Istanbul JSON file or `coverage-final.json` directory | how covered each function is for CRAP computation | no |\n| Runtime runtime coverage | `--runtime-coverage` | V8 directory, V8 JSON file, or Istanbul JSON file | which functions actually executed, which stayed cold, which are hot | yes |\n\nSetup details:\n\n- `fallow license activate --trial --email ...` starts a trial and stores the signed license locally\n- `fallow license refresh` refreshes the stored license before the hard-fail window\n- `fallow coverage setup` detects your framework and package manager, installs the sidecar if needed, writes a collection recipe, and resumes from the current setup state on re-run\n- `fallow coverage setup --yes --json` emits deterministic agent-readable setup instructions without prompts, file writes, installs, or network calls. Add `--explain` to include a `_meta` block with field definitions, enum values, warning semantics, and the docs URL. In workspaces it emits per-runtime-package `members[]`, unions `runtime_targets`, prefixes member file paths, and skips pure workspace aggregator roots\n- `fallow coverage analyze --cloud --repo owner/repo --format json` explicitly fetches the latest cloud runtime facts for a repo, merges them locally with the current AST/static analysis, and emits the same `runtime_coverage` JSON block. `FALLOW_API_KEY` alone does not enable cloud mode; pass `--cloud`, `--runtime-coverage-cloud`, or set `FALLOW_RUNTIME_COVERAGE_SOURCE=cloud`.\n- `fallow coverage upload-inventory` pushes a static function inventory to fallow cloud so the dashboard's `Untracked` filter (functions that exist but never run) lights up. Runs in CI, respects `.gitignore` + `--exclude-paths`, preserves same-named functions by their line-aware cloud identity, and warns when inventory paths do not overlap recent runtime paths. For containerized deployments, pass `--path-prefix /app` (or your Dockerfile `WORKDIR`) so inventory paths match what the runtime beacon reports\n- `fallow coverage upload-source-maps` uploads build `.map` files from CI so bundled runtime coverage resolves back to original source paths. Defaults to `dist/**/*.map`, `$GITHUB_SHA`, and basename matching; pass `--strip-path=false` when coverage reports bundle paths like `assets/app.js`\n- The sidecar can be installed globally or as a project devDependency; fallow resolves `FALLOW_COV_BIN`, project-local shims, package-manager bin lookups, `~/.fallow/bin/fallow-cov`, and `PATH`\n- `fallow health --runtime-coverage \u003cpath\u003e` accepts a V8 directory, a single V8 JSON file, or a single Istanbul coverage map JSON file (commonly `coverage-final.json`)\n- `fallow health --coverage \u003cpath\u003e` accepts a single Istanbul coverage map JSON file or a directory containing `coverage-final.json`\n- `--coverage-root \u003cpath\u003e` must be an absolute prefix from the Istanbul file paths. Use it when coverage was generated in CI or Docker with a different checkout root, for example `fallow health --coverage artifacts/coverage-final.json --coverage-root /home/runner/work/myapp`\n- V8 dumps that include Node's `source-map-cache` are remapped through supported source-map paths before analysis, including file paths, relative paths, `webpack://...`, and `vite://...`; unsupported virtual schemes safely fall back to raw V8 handling\n- `fallow health --changed-since \u003cref\u003e --runtime-coverage \u003cpath\u003e` promotes touched hot paths to a `hot-path-touched` verdict during change review\n\nRuntime coverage is merged into the same human, JSON, SARIF, compact, markdown, and CodeClimate outputs as the rest of the health report.\n\nRead more: [Static vs runtime intelligence](https://docs.fallow.tools/explanations/static-vs-runtime) | [Runtime coverage](https://docs.fallow.tools/analysis/runtime-coverage)\n\n## Audit\n\nQuality gate for AI-generated code and PRs. Combines dead code + complexity + duplication scoped to changed files.\n\n```bash\nfallow audit                              # Auto-detects base branch\nfallow audit --base main                  # Explicit base ref\nfallow audit --base HEAD~3               # Audit last 3 commits\nfallow audit --production-health          # Production health, full dead-code/dupes\nfallow audit --coverage artifacts/coverage-final.json --coverage-root /home/runner/work/myapp\nfallow audit --gate all                   # Fail on inherited findings too\nfallow audit --format json                # Structured output with verdict\n```\n\nReturns a verdict: **pass** (exit 0), **warn** (exit 0, warn-severity only), or **fail** (exit 1). By default, audit compares the current tree with the base ref and gates only findings introduced by the changeset; inherited findings are counted in JSON `attribution`, individual issue objects get `introduced: true|false`, and inherited findings are shown as context. Set `--gate all` or `audit.gate: \"all\"` to fail on every finding in changed files without running the extra base-snapshot attribution pass.\n\n`audit` forwards `--coverage` and `--coverage-root` to its health sub-analysis for exact Istanbul-backed CRAP scoring. Relative `--coverage` paths resolve against `--root`; `--coverage-root` must be an absolute prefix from the coverage data. `FALLOW_COVERAGE` is used as the fallback when `--coverage` is omitted.\n\nAudit caches base snapshots under `.fallow/cache/` and may keep a SHA-scoped temporary git worktree for reuse across runs against the same 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. Transient worktrees are removed on normal exit. Use `--no-cache` to disable snapshot and reusable-worktree caching; if a process is force-killed, run `git worktree prune` to clean up stale `.git/worktrees/fallow-audit-base-*` entries.\n\n**Per-analysis baselines.** When touching legacy files with pre-existing issues, reuse the baselines saved by the individual subcommands so audit only fails on genuinely new findings:\n\n```bash\n# Save once from a clean ref\nfallow dead-code --save-baseline fallow-baselines/dead-code.json\nfallow health    --save-baseline fallow-baselines/health.json\nfallow dupes     --save-baseline fallow-baselines/dupes.json\n\n# Feed into audit on every PR\nfallow audit \\\n  --dead-code-baseline fallow-baselines/dead-code.json \\\n  --health-baseline    fallow-baselines/health.json \\\n  --dupes-baseline     fallow-baselines/dupes.json\n```\n\nKeep committed baselines outside `.fallow/`; that directory is for cache and local data and is typically gitignored. `fallow-baselines/` is the recommended default. Configure defaults in `.fallowrc.json` under `audit.deadCodeBaseline` / `audit.healthBaseline` / `audit.dupesBaseline` so CI stays one command (`fallow audit`). CLI flags override config.\n\n## CI integration\n\n```yaml\n# GitHub Action\n- uses: fallow-rs/fallow@v2\n  with:\n    command: audit\n    max-crap: 30\n    coverage: artifacts/coverage-final.json\n    coverage-root: /home/runner/work/myapp\n\n# GitLab CI -- remote include\ninclude:\n  - remote: 'https://raw.githubusercontent.com/fallow-rs/fallow/vX.Y.Z/ci/gitlab-ci.yml'\nfallow:\n  extends: .fallow\n  variables:\n    FALLOW_COMMAND: \"audit\"\n    FALLOW_MAX_CRAP: \"30\"\n    FALLOW_COVERAGE: \"artifacts/coverage-final.json\"\n    FALLOW_COVERAGE_ROOT: \"/home/runner/work/myapp\"\n```\n\n```yaml\n# GitLab CI -- vendored include when runners cannot reach GitHub raw\n# Run once locally: npx fallow ci-template gitlab --vendor\n# Commit the generated ci/ + action/ files.\ninclude:\n  - local: 'ci/gitlab-ci.yml'\n\nfallow:\n  extends: .fallow\n```\n\n```yaml\n# Any CI\nscript:\n  - npx fallow --ci\n```\n\n`--ci` enables SARIF output, quiet mode, and non-zero exit on issues. Also supports:\n\n- `--group-by owner|directory|package|section` -- group output by CODEOWNERS ownership, directory, workspace package, or GitLab CODEOWNERS `[Section]` headers for team-level triage\n- `--summary` -- show only category counts (no individual issues)\n- `--changed-since main` -- analyze only files touched in a PR\n- `--changed-workspaces origin/main` -- scope monorepo analysis to workspaces containing any changed file (CI primitive; fails hard on git errors so CI never silently widens back to the full repo)\n- `--baseline` / `--save-baseline` -- fail only on **new** issues\n- `--fail-on-regression` / `--tolerance 2%` -- fail only if issues **grew** beyond tolerance\n- `--format sarif` -- upload to GitHub Code Scanning\n- `--format codeclimate` / `--format gitlab-codequality` -- GitLab Code Quality inline MR annotations\n- `--format pr-comment-github` / `--format pr-comment-gitlab` -- typed sticky PR/MR comment markdown\n- `--format review-github` / `--format review-gitlab` -- typed inline review envelopes for CI scripts\n- `--format annotations` -- GitHub Actions inline PR annotations (no Action required)\n- `--format json` / `--format markdown` -- for custom workflows (JSON includes machine-actionable `actions` per issue)\n- `--format badge` -- shields.io-compatible SVG health badge (`fallow health --format badge \u003e badge.svg`)\n\nBoth the GitHub Action and GitLab CI template auto-detect your package manager (npm/pnpm/yarn) from lock files, so install/uninstall commands in review comments match your project.\n\nSARIF upload requires GitHub Code Scanning, which is available on public repositories and on private repositories with GitHub Advanced Security enabled. If it is unavailable, the action skips upload with a warning and leaves the job summary and primary output intact.\n\nGitHub inline review comments target the current PR file state (`side: RIGHT`). Findings on deleted lines are not modeled yet; fallow's diagnostics are current-state oriented in normal use.\n\nAdopt incrementally -- surface issues without blocking CI, then promote when ready:\n\n```jsonc\n{ \"rules\": { \"unused-files\": \"error\", \"unused-exports\": \"warn\", \"circular-dependencies\": \"off\" } }\n```\n\n### GitLab CI rich MR comments\n\nThe GitLab CI template can post rich comments directly on merge requests -- summary comments with collapsible sections and inline review discussions with suggestion blocks.\n\n| Variable | Default | Description |\n|---|---|---|\n| `FALLOW_COMMENT` | `\"false\"` | Post a summary comment on the MR with collapsible sections per analysis |\n| `FALLOW_REVIEW` | `\"false\"` | Post inline MR discussions at the relevant lines, with `suggestion` blocks for unused exports and unused imports |\n| `FALLOW_MAX_COMMENTS` | `\"50\"` | Maximum number of inline review comments |\n| `FALLOW_SCRIPTS_REF` | `\"\"` | Pinned tag or commit for remote MR-integration scripts; leave empty to prefer vendored local `ci/` + `action/` scripts |\n| `FALLOW_VERSION` | `\"\"` | Fallow version to install. Empty reads the project's `package.json` `fallow` dependency, then falls back to `latest`; set explicitly to override the local pin |\n\nIn MR pipelines, `--changed-since` is set automatically to scope analysis to changed files. Fallow edits sticky comments in place and fingerprints inline review comments so repeated runs can skip duplicates.\n\nThe comment merging pipeline groups unused exports per file and deduplicates clone reports, keeping MR threads readable.\n\nFor remote includes, pin the template to a release tag and keep `FALLOW_SCRIPTS_REF` on the same tag or commit. If your GitLab runners cannot reach `raw.githubusercontent.com`, run `npx fallow ci-template gitlab --vendor` locally, commit the generated `ci/` and `action/` files, and use GitLab's local include syntax. The vendored template prefers local scripts and skips the remote fetch path entirely.\n\nA `GITLAB_TOKEN` (PAT or project access token with `api` scope) is required for summary comments and inline MR discussions. GitLab's documented `CI_JOB_TOKEN` permissions allow reading MR notes, but not creating, updating, or deleting them. `CI_JOB_TOKEN` is still useful for GitLab package registry authentication.\n\nGitLab setup gotchas:\n\n- The template sets `GIT_STRATEGY: \"fetch\"` so shared templates that set `GIT_STRATEGY=none` do not leave fallow without a working tree.\n- The template sets `GIT_DEPTH: \"0\"` so `--changed-since` can diff against the MR base SHA without shallow-clone ambiguity.\n- For private GitLab npm registries, create `.npmrc` during the job with `${CI_PROJECT_ID}` and `${CI_JOB_TOKEN}` rather than committing tokens.\n- For pnpm projects with `minimumReleaseAge`, add `fallow` and `@fallow-cli/*` to `minimumReleaseAgeExclude` when you need to consume a just-published fallow release immediately.\n\n```yaml\n# .gitlab-ci.yml -- full example with rich MR comments\ninclude:\n  - remote: 'https://raw.githubusercontent.com/fallow-rs/fallow/vX.Y.Z/ci/gitlab-ci.yml'\n\nfallow:\n  extends: .fallow\n  variables:\n    FALLOW_COMMENT: \"true\"       # Summary comment with collapsible sections\n    FALLOW_REVIEW: \"true\"        # Inline discussions with suggestion blocks\n    FALLOW_MAX_COMMENTS: \"30\"    # Cap inline comments (default: 50)\n    FALLOW_SCRIPTS_REF: \"vX.Y.Z\" # Match the pinned template ref when using remote scripts\n    FALLOW_FAIL_ON_ISSUES: \"true\"\n```\n\n## Configuration\n\nWorks out of the box. When you need to customize, create `.fallowrc.json` or run `fallow init`:\n\n```jsonc\n// .fallowrc.json\n{\n  \"$schema\": \"https://raw.githubusercontent.com/fallow-rs/fallow/main/schema.json\",\n  \"entry\": [\"src/workers/*.ts\", \"scripts/*.ts\"],\n  \"ignorePatterns\": [\"**/*.generated.ts\"],\n  \"ignoreDependencies\": [\"autoprefixer\"],\n  \"ignoreExportsUsedInFile\": true,\n  \"rules\": {\n    \"unused-files\": \"error\",\n    \"unused-exports\": \"warn\",\n    \"unused-types\": \"off\"\n  },\n  \"health\": {\n    \"maxCyclomatic\": 20,\n    \"maxCognitive\": 15,\n    \"maxCrap\": 30\n  }\n}\n```\n\nArchitecture boundary presets enforce import rules between layers with zero manual config:\n\n```jsonc\n{ \"boundaries\": { \"preset\": \"bulletproof\" } } // or: layered, hexagonal, feature-sliced\n```\n\nFor custom feature-module boundaries, `autoDiscover` turns each immediate child\ndirectory into its own zone while rules still reference the logical parent:\n\n```jsonc\n{\n  \"boundaries\": {\n    \"zones\": [\n      { \"name\": \"app\", \"patterns\": [\"src/app/**\"] },\n      { \"name\": \"features\", \"autoDiscover\": [\"src/features\"] },\n      { \"name\": \"shared\", \"patterns\": [\"src/shared/**\"] }\n    ],\n    \"rules\": [\n      { \"from\": \"app\", \"allow\": [\"features\", \"shared\"] },\n      { \"from\": \"features\", \"allow\": [\"shared\"] }\n    ]\n  }\n}\n```\n\nTop-level files inside an `autoDiscover` directory (e.g. `src/features/index.ts` barrel, `src/features/types.ts`) do not match any auto-discovered child pattern and stay unclassified, so barrel files can re-export children without false-positive cross-zone violations. The same applies to the Bulletproof preset's `features` zone. To classify top-level files strictly, add a `patterns` field to the zone (fallow then warns about the barrel-violation footgun).\n\nRun `fallow list --boundaries` to inspect the expanded rules. TOML also supported (`fallow init --toml`). The init command auto-detects your project structure (monorepo layout, frameworks, existing config) and generates a tailored config. It also adds `.fallow/` to your `.gitignore` (cache and local data). Scaffold a pre-commit `fallow audit` hook with `fallow hooks install --target git`; the hook uses the current branch upstream as its base and falls back to `--branch` (or the detected default branch) when no upstream is set. For agent gates, use `fallow hooks install --target agent`. Migrating from knip or jscpd? Run `fallow migrate`.\n\nSee the [full configuration reference](https://docs.fallow.tools/configuration/overview) for all options.\n\n## Framework plugins\n\n95 built-in plugins detect entry points, convention exports, config-defined aliases, and template-visible usage for your framework automatically.\n\n| Category | Plugins |\n|---|---|\n| **Frameworks** | Next.js, Nuxt, Remix, Qwik, SvelteKit, Gatsby, Astro, Angular, NestJS, AdonisJS, Lit, Expo, Expo Router, Electron, and more |\n| **Bundlers** | Vite, Webpack, Rspack, Rsbuild, Rollup, Rolldown, Tsup, Tsdown, Parcel |\n| **Testing** | Vitest, Jest, Playwright, Cypress, Storybook, Mocha, Ava, tap, tsd |\n| **CSS** | Tailwind, PostCSS, UnoCSS, PandaCSS |\n| **Databases \u0026 Backend** | Prisma, Drizzle, Knex, TypeORM, Kysely, Convex |\n| **Blockchain** | Hardhat |\n| **Monorepos** | Turborepo, Nx, Changesets, Syncpack, pnpm |\n\n[Full plugin list](https://docs.fallow.tools/frameworks/built-in) -- missing one? Add a [custom plugin](https://docs.fallow.tools/frameworks/custom-plugins) or [open an issue](https://github.com/fallow-rs/fallow/issues).\n\n## Editor \u0026 AI support\n\nFallow is not an AI assistant. It is the codebase truth layer your assistant can call.\n\n- **VS Code extension** -- tree views, status bar, one-click fixes, auto-download LSP binary ([Marketplace](https://github.com/fallow-rs/fallow/tree/main/editors/vscode))\n- **LSP server** -- real-time diagnostics, hover info, code actions, Code Lens with reference counts\n- **Agent Skill + MCP server** -- version-matched AI agent guidance ships in the npm package, with MCP integration for Claude Code, Codex, Cursor, Windsurf, and other agents ([fallow-skills](https://github.com/fallow-rs/fallow-skills))\n- **JSON `actions` array** -- every issue in `--format json` output includes fix suggestions with `auto_fixable` flag, so agents can self-correct\n\n## Performance\n\nBenchmarked on real open-source projects (median of 5 runs with 2 warmups, Apple M5).\n\n### Dead code: fallow vs knip\n\n| Project | Files | fallow | knip v5 | knip v6 | vs v5 | vs v6 |\n|:--------|------:|-------:|--------:|--------:|------:|------:|\n| [zod](https://github.com/colinhacks/zod) | 174 | **25ms** | 650ms | 330ms | 26x | 13x |\n| [fastify](https://github.com/fastify/fastify) | 286 | **27ms** | 933ms | 222ms | 34x | 8x |\n| [preact](https://github.com/preactjs/preact) | 244 | **200ms** | 911ms | 2.15s | 5x | 11x |\n| [vue/core](https://github.com/vuejs/core) | 522 | **68ms** | ---* | ---* | --- | --- |\n| [TanStack/query](https://github.com/TanStack/query) | 901 | **330ms** | 2.66s | 1.08s | 8x | 3.3x |\n| [vite](https://github.com/vitejs/vite) | 1,420 | **378ms** | ---* | ---* | --- | --- |\n| [svelte](https://github.com/sveltejs/svelte) | 3,337 | **363ms** | 1.95s | 714ms | 5x | 2x |\n| [next.js](https://github.com/vercel/next.js) | 20,416 | **1.72s** | ---* | ---* | --- | --- |\n\nOn the current benchmark fixtures, knip does not produce valid JSON results for vite, vue/core, and next.js. fallow completes on all three. See the [full comparison page](https://docs.fallow.tools/migration/comparison) for the complete matrix and current caveats. * knip exits without valid results on those fixtures.\n\n### Duplication: fallow vs jscpd\n\n| Project | Files | fallow | jscpd | Speedup |\n|:--------|------:|-------:|------:|--------:|\n| [fastify](https://github.com/fastify/fastify) | 286 | **76ms** | 1.96s | 26x |\n| [vue/core](https://github.com/vuejs/core) | 522 | **124ms** | 3.11s | 25x |\n| [next.js](https://github.com/vercel/next.js) | 20,416 | **2.89s** | 24.37s | 8x |\n\nNo TypeScript compiler, no Node.js runtime needed to analyze your code. [Fallow vs linters](https://docs.fallow.tools/explanations/fallow-vs-linters) | [Reproduce benchmarks](https://github.com/fallow-rs/fallow/tree/main/benchmarks)\n\n## Suppressing findings\n\n```ts\n// fallow-ignore-next-line unused-export\nexport const keepThis = 1;\n\n// fallow-ignore-next-line unused-export, complexity\nexport const publicComplexHelper = (value: number) =\u003e value;\n\n// fallow-ignore-file\n// Suppress all issues in this file\n```\n\nUse a comma-separated issue-kind list when one line has multiple findings.\n\nAlso supports JSDoc visibility tags (`/** @public */`, `/** @internal */`, `/** @beta */`, `/** @alpha */`) to suppress unused export reports for library APIs consumed externally.\n\nSet `ignoreExportsUsedInFile: true` when exported helpers should stay quiet while another symbol in the same file still references them, but should be reported once they become completely unreferenced. The `{ \"type\": true, \"interface\": true }` object form is accepted for knip parity; fallow groups type aliases and interfaces under one issue, so both type-kind fields behave identically. References inside the export specifier itself (`export { foo }`, `export default foo`) do not count as same-file uses.\n\n## Limitations\n\nfallow uses syntactic analysis -- no type information. This is what makes it fast, but type-level dead code is out of scope. Use [inline suppression comments](#suppressing-findings) or [`ignoreExports`](https://docs.fallow.tools/configuration/overview#ignoring-specific-exports) for edge cases.\n\n## Documentation\n\n- [Getting started](https://docs.fallow.tools)\n- [Configuration reference](https://docs.fallow.tools/configuration/overview)\n- [CI integration guide](https://docs.fallow.tools/integrations/ci)\n- [Migrating from knip](https://docs.fallow.tools/migration/from-knip)\n- [Fallow compliance happy path](https://github.com/fallow-rs/fallow/blob/main/docs/fallow-compliance.md)\n- [Plugin authoring guide](https://github.com/fallow-rs/fallow/blob/main/docs/plugin-authoring.md)\n\n## Contributing\n\nMissing a framework plugin? Found a false positive? [Open an issue](https://github.com/fallow-rs/fallow/issues).\n\n```bash\ncargo build --workspace \u0026\u0026 cargo test --workspace\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffallow-rs%2Ffallow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffallow-rs%2Ffallow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffallow-rs%2Ffallow/lists"}