From d1b2d46ddb56f89d0d996d6c4cab8fb22a3574db Mon Sep 17 00:00:00 2001 From: Bart Waardenburg Date: Wed, 7 Oct 2026 18:53:53 +0200 Subject: [PATCH 1/4] docs(cli): add fallow architecture command Add a page for fallow architecture and list it next to guard. Mark the five dead-code structure flags as deprecated aliases and describe the stderr hint. Point the boundaries, rule-pack, cycle, quickstart and CI pages to the new command, and document command: architecture, FALLOW_COMMAND: architecture and --only/--skip architecture. --- analysis/boundaries.mdx | 14 ++-- analysis/dead-code.mdx | 4 +- cli/architecture.mdx | 153 +++++++++++++++++++++++++++++++++++ cli/dead-code.mdx | 24 ++++-- cli/global-flags.mdx | 4 +- cli/guard.mdx | 13 ++- configuration/boundaries.mdx | 2 +- configuration/overview.mdx | 2 +- docs.json | 1 + explanations/dead-code.mdx | 8 +- integrations/ci.mdx | 20 +++-- public-content-manifest.json | 51 ++++++------ quickstart.mdx | 9 ++- 13 files changed, 251 insertions(+), 54 deletions(-) create mode 100644 cli/architecture.mdx diff --git a/analysis/boundaries.mdx b/analysis/boundaries.mdx index 03b4798..d115111 100644 --- a/analysis/boundaries.mdx +++ b/analysis/boundaries.mdx @@ -5,14 +5,14 @@ keywords: ["architecture boundaries", "import rules", "module boundaries", "laye icon: "layer-group" --- -Architecture boundaries catch a UI component that imports the database client, or one feature that imports another. You define zones and declare which zones may import from which. `fallow dead-code` then reports each import that breaks a rule. +Architecture boundaries catch a UI component that imports the database client, or one feature that imports another. You define zones and declare which zones may import from which. `fallow architecture` then reports each import that breaks a rule. ```bash -fallow dead-code --boundary-violations +fallow architecture --boundaries ``` - `fallow dead-code` includes boundary violations in its output by default. To show only boundary issues, pass `--boundary-violations`. + `fallow architecture` reports boundary violations together with import cycles and policy violations. To show only boundary issues, pass `--boundaries`. To see the rules for a file before you edit it, run [`fallow guard`](/cli/guard). `fallow dead-code` also reports boundary violations until the next major version. Its `--boundary-violations` flag is a deprecated alias for `fallow architecture --boundaries`. ## Quick start with presets @@ -330,8 +330,8 @@ All output formats include boundary violations: - ```bash title="$ fallow dead-code --boundary-violations" - ── Structure ───────────────────────────────────── + ```bash title="$ fallow architecture --boundaries" + ── Architecture ────────────────────────────────── ● Boundary violations (2) src/components/Button.tsx:1 → src/server/db/client.ts (shared → server) @@ -377,8 +377,8 @@ All output formats include boundary violations: ## See also - - CLI reference for the dead code command and all issue type filters. + + CLI reference for import cycles, boundaries, and policy rules. Set boundary violations to error, warn, or off. diff --git a/analysis/dead-code.mdx b/analysis/dead-code.mdx index eb679fb..b224832 100644 --- a/analysis/dead-code.mdx +++ b/analysis/dead-code.mdx @@ -37,7 +37,7 @@ Fallow reports these core issue types: | **Test-only dependencies** | Production dependencies that only test files import (move them to devDependencies) | | **Stale suppressions** | `fallow-ignore` comments or `@expected-unused` JSDoc tags that no longer match any issue | -Fallow also has framework-specific rules, such as unused component props and route collisions, and opt-in rules, such as private type leaks. To set the severity of a rule, see [Rules & severity](/configuration/rules). To see the filter flag of each issue type, run `fallow dead-code --help`. +Fallow also has framework-specific rules, such as unused component props and route collisions, and opt-in rules, such as private type leaks. To set the severity of a rule, see [Rules & severity](/configuration/rules). To see the filter flag of each issue type, run `fallow dead-code --help`. For circular dependencies, boundary violations, and the other architecture findings, use [`fallow architecture`](/cli/architecture). Typical output with more than one issue type: @@ -598,7 +598,7 @@ The comparison finds: ## Circular dependency performance -`fallow dead-code --circular-deps` runs the full analysis (dead code, dependencies, boundaries, and cycles). All runs are cold, with fallow 2.100.0 on an Apple M5. +`fallow dead-code --circular-deps` runs the full analysis (dead code, dependencies, boundaries, and cycles). All runs are cold, with fallow 2.100.0 on an Apple M5. The flag is now a deprecated alias for `fallow architecture --cycles`, which runs the same analysis. | Project | Files | Time | Cycles | |:--------|------:|-----:|-------:| diff --git a/cli/architecture.mdx b/cli/architecture.mdx new file mode 100644 index 0000000..b0d91f3 --- /dev/null +++ b/cli/architecture.mdx @@ -0,0 +1,153 @@ +--- +title: "fallow architecture" +description: "Check the structure of your code after an edit. Fallow architecture reports circular dependencies, re-export cycles, package cycles, boundary violations, and rule-pack policy violations." +keywords: ["fallow architecture", "architecture", "circular dependencies", "import cycles", "boundaries", "boundary violations", "rule packs", "policy", "CLI"] +icon: "terminal" +--- + +`fallow architecture` reports the findings that break the structure of your code: + +- circular dependencies +- re-export cycles +- package cycles (workspace packages that import each other in a loop) +- boundary violations, which include boundary coverage and forbidden calls +- rule-pack policy violations + +```bash +fallow architecture +fallow architecture --cycles +fallow architecture --boundaries --changed-since main +``` + +The command runs the same analysis as [`fallow dead-code`](/cli/dead-code) with only these issue types selected. The JSON output is the `dead-code` envelope (`kind: "dead-code"`). The arrays, the finding ids, the exit codes, and the baselines are the same as on `dead-code`. + + + Run [`fallow guard`](/cli/guard) before an edit to see the rules that apply to a file. Run `fallow architecture` after the edit to find the violations in the code. + + +## Options + +### Selection + +| Flag | Selects | +|:-----|:--------| +| `--cycles` | Circular dependencies, re-export cycles, and package cycles | +| `--boundaries` | Boundary violations, boundary coverage, and forbidden calls | +| `--policy` | Rule-pack policy violations | + +Without a selection flag, the command reports all architecture issue types. You can combine the flags, for example `--cycles --policy`. + +### Scoping + +| Flag | Description | +|:-----|:------------| +| `[PATH]` | Report only the findings in this file or directory. The default is the whole project. Fallow still builds the full project graph. | +| `--file ` | Report only the findings in these files. Repeat the flag for more files. Fallow still builds the full project graph. | +| `--finding-id ` | Report only the findings with this `finding_id`. Repeat the flag or pass a comma-separated list. See [`finding_id_query`](/cli/dead-code#finding-id-query). | + +The [global flags](/cli/global-flags) work as on `dead-code`. These include `--format`, `--quiet`, `--changed-since`, `--workspace`, `--baseline`, and `--save-baseline`. + +## Relation to `fallow dead-code` + +`fallow architecture` and `dead-code` with the matching filter flags give the same report: + +| Command | Same report as | +|:--------|:---------------| +| `fallow architecture --cycles` | `fallow dead-code --circular-deps --re-export-cycles --package-cycles` | +| `fallow architecture --boundaries` | `fallow dead-code --boundary-violations` | +| `fallow architecture --policy` | `fallow dead-code --policy-violations` | + +These five `dead-code` flags are deprecated aliases. They continue to work in version 3. `fallow dead-code` also continues to report the architecture findings by default until the next major version. In human output, `dead-code` prints a hint on stderr that points to `fallow architecture` when it reports such a finding. + +## Example output + +```bash title="$ fallow architecture (excerpt)" +── Architecture ────────────────────────────────── + +● Circular dependencies (1) + src/ui/App.ts + → state.ts → App.ts + +● Boundary violations (1) + src/ui/App.ts:3 → src/db/client.ts (ui → db) +``` + +The output has one "Architecture" category. The sections in it are the same as in `dead-code` output. With `--group-by`, each group uses the `dead-code` category headings ("Structure" and "Policy"), and not one "Architecture" heading. + +In `--format json`, the findings are in the same arrays as in `dead-code` output, for example `circular_dependencies`, `re_export_cycles`, `boundary_violations`, and `policy_violations`: + +```json title="$ fallow architecture --boundaries --format json (excerpt)" +{ + "kind": "dead-code", + "boundary_violations": [ + { + "from_path": "src/ui/App.ts", + "to_path": "src/db/client.ts", + "from_zone": "ui", + "to_zone": "db", + "import_specifier": "../db/client", + "line": 3, + "col": 9 + } + ] +} +``` + +## Exit codes + +| Code | Meaning | +|:-----|:--------| +| `0` | No finding with error severity. | +| `1` | At least one finding has error severity. | +| `2` | Invalid input or configuration. | + +The exit codes are the same as on `dead-code`. A circular dependency and a boundary violation have `error` severity by default. A policy violation has `warn` severity by default. Change the severity in [`rules`](/configuration/rules). + +## Baselines + +`fallow architecture` reads and writes the same baseline format as `dead-code`. You can use a baseline from `fallow dead-code --save-baseline` with `fallow architecture --baseline`. + +A baseline that `fallow architecture --save-baseline` writes records a scope that the issue types filter. For this reason, `--fail-on-stale-baseline` does not gate on such a baseline. + +## Examples + +```bash +# Before an edit: the rules that apply to the file +fallow guard src/ui/App.ts --format json --quiet + +# After an edit: cycles, boundaries, and policy rules +fallow architecture --format json --quiet + +# Only import cycles in the files that changed since main +fallow architecture --cycles --changed-since main --format json --quiet + +# Only boundary findings in one workspace +fallow architecture --boundaries --workspace web + +# Adopt the check on an existing codebase +fallow architecture --save-baseline fallow-architecture-baseline.json +fallow architecture --baseline fallow-architecture-baseline.json +``` + +## Bare `fallow` + +Bare `fallow` also reports these findings. In human output, they show in an "Architecture" section after the dead code findings. The JSON and the other machine formats do not change: the findings stay in the dead code part of the output. + +To run only this section, pass `--only architecture`. To leave it out, pass `--skip architecture`. See [global flags](/cli/global-flags). + +## See also + + + + See the architecture rules for a file before you edit it. + + + Define zones and the imports that each zone allows. + + + What cycles, boundary violations, and policy violations mean, and when to act. + + + The dead code command and its issue type filters. + + diff --git a/cli/dead-code.mdx b/cli/dead-code.mdx index 5045045..92df1d0 100644 --- a/cli/dead-code.mdx +++ b/cli/dead-code.mdx @@ -8,7 +8,7 @@ icon: "terminal" `fallow dead-code` finds the code that nothing uses, so you can delete it and keep the codebase smaller. Fallow starts at your entry points, traces all reachable exports, and reports each file, export, dependency, and type that is not used. - Bare `fallow` runs **all analyses** (dead code, duplication, and health). To run only the dead code analysis, use `fallow dead-code`. `fallow check` is still a hidden alias for `fallow dead-code`. + Bare `fallow` runs **all analyses** (dead code, architecture, duplication, and health). To run only the dead code analysis, use `fallow dead-code`. For import cycles, boundaries, and policy rules, use [`fallow architecture`](/cli/architecture). `fallow check` is still a hidden alias for `fallow dead-code`. ```bash @@ -57,11 +57,11 @@ fallow check # Hidden alias for fallow dead-code | `--unresolved-imports` | Report only unresolved imports | | `--unlisted-deps` | Report only unlisted dependencies | | `--duplicate-exports` | Report only duplicate exports | -| `--circular-deps` | Report only circular dependencies | -| `--re-export-cycles` | Report only re-export cycles (barrel files that re-export from each other in a loop, or self-loops). See [explanations/dead-code#re-export-cycles](/explanations/dead-code#re-export-cycles) | -| `--package-cycles` | Report only package cycles (workspace packages that import each other in a loop). See [explanations/dead-code#package-cycles](/explanations/dead-code#package-cycles) | -| `--boundary-violations` | Report only boundary violations | -| `--policy-violations` | Report only configured rule-pack violations, including banned usages and gdp-ts proof producers outside allowed files. See [Policy violations](/explanations/dead-code#policy-violations). | +| `--circular-deps` | Deprecated alias for [`fallow architecture --cycles`](/cli/architecture). Report only circular dependencies. | +| `--re-export-cycles` | Deprecated alias for [`fallow architecture --cycles`](/cli/architecture). Report only re-export cycles (barrel files that re-export from each other in a loop, or self-loops). See [explanations/dead-code#re-export-cycles](/explanations/dead-code#re-export-cycles) | +| `--package-cycles` | Deprecated alias for [`fallow architecture --cycles`](/cli/architecture). Report only package cycles (workspace packages that import each other in a loop). See [explanations/dead-code#package-cycles](/explanations/dead-code#package-cycles) | +| `--boundary-violations` | Deprecated alias for [`fallow architecture --boundaries`](/cli/architecture). Report only boundary violations. | +| `--policy-violations` | Deprecated alias for [`fallow architecture --policy`](/cli/architecture). Report only configured rule-pack violations, including banned usages and gdp-ts proof producers outside allowed files. See [Policy violations](/explanations/dead-code#policy-violations). | | `--stale-suppressions` | Report only stale suppression comments and `@expected-unused` JSDoc tags | | `--unused-catalog-entries` | Report only unused pnpm catalog entries | | `--empty-catalog-groups` | Report only empty named pnpm catalog groups | @@ -71,6 +71,18 @@ fallow check # Hidden alias for fallow dead-code | `--include-dupes` | Also run duplication analysis and link its results to dead code findings | | `--finding-id ` | Report only the findings with this `finding_id`. Repeat the flag or pass a comma-separated list. The JSON output adds a `finding_id_query` answer. A malformed id exits 2. See [`finding_id_query`](#finding-id-query). | +The five deprecated aliases continue to work in version 3. + + + `fallow dead-code` continues to report circular dependencies, re-export cycles, package cycles, boundary violations, and policy violations by default until the next major version. When the human output reports such a finding, fallow prints one hint on stderr: + + ```text + Tip: run `fallow architecture` for import cycles, boundaries and policy rules. A future major version removes them from `fallow dead-code`. + ``` + + `--quiet` and the machine formats do not print the hint. The JSON, SARIF, CodeClimate, compact, and markdown output do not change. Use [`fallow architecture`](/cli/architecture) for these findings. + + ### Scoping | Flag | Description | diff --git a/cli/global-flags.mdx b/cli/global-flags.mdx index aa4419e..a8b4c69 100644 --- a/cli/global-flags.mdx +++ b/cli/global-flags.mdx @@ -55,8 +55,8 @@ The `--dupes-*` flags apply to combined mode. When you do not set one, fallow us | `--report-path-prefix ` (alias: `--annotations-path-prefix`) | Override the repository-root offset that fallow adds in front of each path in the CI formats. An empty string disables the offset. See [Repository-root paths in CI formats](#repository-root-paths-in-ci-formats). | | `--group-by ` | Group output by CODEOWNERS ownership (`owner`), first directory component (`directory`), workspace package (`package`), or GitLab CODEOWNERS section (`section`). `json`, `human`, `sarif` and `codeclimate` show the groups. For `dead-code`, `compact` and `markdown` also show the groups. For `health`, `markdown` and `github-summary` also show the groups. All other formats render one flat document and print a warning on stderr. See [Grouped output](#grouped-output). | | `--summary` | In human output, show only the issue counts per category, without the individual items. JSON output does not change. | -| `--only ` | Run only specific analyses when no subcommand is given. `check` is an alias for `dead-code`. | -| `--skip ` | Skip specific analyses when no subcommand is given | +| `--only ` | Run only specific analyses when no subcommand is given. `check` is an alias for `dead-code`. `architecture` selects the import cycles, boundary violations, and policy violations. See [`fallow architecture`](/cli/architecture). | +| `--skip ` | Skip specific analyses when no subcommand is given | | `--coverage ` | In combined mode, give Istanbul coverage data to the health analysis. Same fallback chain as [`fallow health --coverage`](/cli/health#options). | | `--coverage-root ` | Absolute prefix to strip from Istanbul coverage paths in combined mode. See [`fallow health --coverage-root`](/cli/health#options). | | `--dupes-baseline ` | In combined mode, hide the clone groups in a baseline that `fallow dupes --save-baseline` wrote. With a subcommand, use `fallow dupes --baseline`. | diff --git a/cli/guard.mdx b/cli/guard.mdx index 2fe49af..bb943b0 100644 --- a/cli/guard.mdx +++ b/cli/guard.mdx @@ -20,7 +20,7 @@ fallow guard src/ui/App.ts src/db/query.ts --format json ``` - `guard` shows the rules before an edit. For violations that already exist in the code, run [`fallow dead-code`](/cli/dead-code) or [`fallow audit`](/cli/audit), which report `boundary-violation` and `policy-violation` findings. + `guard` shows the rules before an edit. For violations that already exist in the code, run [`fallow architecture`](/cli/architecture) after the edit. [`fallow audit`](/cli/audit) also reports `boundary-violation` and `policy-violation` findings in the changed files. ## Output @@ -154,11 +154,20 @@ Call `guard` on the files you are about to change, while you can still choose wh fallow guard --format json --quiet ``` -The `guard` MCP tool gives the same output. The [MCP integration guide](/integrations/mcp) describes it. +After the edit, run `fallow architecture` to find the violations in the code: + +```bash +fallow architecture --format json --quiet +``` + +The `guard` MCP tool gives the same output as `fallow guard`. The [MCP integration guide](/integrations/mcp) describes it. ## See also + + Find import cycles, boundary violations, and policy violations after an edit. + How fallow detects imports that cross zone boundaries. diff --git a/configuration/boundaries.mdx b/configuration/boundaries.mdx index f2299f4..da7fd0f 100644 --- a/configuration/boundaries.mdx +++ b/configuration/boundaries.mdx @@ -5,7 +5,7 @@ keywords: ["boundaries", "zones", "rules", "presets", "architecture", "import ru icon: "layer-group" --- -Boundaries stop imports that break your architecture, for example UI code that imports the database layer. You group files into zones with glob patterns. A rule says which zones a zone may import from. Fallow reports each forbidden import as a `boundary-violation` issue in `fallow dead-code` output. +Boundaries stop imports that break your architecture, for example UI code that imports the database layer. You group files into zones with glob patterns. A rule says which zones a zone may import from. Fallow reports each forbidden import as a `boundary-violation` issue in [`fallow architecture`](/cli/architecture) output. Two optional sections add checks beyond import direction: diff --git a/configuration/overview.mdx b/configuration/overview.mdx index af07219..e7ba922 100644 --- a/configuration/overview.mdx +++ b/configuration/overview.mdx @@ -1175,7 +1175,7 @@ An absent or empty `proofKinds` checks every recognized factory call, including The rule checks every analyzed file, including files unreachable from entry points. Files excluded from discovery are outside its scope. It follows named and namespace imports, import aliases, and unambiguous project re-export chains to the gdp-ts factory. See [Policy violations](/explanations/dead-code#policy-violations) for supported forms and limits. -Inspect the configured permissions with `fallow rule-pack list --format json` or `fallow guard src/routes/project.ts --format json`. Use `fallow rule-pack test rule-packs/gdp.json --format json` to inspect matches while authoring the pack. This command exits successfully when it reports findings. For CI enforcement, run `fallow dead-code --policy-violations`; an error-severity finding exits with code 1. +Inspect the configured permissions with `fallow rule-pack list --format json` or `fallow guard src/routes/project.ts --format json`. Use `fallow rule-pack test rule-packs/gdp.json --format json` to inspect matches while authoring the pack. This command exits successfully when it reports findings. For CI enforcement, run [`fallow architecture --policy`](/cli/architecture). An error-severity finding exits with code 1. For details on the issue type, see [Policy violations](/explanations/dead-code#policy-violations). diff --git a/docs.json b/docs.json index 9348c6a..32c5a11 100644 --- a/docs.json +++ b/docs.json @@ -151,6 +151,7 @@ "cli/recommend", "cli/doctor", "cli/guard", + "cli/architecture", "cli/plugin-check", "cli/migrate", "cli/list", diff --git a/explanations/dead-code.mdx b/explanations/dead-code.mdx index 1475f91..7a57e47 100644 --- a/explanations/dead-code.mdx +++ b/explanations/dead-code.mdx @@ -304,6 +304,10 @@ The same symbol name exported from more than one module. Auto-imports become amb Modules that import each other, directly or transitively, and so form a cycle. + + Circular dependencies, re-export cycles, package cycles, boundary violations, and policy violations are architecture findings. [`fallow architecture`](/cli/architecture) reports them. `fallow dead-code` also reports them until the next major version. To report only the cycles, run `fallow architecture --cycles`. + + | Severity | Default | |:---------|:--------| | Error | Yes | @@ -450,7 +454,7 @@ The cycle goes away when every import on one hop is removed. If a hop has more t ### Boundary violations -Imports that cross the architecture zone boundaries that you define. You define zones in the `boundaries` config section. Each zone maps file path patterns to a name. A boundary violation is an import from a file in one zone to a file in another zone that the boundary rules do not allow. Fallow checks every analyzed file, also a file that no entry point reaches. For a named or default import through a barrel file, fallow judges the zone of the module that declares the symbol. The finding then names the barrel in `via_path`. +Imports that cross the architecture zone boundaries that you define. You define zones in the `boundaries` config section. Each zone maps file path patterns to a name. A boundary violation is an import from a file in one zone to a file in another zone that the boundary rules do not allow. Fallow checks every analyzed file, also a file that no entry point reaches. For a named or default import through a barrel file, fallow judges the zone of the module that declares the symbol. The finding then names the barrel in `via_path`. To report only this issue type, run `fallow architecture --boundaries`. | Severity | Default | |:---------|:--------| @@ -469,7 +473,7 @@ Imports that cross the architecture zone boundaries that you define. You define ### Policy violations {#policy-violations} -Calls, imports, exports, effects, or gdp-ts proof producers that violate a configured rule pack (the `rulePacks` config key). A rule pack is a standalone JSON or JSONC file with declarative policy data only. Loading a pack never executes project code. Every output format identifies a finding as `/`. +Calls, imports, exports, effects, or gdp-ts proof producers that violate a configured rule pack (the `rulePacks` config key). A rule pack is a standalone JSON or JSONC file with declarative policy data only. Loading a pack never executes project code. Every output format identifies a finding as `/`. To report only this issue type, run `fallow architecture --policy`. | Severity | Default | |:---------|:--------| diff --git a/integrations/ci.mdx b/integrations/ci.mdx index 5a092c7..4ddd36f 100644 --- a/integrations/ci.mdx +++ b/integrations/ci.mdx @@ -59,7 +59,7 @@ Run fallow in CI to catch changed-code risk, cleanup opportunities, duplication, | Input | Default | Description | |:------|:--------|:------------| - | `command` | -- (all) | Command to run (`dead-code`, `dupes`, `health`, `audit`, `security`, `fix`, or empty for all). Legacy alias: `check` = `dead-code`. | + | `command` | -- (all) | Command to run (`dead-code`, `architecture`, `dupes`, `health`, `audit`, `security`, `fix`, or empty for all). Legacy alias: `check` = `dead-code`. `architecture` reports import cycles, boundary violations, and policy violations. See [`fallow architecture`](/cli/architecture). | | `root` | `.` | Project root directory | | `config` | -- | Path to config file (`.fallowrc.json`, `.fallowrc.jsonc`, `fallow.toml`, or `.fallow.toml`) | | `format` | `sarif` | Output format (`human`, `json`, `sarif`, `compact`, `markdown`, `codeclimate`, `pr-comment-github`, `pr-comment-gitlab`, `review-github`, `review-gitlab`, or `badge`) | @@ -140,8 +140,8 @@ Run fallow in CI to catch changed-code risk, cleanup opportunities, duplication, | `dead-code-baseline` / `health-baseline` / `dupes-baseline` | -- | Baseline file paths for each analysis in the audit command (saved by `fallow dead-code|health|dupes --save-baseline`). With these, old issues in touched files do not decide the verdict. | | `no-cache` | `false` | Turn off the incremental parse cache and parse all files again | | `threads` | -- | Number of parser threads (default: the number of CPU cores) | - | `only` | -- | Without `command`: run only these analyses (comma-separated: `dead-code`, `dupes`, `health`) | - | `skip` | -- | Without `command`: skip these analyses (comma-separated: `dead-code`, `dupes`, `health`) | + | `only` | -- | Without `command`: run only these analyses (comma-separated: `dead-code`, `architecture`, `dupes`, `health`) | + | `skip` | -- | Without `command`: skip these analyses (comma-separated: `dead-code`, `architecture`, `dupes`, `health`) | | `args` | -- | More arguments to pass to fallow. With `command: audit`, the action rejects `--fail-on-stale-baseline` with exit 2. An audit analyzes only the files that changed against its base, so it cannot judge a whole-project baseline. | @@ -222,7 +222,7 @@ Run fallow in CI to catch changed-code risk, cleanup opportunities, duplication, | Variable | Default | Description | |:---------|:--------|:------------| - | `FALLOW_COMMAND` | `""` | Command to run (`dead-code`, `dupes`, `health`, `audit`, `security`, `fix`, or empty for all). Legacy alias: `check` = `dead-code`. | + | `FALLOW_COMMAND` | `""` | Command to run (`dead-code`, `architecture`, `dupes`, `health`, `audit`, `security`, `fix`, or empty for all). Legacy alias: `check` = `dead-code`. `architecture` reports import cycles, boundary violations, and policy violations. See [`fallow architecture`](/cli/architecture). | | `FALLOW_ROOT` | `.` | Project root directory | | `FALLOW_CONFIG` | -- | Path to config file | | `FALLOW_PRODUCTION` | `""` | Set to `"true"` to turn on production mode for every analysis. When empty, the per-analysis env and config decide. | @@ -316,6 +316,15 @@ Run fallow in CI to catch changed-code risk, cleanup opportunities, duplication, FALLOW_COMMAND: "dead-code" FALLOW_COMMENT: "true" ``` + + Example: import cycles, boundaries, and policy rules only: + + ```yaml + fallow: + extends: .fallow + variables: + FALLOW_COMMAND: "architecture" + ``` The template generates a GitLab Code Quality report (CodeClimate format). GitLab shows the fallow findings as **inline annotations** on the MR diff. This is the GitLab equivalent of GitHub Code Scanning. @@ -657,7 +666,7 @@ Run fallow in CI to catch changed-code risk, cleanup opportunities, duplication, - run: npx fallow health --format compact ``` - Reports complexity findings, the health score, file scores, hotspots, and refactoring targets. Circular dependencies lower the health score and can show as refactoring targets. To list each cycle, run `fallow dead-code --circular-deps`. To change the threshold, use `--max-cyclomatic 15`. + Reports complexity findings, the health score, file scores, hotspots, and refactoring targets. Circular dependencies lower the health score and can show as refactoring targets. To list each cycle, run `fallow architecture --cycles`. To change the threshold, use `--max-cyclomatic 15`. Fallow works in any CI environment that can run Node.js or [install fallow](/installation). The commands are the same everywhere: @@ -668,6 +677,7 @@ Run fallow in CI to catch changed-code risk, cleanup opportunities, duplication, # Or individual commands npx fallow dead-code --format compact + npx fallow architecture --format compact npx fallow dupes --format compact npx fallow health --format compact diff --git a/public-content-manifest.json b/public-content-manifest.json index 8b0c88d..881a013 100644 --- a/public-content-manifest.json +++ b/public-content-manifest.json @@ -7,7 +7,7 @@ "visibility": "public-only" }, "content": { - "sha256": "5030fd016f467e7fa3da50fe5820e5b64b09fa325bb9c123a1fd99f5b4c15112", + "sha256": "b6163b899fe407662c262278ff5bd331aae16757bfb346098c30b24df884b077", "files": [ { "path": "adoption.mdx", @@ -21,8 +21,8 @@ }, { "path": "analysis/boundaries.mdx", - "bytes": 14914, - "sha256": "bd2281137a64afc2d5b4236ca74742ab00346826e136ce4fbdd7a40a8b70e0b7" + "bytes": 15177, + "sha256": "7106f782809b2d63e9691cf164e9e2bbd4c8f2e7541bf63476eebd89c2203a9c" }, { "path": "analysis/css-analysis.mdx", @@ -31,8 +31,8 @@ }, { "path": "analysis/dead-code.mdx", - "bytes": 33142, - "sha256": "138b544d67ca6f746d3bd4265fffd4c6fbc0d5b003a62b28f075e8b79a712d1c" + "bytes": 33376, + "sha256": "4e733d4e6fc2b7abc20921982ea15a72688d8a741d7aadd110fed182c4e095db" }, { "path": "analysis/debugging.mdx", @@ -84,6 +84,11 @@ "bytes": 9463, "sha256": "df3ddc4be2b57674e10bab2b1664ab00a9c527962e37e019506414221aae09bc" }, + { + "path": "cli/architecture.mdx", + "bytes": 6778, + "sha256": "06171c74968eaf6dd1d26593f32e08299b3be3fb025c3533b79d70362c722b57" + }, { "path": "cli/audit.mdx", "bytes": 46775, @@ -101,8 +106,8 @@ }, { "path": "cli/dead-code.mdx", - "bytes": 33395, - "sha256": "f90b43b9c506d9911dd05fe6a3bf9fb24451f1eaa505e117389a491cf1ce4e21" + "bytes": 34580, + "sha256": "3766396df288894057b8f75293026bdac3805d4a36772e47470369021720da54" }, { "path": "cli/decision-surface.mdx", @@ -136,13 +141,13 @@ }, { "path": "cli/global-flags.mdx", - "bytes": 40937, - "sha256": "fa37a43439fe6b83918481adab988ee439d3ae42d4d4726c91c95ba886f0a988" + "bytes": 41097, + "sha256": "0bb894ad03dfe2bf08fdbc2578bb84d69a8c8ef8652a42dacdebd1539853dfac" }, { "path": "cli/guard.mdx", - "bytes": 7847, - "sha256": "d03527c0cc00e11786fee7797b9eb6b5559f81ae5d9d0dbbfcbb2e6cd7745f58" + "bytes": 8208, + "sha256": "367a5ab4e92c92736491cce0d000a3b1202a5162d7877a84f7d4e2014bd11ebe" }, { "path": "cli/health.mdx", @@ -246,8 +251,8 @@ }, { "path": "configuration/boundaries.mdx", - "bytes": 22577, - "sha256": "9eafba3f249c9a68b5c0699883ebeb81061e3a640acbaf9535943add41e632a8" + "bytes": 22601, + "sha256": "1cffabca639739bbb7b801bffa2b58d6ae0506f9224df9df69a85077bf45ff0c" }, { "path": "configuration/environment.mdx", @@ -256,8 +261,8 @@ }, { "path": "configuration/overview.mdx", - "bytes": 76639, - "sha256": "d5f6c9c9506a1ba2d451bef153c9c134c7986cac833ead3cee0834c04a094ac8" + "bytes": 76652, + "sha256": "63e50b6cb5309402e4e45e2e3c6f5d73b36fe79e05621b03d463ba5a2c334e35" }, { "path": "configuration/rules.mdx", @@ -286,13 +291,13 @@ }, { "path": "docs.json", - "bytes": 8425, - "sha256": "450abe04af474559a8ec9b4a7ebcb3b5077856d7dd87672f8487228bbc118c32" + "bytes": 8459, + "sha256": "20e381fcfb5b487feb7061b587ce536fe44c0949a4d0f74d89734d453ad6533c" }, { "path": "explanations/dead-code.mdx", - "bytes": 93215, - "sha256": "8e557f7ac7f2bdcf232a59821c19e991b80f15dfa739a28804b5297a2f54534f" + "bytes": 93687, + "sha256": "556990c27ee1b7fc8b8cf247c03e35f83e9a5bcb1360f7af735af7f44b856367" }, { "path": "explanations/duplication.mdx", @@ -391,8 +396,8 @@ }, { "path": "integrations/ci.mdx", - "bytes": 84297, - "sha256": "8446f31925d015bdcee7e0092412bfd15b8c0c4a2174507a5e56738becd76170" + "bytes": 84866, + "sha256": "f62f8084977327ac25b6f91f5d02eae0873bb16b35f6a42dafade5f4f887a5dd" }, { "path": "integrations/claude-hooks.mdx", @@ -446,8 +451,8 @@ }, { "path": "quickstart.mdx", - "bytes": 5290, - "sha256": "49869a0d365caab006ec449c141615c5ada47d2cb0e2f5bcc2b299b103e44fed" + "bytes": 5574, + "sha256": "9f3d13505b7900a7e4b8a32f583fa7d2798ef4c5987f4d627d6f1241619653fc" } ] } diff --git a/quickstart.mdx b/quickstart.mdx index e975d7b..eee58ff 100644 --- a/quickstart.mdx +++ b/quickstart.mdx @@ -15,9 +15,10 @@ From your project root, run: npx fallow ``` -This command runs three analyses in one pass: +This command runs these analyses in one pass: -- **Dead code**: unused files, exports, dependencies, cycles, boundaries, and more +- **Dead code**: unused files, exports, dependencies, and more +- **Architecture**: import cycles, boundary violations, and rule-pack policy violations - **Duplication**: repeated logic across files - **Health**: complexity hotspots and refactor targets @@ -29,13 +30,15 @@ This command runs three analyses in one pass: ```bash npx fallow dead-code # Cleanup candidates +npx fallow architecture # Import cycles, boundaries, and policy rules npx fallow dupes # Repeated logic npx fallow health # Complexity and refactor targets npx fallow review # Advisory review brief over changed files (always exits 0) npx fallow fix --dry-run # Preview automatic cleanup ``` -- `dead-code` reports unused files, exports, types, dependencies, circular dependencies, and boundary violations. See the [dead code guide](/analysis/dead-code). +- `dead-code` reports unused files, exports, types, and dependencies. See the [dead code guide](/analysis/dead-code). +- `architecture` reports circular dependencies, re-export cycles, package cycles, boundary violations, and rule-pack policy violations. See [`fallow architecture`](/cli/architecture). - `dupes` finds AST-based duplicates in the default `mild` mode. To also find clones with renamed variables, add `--mode semantic`. See the [duplication guide](/analysis/duplication). - `health` reports complexity findings, maintainability per file, hotspots, and ranked refactor targets. See the [health explanation](/explanations/health). - `fix --dry-run` shows the automatic cleanup without changing files. To apply it, remove `--dry-run`. See the [auto-fix guide](/analysis/auto-fix). From c86aa3638bf464da66548bffd54a558559569989 Mon Sep 17 00:00:00 2001 From: Bart Waardenburg Date: Wed, 7 Oct 2026 20:05:12 +0200 Subject: [PATCH 2/4] docs(cli): match architecture docs to the command output Use the real Architecture header, the human and JSON examples, the default severities, the baseline rules, the --quiet layout of bare fallow and the architecture values of the issue-types CI inputs. --- analysis/boundaries.mdx | 2 +- cli/architecture.mdx | 26 +++++++++++++------------- integrations/ci.mdx | 4 ++-- public-content-manifest.json | 14 +++++++------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/analysis/boundaries.mdx b/analysis/boundaries.mdx index d115111..24c4a86 100644 --- a/analysis/boundaries.mdx +++ b/analysis/boundaries.mdx @@ -331,7 +331,7 @@ All output formats include boundary violations: ```bash title="$ fallow architecture --boundaries" - ── Architecture ────────────────────────────────── + ── Architecture ───────────────────────────────────── ● Boundary violations (2) src/components/Button.tsx:1 → src/server/db/client.ts (shared → server) diff --git a/cli/architecture.mdx b/cli/architecture.mdx index b0d91f3..b2b6358 100644 --- a/cli/architecture.mdx +++ b/cli/architecture.mdx @@ -49,9 +49,9 @@ The [global flags](/cli/global-flags) work as on `dead-code`. These include `--f ## Relation to `fallow dead-code` -`fallow architecture` and `dead-code` with the matching filter flags give the same report: +`fallow architecture` and `dead-code` with the matching filter flags find the same issues and give the same machine output. Only the human headings are different: -| Command | Same report as | +| Command | Same issues as | |:--------|:---------------| | `fallow architecture --cycles` | `fallow dead-code --circular-deps --re-export-cycles --package-cycles` | | `fallow architecture --boundaries` | `fallow dead-code --boundary-violations` | @@ -62,17 +62,17 @@ These five `dead-code` flags are deprecated aliases. They continue to work in ve ## Example output ```bash title="$ fallow architecture (excerpt)" -── Architecture ────────────────────────────────── +── Architecture ───────────────────────────────────── ● Circular dependencies (1) - src/ui/App.ts - → state.ts → App.ts + src/static/a.ts + → b.ts → a.ts ● Boundary violations (1) - src/ui/App.ts:3 → src/db/client.ts (ui → db) + src/ui/App.ts:5 → src/db/query.ts (ui → db) ``` -The output has one "Architecture" category. The sections in it are the same as in `dead-code` output. With `--group-by`, each group uses the `dead-code` category headings ("Structure" and "Policy"), and not one "Architecture" heading. +The output has one "Architecture" category. The sections in it are the same as in `dead-code` output. With `--group-by`, each group has its own "Architecture" heading. In `--format json`, the findings are in the same arrays as in `dead-code` output, for example `circular_dependencies`, `re_export_cycles`, `boundary_violations`, and `policy_violations`: @@ -82,11 +82,11 @@ In `--format json`, the findings are in the same arrays as in `dead-code` output "boundary_violations": [ { "from_path": "src/ui/App.ts", - "to_path": "src/db/client.ts", + "to_path": "src/db/query.ts", "from_zone": "ui", "to_zone": "db", - "import_specifier": "../db/client", - "line": 3, + "import_specifier": "src/db/query.ts", + "line": 5, "col": 9 } ] @@ -101,13 +101,13 @@ In `--format json`, the findings are in the same arrays as in `dead-code` output | `1` | At least one finding has error severity. | | `2` | Invalid input or configuration. | -The exit codes are the same as on `dead-code`. A circular dependency and a boundary violation have `error` severity by default. A policy violation has `warn` severity by default. Change the severity in [`rules`](/configuration/rules). +The exit codes are the same as on `dead-code`. A circular dependency and a boundary violation have `error` severity by default. A re-export cycle, a package cycle and a policy violation have `warn` severity by default. A rule in a rule pack can set its own `severity`. Change the severity in [`rules`](/configuration/rules). ## Baselines `fallow architecture` reads and writes the same baseline format as `dead-code`. You can use a baseline from `fallow dead-code --save-baseline` with `fallow architecture --baseline`. -A baseline that `fallow architecture --save-baseline` writes records a scope that the issue types filter. For this reason, `--fail-on-stale-baseline` does not gate on such a baseline. +A `fallow architecture` run reports only part of the issue types. For this reason, `--fail-on-stale-baseline` does not gate on `fallow architecture`, with any baseline. A baseline that `fallow architecture --save-baseline` writes lists only the architecture findings. When `fallow dead-code` reads such a baseline, fallow shows a warning. ## Examples @@ -131,7 +131,7 @@ fallow architecture --baseline fallow-architecture-baseline.json ## Bare `fallow` -Bare `fallow` also reports these findings. In human output, they show in an "Architecture" section after the dead code findings. The JSON and the other machine formats do not change: the findings stay in the dead code part of the output. +Bare `fallow` also reports these findings. In human output without `--quiet`, they show in an "Architecture" section after the dead code findings. With `--quiet`, they stay in the "Structure" and "Policy" categories. The JSON and the other machine formats do not change: the findings stay in the dead code part of the output. To run only this section, pass `--only architecture`. To leave it out, pass `--skip architecture`. See [global flags](/cli/global-flags). diff --git a/integrations/ci.mdx b/integrations/ci.mdx index 4ddd36f..101f5ad 100644 --- a/integrations/ci.mdx +++ b/integrations/ci.mdx @@ -70,7 +70,7 @@ Run fallow in CI to catch changed-code risk, cleanup opportunities, duplication, | `production-health` | `false` | Combined mode only: per-analysis production mode for health | | `production-dupes` | `false` | Combined mode only: per-analysis production mode for duplication | | `fail-on-issues` | `true` | Exit with code 1 when there are issues | - | `issue-types` | -- | Comma-separated issue types to report (dead-code command) | + | `issue-types` | -- | Comma-separated issue types to report (`dead-code` and `architecture` commands). For `architecture`, the values are `cycles`, `boundaries` and `policy`. | | `include-entry-exports` | `false` | Report unused exports in entry files and do not mark them as used. This catches typos in framework exports (dead-code analysis). | | `fail-on-regression` | `false` | Exit with code 1 when the issue counts increase compared to the regression baseline (dead-code command) | | `tolerance` | `0` | Allowed increase before a regression fails, for example `2%` or `5` (dead-code command) | @@ -230,7 +230,7 @@ Run fallow in CI to catch changed-code risk, cleanup opportunities, duplication, | `FALLOW_PRODUCTION_HEALTH` | `""` | Combined mode only: set to `"true"` or `"false"` to override `FALLOW_PRODUCTION` for health. When empty, `FALLOW_PRODUCTION` decides. | | `FALLOW_PRODUCTION_DUPES` | `""` | Combined mode only: set to `"true"` or `"false"` to override `FALLOW_PRODUCTION` for duplication. When empty, `FALLOW_PRODUCTION` decides. | | `FALLOW_FAIL_ON_ISSUES` | `true` | Fail the pipeline when there are issues | - | `FALLOW_ISSUE_TYPES` | `""` | Comma-separated issue types to report (dead-code command) | + | `FALLOW_ISSUE_TYPES` | `""` | Comma-separated issue types to report (`dead-code` and `architecture` commands). For `architecture`, the values are `cycles`, `boundaries` and `policy`. | | `FALLOW_INCLUDE_ENTRY_EXPORTS` | `"false"` | Report unused exports in entry files and do not mark them as used (same as `--include-entry-exports`) | | `FALLOW_FAIL_ON_REGRESSION` | `"false"` | Fail when the issue counts increase compared to the regression baseline (dead-code command) | | `FALLOW_TOLERANCE` | `"0"` | Allowed increase before a regression fails (dead-code command) | diff --git a/public-content-manifest.json b/public-content-manifest.json index 881a013..735a08d 100644 --- a/public-content-manifest.json +++ b/public-content-manifest.json @@ -7,7 +7,7 @@ "visibility": "public-only" }, "content": { - "sha256": "b6163b899fe407662c262278ff5bd331aae16757bfb346098c30b24df884b077", + "sha256": "f71b4a55caa29b2d60f3442d1c864729cad1a049d3ebfb2d35330b23cab9d2a4", "files": [ { "path": "adoption.mdx", @@ -21,8 +21,8 @@ }, { "path": "analysis/boundaries.mdx", - "bytes": 15177, - "sha256": "7106f782809b2d63e9691cf164e9e2bbd4c8f2e7541bf63476eebd89c2203a9c" + "bytes": 15186, + "sha256": "b1fe2859c2dd064519e5512d45df7f7137ccff6d0ec30e2b57862fd6fcf1b3c7" }, { "path": "analysis/css-analysis.mdx", @@ -86,8 +86,8 @@ }, { "path": "cli/architecture.mdx", - "bytes": 6778, - "sha256": "06171c74968eaf6dd1d26593f32e08299b3be3fb025c3533b79d70362c722b57" + "bytes": 7122, + "sha256": "cc495957596d6adb2a2b63985487b3da6badea11a23112d5a92460146f73947e" }, { "path": "cli/audit.mdx", @@ -396,8 +396,8 @@ }, { "path": "integrations/ci.mdx", - "bytes": 84866, - "sha256": "f62f8084977327ac25b6f91f5d02eae0873bb16b35f6a42dafade5f4f887a5dd" + "bytes": 85056, + "sha256": "7e4050a830fed07417ac79fac98832d61311a727db477b6e96b10d6d09f02c22" }, { "path": "integrations/claude-hooks.mdx", From 0de8689cde13325be805b0f8aa984e64f3326772 Mon Sep 17 00:00:00 2001 From: Bart Waardenburg Date: Wed, 7 Oct 2026 21:25:19 +0200 Subject: [PATCH 3/4] docs(node-bindings): note the deprecated dead-code flags --- integrations/node-bindings.mdx | 2 ++ public-content-manifest.json | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/integrations/node-bindings.mdx b/integrations/node-bindings.mdx index a93421b..949ecc3 100644 --- a/integrations/node-bindings.mdx +++ b/integrations/node-bindings.mdx @@ -81,6 +81,8 @@ All eight functions are async and take an optional options object. The functions | `computeComplexity(options?)` | `fallow health --format json` | `HealthReport` | | `computeHealth(options?)` | `fallow health --format json` | Alias for `computeComplexity` | +The `--circular-deps` and `--boundary-violations` flags of `fallow dead-code` are deprecated aliases. They select only one issue type, so they stay the exact CLI equivalents here. [`fallow architecture`](/cli/architecture) reports all import cycles, boundary violations and policy violations together. + ### Shared options Every options object extends `AnalysisOptions`: diff --git a/public-content-manifest.json b/public-content-manifest.json index 735a08d..d29916b 100644 --- a/public-content-manifest.json +++ b/public-content-manifest.json @@ -7,7 +7,7 @@ "visibility": "public-only" }, "content": { - "sha256": "f71b4a55caa29b2d60f3442d1c864729cad1a049d3ebfb2d35330b23cab9d2a4", + "sha256": "1ce1d95097095d950657ebeb02a814ed999519d1caae9cbc2815dbd85880aa09", "files": [ { "path": "adoption.mdx", @@ -421,8 +421,8 @@ }, { "path": "integrations/node-bindings.mdx", - "bytes": 11915, - "sha256": "3453e126a02a015e29a957026a815be220f65ba58161861227111c9a3dae4ffb" + "bytes": 12218, + "sha256": "9e2097786d41df159969d795d42739bce230eeac62700b054eed2617bfac631a" }, { "path": "integrations/vscode.mdx", From 0c83845bd0ca94f006915ed04f642eae630fb515 Mon Sep 17 00:00:00 2001 From: Bart Waardenburg Date: Wed, 7 Oct 2026 22:06:53 +0200 Subject: [PATCH 4/4] docs(cli): match the architecture layout and status line --- analysis/boundaries.mdx | 2 +- cli/architecture.mdx | 2 +- public-content-manifest.json | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/analysis/boundaries.mdx b/analysis/boundaries.mdx index 24c4a86..0ac43eb 100644 --- a/analysis/boundaries.mdx +++ b/analysis/boundaries.mdx @@ -339,7 +339,7 @@ All output formats include boundary violations: Imports that cross defined architecture zone boundaries https://fallow.tools/docs/explanations/dead-code/#boundary-violations - ✗ 2 violations (0.05s) + ✗ 2 boundary violations (0.05s) ``` diff --git a/cli/architecture.mdx b/cli/architecture.mdx index b2b6358..ac09e5c 100644 --- a/cli/architecture.mdx +++ b/cli/architecture.mdx @@ -131,7 +131,7 @@ fallow architecture --baseline fallow-architecture-baseline.json ## Bare `fallow` -Bare `fallow` also reports these findings. In human output without `--quiet`, they show in an "Architecture" section after the dead code findings. With `--quiet`, they stay in the "Structure" and "Policy" categories. The JSON and the other machine formats do not change: the findings stay in the dead code part of the output. +Bare `fallow` also reports these findings. In human output, they show in an "Architecture" category inside the Dead Code section, after the other dead code categories. This is the same with `--quiet`. The JSON and the other machine formats do not change: the findings stay in the dead code part of the output. To run only this section, pass `--only architecture`. To leave it out, pass `--skip architecture`. See [global flags](/cli/global-flags). diff --git a/public-content-manifest.json b/public-content-manifest.json index d29916b..35f158f 100644 --- a/public-content-manifest.json +++ b/public-content-manifest.json @@ -7,7 +7,7 @@ "visibility": "public-only" }, "content": { - "sha256": "1ce1d95097095d950657ebeb02a814ed999519d1caae9cbc2815dbd85880aa09", + "sha256": "5716ccd4eb06976a7d411f724a7086b7dab1e4c6411faf4cdb791ce245afdf48", "files": [ { "path": "adoption.mdx", @@ -21,8 +21,8 @@ }, { "path": "analysis/boundaries.mdx", - "bytes": 15186, - "sha256": "b1fe2859c2dd064519e5512d45df7f7137ccff6d0ec30e2b57862fd6fcf1b3c7" + "bytes": 15195, + "sha256": "7c5615bac79060a9d1be82d77c1da93f83578c0f7da2362ac9df9827526dfb0c" }, { "path": "analysis/css-analysis.mdx", @@ -86,8 +86,8 @@ }, { "path": "cli/architecture.mdx", - "bytes": 7122, - "sha256": "cc495957596d6adb2a2b63985487b3da6badea11a23112d5a92460146f73947e" + "bytes": 7106, + "sha256": "4c5ff7e74064f6a1c326c9f745789f5acab32df9d6ee9ec3356ee55a86cc12d8" }, { "path": "cli/audit.mdx",