- a repo-level Fallow policy encoded in config
- dead code fixed or intentionally modeled
- duplication at or below your chosen threshold
- complex functions refactored or consciously widened with a written justification
fallow auditenforcing the same policy on changed files
Repo clean vs PR clean
These are different goals. Both matter. Do them in order.Repo clean (this guide)
Full-repo analysis to understand and clean the whole codebase.
Use
fallow, fallow dead-code, fallow dupes, and fallow health.PR clean
Changed-files gate that enforces the policy on every PR.
Use
fallow audit after the repo is clean.Before you start
Coming from knip?
Run
fallow migrate first to port your knip config, then follow this guide.Large monorepo?
Apply this flow per workspace package. Use
fallow --workspace <name> and a shared root config.1. First run: get the whole picture
From your project root:fallow init auto-detects your project structure (package manager, workspaces, frameworks) and generates a tailored starting config. It also adds .fallow/ to your .gitignore.
2. Decide the project policy before triage
Do not start by suppressing findings one by one. That path turns into an ever-growing list of inline exceptions and no coherent policy.Not the policy owner? Run section 3 first on a branch, then bring the findings into the policy discussion. Fallow output is a good forcing function for the “what do we actually care about” conversation.
- what counts as a real entry point (workers, scripts, route files, dynamically loaded modules)
- which files are generated or out of scope
- which packages are public APIs that ship exports outside the repo
- which dependencies are runtime-provided or intentionally retained
- which health thresholds you actually want to enforce
- whether duplication should warn or fail
maxCyclomatic: 20 and maxCognitive: 15; override in a health block only when your repo’s realistic baseline differs.
3. Work findings in the right order
Use this order for most existing repos. Each step removes noise that would otherwise distort the next step.Fix unresolved imports and unlisted dependencies
High confidence, low debate. These are real bugs waiting to happen and should be cleared first.
Delete unused files
Unreachable files are usually safe cleanup. Use
fallow list --entry-points to sanity-check reachability before deleting anything you are unsure about.Remove unused dependencies
Remove dead packages early. This reduces noise in later steps and speeds up installs.
Clean up unused exports, types, enum members, and class members
Usually the biggest category. Fix real dead code. Model intentional API surface with visibility tags or config instead of suppressing it. Hand this step to an agent using the prompt in section 8: the findings are mechanical but the decisions (delete vs. mark Add
@public vs. add to entry) benefit from code-aware judgement.--unused-enum-members and --unused-class-members when you want to focus on those categories explicitly. See the fallow dead-code reference for every filter flag.Consolidate duplication
Merge repeated logic into shared helpers. Only ignore generated or template-heavy files when the duplication is genuinely intentional.
4. Match the reason to the right mechanism
Do not default to inline suppression. Pick the mechanism that matches the reason.External or public API
Exports consumed outside the repo (published libraries, SDKs, public packages). Prefer, in order:@public,@internal,@beta,@alphaJSDoc visibility tags on the exportpublicPackagesas the coarse switch for “this whole package is external API”ignoreExportsonly when file-level or export-level exceptions cannot be expressed any other way
publicPackages and visibility tags are complementary, not alternatives: publicPackages marks the package as externally consumed; @public/@internal tags distinguish public API from internal helpers that happen to be exported for cross-file use.
Framework or runtime-discovered entry points
Files your framework or runtime invokes but no other module imports directly (workers, CLI scripts, route files, plugin modules). Prefer, in order:- built-in plugin detection (Next.js, Vite, NestJS, Remotion, and dozens more are handled out of the box)
entryfor project-specific entry globsdynamicallyLoadedfor code pulled in through reflection, manifests, or dynamic importsfallow list --entry-pointsto inspect what Fallow already considers reachable
Generated or vendored files
Files produced by a build step, code generator, or vendored third-party bundle. Prefer:ignorePatternsto exclude them from analysis entirelyhealth.ignorewhen the noise is health-only and dead-code analysis should still run- duplication configuration for clone-heavy generated code
Runtime-provided or intentionally retained dependencies
Packages installed for runtime usage only (no static import), CLI tools, or peer dependencies. Prefer:ignoreDependencieswith the exact package names
One-off intentional unused export
An export you want to keep around deliberately (compatibility shims, future API). Prefer:/** @expected-unused */on the export
One-off false positive
A specific site where Fallow is wrong and no config rule captures the reason cleanly. Prefer:// fallow-ignore-next-line <issue>on the line above// fallow-ignore-file <issue>only when the whole file is truly exceptional
Repo-wide policy change
The project genuinely has a different standard for a whole category. Prefer:rules,health, duplication thresholds, oroverridesblocks
See suppression for the full decision tree and examples, and configuration overview for every key.
5. Keep exceptions narrow and reviewable
Narrow exceptions are an asset. Broad exceptions are a debt. Good:- a single
@publicexport on a library entry point - one
ignoreDependenciesentry for a runtime-provided package - one
entrypattern for worker scripts - one file-level generated-code ignore with a comment explaining why
- broad
ignorePatternsthat silently exclude half the repo - repeated inline suppressions that could be one config rule
- raising global
health.maxCyclomaticto hide a handful of hotspots (acceptable only when the new threshold reflects a thought-through project standard with written justification)
6. Define done
Work in two stages. Most teams shipfallow audit at the end of stage 1 and finish stage 2 over the following weeks.
Stage 1: good enough to ship fallow audit
- the chosen policy is encoded in config, not accumulated in scattered suppressions
- unresolved imports and unlisted dependencies are cleared
- blatant dead code (unused files, unused dependencies) is removed
fallow auditis wired into CI and passes for new changes against the default branch
Stage 2: ideal state
- no functions above your chosen health thresholds, either by refactoring or by consciously widening the threshold with written justification
- duplication at or below the chosen threshold
- stale suppressions gone or consciously accepted
7. Turn on PR enforcement
Once stage 1 is done, add the PR gate:fallow audit runs dead code, duplication, and complexity analysis scoped to changed files, then returns a pass, warn, or fail verdict. See the fallow audit reference for flags and CI recipes.
Pick one rollout strategy
- Option A: warn-everywhere
- Option B: error + baselines
- Option C: local agent gate
Best for smaller teams. CI never blocks; fixes land under social pressure.Risk: warn-only gates become warning-forever gates. Set a calendar reminder to promote rules to
error after the first clean month..fallowrc.json and run fallow audit with no flags:
8. Clean up with an agent
Fallow finds the problems. An AI agent (Claude Code, Cursor, Codex, Windsurf, any shell-capable coding assistant) is the right tool to fix them: edits are mechanical but decisions (“delete this export” vs. “mark it@public” vs. “add it to entry”) benefit from code-aware judgement.
Three levels of integration, pick whichever your agent supports:
Skills (best)
Install
fallow-skills for Claude Code, Cursor, Windsurf, or any Agent Skills compatible agent. Once installed, the skill works offline; the agent does not need to fetch docs URLs during use.MCP
Structured tool calling with JSON output and
_meta explanations. Works alongside skills.Plain shell
Any agent that can run a shell command can drive Fallow. Use the copy-paste prompt below.
Copy-paste adoption prompt (for agents without skills or MCP)
Copy-paste adoption prompt (for agents without skills or MCP)
Paste this prompt into your agent. It is self-contained: the agent does not need to fetch this page to follow it.
Next steps
fallow audit
Enforce the policy on changed files in CI.
Configuration overview
Every config key, with examples.
Suppression
Visibility tags, inline comments, and when to use each.
Agent Skills
Install
fallow-skills for agent-driven adoption.