fallow guard
Know the architecture rules for a file before you edit it. Fallow guard reports the boundary zone, the zones the file can import from, the forbidden calls, and the rule-pack policies with their suppression tokens.
Before you write code in a file, fallow guard tells you what the file is allowed to do. You can then choose an allowed import from the start, and you do not have to fix a violation later. For each file, guard reports:
- the boundary zone of the file
- the zones that the file can import from
- the calls that are forbidden in that zone
- each rule-pack policy in scope, with the token that suppresses it
guard reads the configuration and runs no analysis. It is fast enough to call on every edit, and it works on files that do not exist yet.
fallow guard src/ui/App.ts
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 architecture after the edit. fallow audit also reports boundary-violation and policy-violation findings in the changed files.
Output
src/ui/App.ts (zone: ui)
note: Same-zone imports are always allowed.
may import zones: shared, ui (same zone) type-only: db
forbidden calls in zone: child_process.*, eval
policy rules:
warn house-rules/no-child-process banned-call: child_process.*
suppress: // fallow-ignore-next-line policy-violation:house-rules/no-child-process -- <reason>
severities: boundary-violation=error policy-violation=warn
Files that do not exist yet
guard matches the path against the zone patterns and does not read the file. You can call it for a file that you are about to create:
fallow guard src/ui/NewScreen.tsx
The JSON has "exists": false, and the human output adds an exists: false line. guard fills every rule field as usual.
Paths outside every zone
For a path that matches no configured zone, guard returns "zone": null and an empty rule set. This is a normal answer and not an error: import rules do not restrict files outside every zone.
src/orphan/thing.ts (zone: none)
note: Files outside every zone are unrestricted for import and call checks.
may import zones: none type-only: none
forbidden calls in zone: none
policy rules:
warn house-rules/no-moment banned-import: moment
suppress: // fallow-ignore-next-line policy-violation:house-rules/no-moment -- <reason>
severities: boundary-violation=error policy-violation=warn
A file outside every zone has no import rules, but the policy rules still apply. A rule-pack rule that declares no zones applies everywhere, so it still appears in the output.
Some projects set boundaries.coverage.requireAllFiles. If the path does not match an allowUnmatched glob, the JSON has "coverage_required": true. An analysis run then reports the file as a boundary-coverage-violation because it belongs to no zone. The human output adds a second note that says boundaries.coverage.requireAllFiles is enabled. In scripts, read coverage_required from the JSON.
Options
| Flag | Default | Description |
|---|---|---|
<FILES>... | required | One or more files to report on. Paths can be root-relative or absolute. The output shows them root-relative. |
--root <ROOT> | current directory | Project root directory. |
--config <CONFIG> | discovered | Path to the Fallow config file. |
--allow-remote-extends | off | Allow trusted config files to extend HTTPS URLs. |
--format <FORMAT> | human | human or json only. |
--pretty | off | Indent JSON output. |
--quiet | off | Suppress progress output. |
--help also lists the analysis flags. They have no effect on guard because it runs no analysis. This includes the scoping, baseline, and severity-gate flags. Any format other than human or json exits 2 with guard supports --format json or human.
Exit codes
| Code | Meaning |
|---|---|
0 | The rules were reported, including when a path matches no zone or does not exist. |
2 | Invalid input or configuration, such as an unsupported --format or a rule pack that fails to parse. |
guard reports no findings, so it never exits 1.
JSON output
{
"files": [
{
"path": "src/ui/App.ts",
"exists": true,
"zone": {
"name": "ui",
"patterns": ["src/ui/**"]
},
"boundary": {
"configured": true,
"unrestricted": false,
"allowed_zones": ["shared", "ui"],
"allowed_type_only_zones": ["db"],
"forbidden_calls": ["child_process.*", "eval"],
"coverage_required": false
},
"policy_rules": [
{
"pack": "house-rules",
"rule_id": "no-child-process",
"kind": "banned-call",
"patterns": ["child_process.*"],
"message": null,
"severity": "warn",
"suppress_token": "policy-violation:house-rules/no-child-process"
}
],
"severities": {
"boundary_violation": "error",
"policy_violation": "warn"
},
"notes": ["Same-zone imports are always allowed."]
}
],
"kind": "guard"
}
allowed_zonesalways contains the zone of the file itself, because same-zone imports are never restricted.unrestrictedistruewhen no import rule applies to the file. This happens when boundaries are not configured, or when the path is outside every zone.policy_rulescontains only the rules in scope for that file. A rule that declareszonesappears only for files in those zones. The array is empty whenrules.policy-violationisoff.- For a
gdp-proof-producerpolicy,allowed_fileslists the globs where proof factories are permitted.proof_kinds, when present, lists the exact label filter. An absent filter checks every recognized factory call, including dynamic labels. The human output also shows the allowed producers and proof kinds. These fields describe permission; the rule's scope still comes fromfiles,exclude, andzones.
Suppression tokens
Each policy rule reports the exact token that suppresses it. You can copy the comment directly from the output:
// fallow-ignore-next-line policy-violation:house-rules/no-moment -- vendored, migrating in Q3
import moment from "moment";
The token is policy-violation:<pack>/<rule-id>. Rule ids are unique in a pack, so the pair identifies one rule in all places.
For agents
Call guard on the files you are about to change, while you can still choose what to write. An agent that reads the rules first can pick an allowed import. An agent that runs an analysis after the edit can only fix the violation it already wrote.
fallow guard --format json --quiet <files>
After the edit, run fallow architecture to find the violations in the code:
fallow architecture --format json --quiet
The guard MCP tool gives the same output as fallow guard. The MCP integration guide describes it.
See also
Find import cycles, boundary violations, and policy violations after an edit.
How fallow detects imports that cross zone boundaries.
Define zones, import rules, and forbidden calls.
Suppress a finding with an inline comment.
Call guard and other fallow tools from an agent.