Configuration reference
Settings live under [guard] in mago.toml. The configuration has two parts: [guard.perimeter] for dependency rules and [[guard.structural.rules]] for structural conventions.
Top-level options
| Option | Type | Default | Description |
|---|---|---|---|
mode | string | "default" | Which checks to run. One of "default", "structural", "perimeter". |
excludes | string[] | [] | Paths or glob patterns to exclude from analysis. Additive to [source].excludes. |
baseline | string | unset | Path to a baseline file. Equivalent to passing --baseline on every run. |
baseline-variant | string | "loose" | Format for newly generated baselines. "loose" (count-based) or "strict" (exact line matching). See baseline. |
minimum-fail-level | string | "error" | Minimum severity that causes a non-zero exit. One of "note", "help", "warning", "error". Overridden by --minimum-fail-level. |
mode controls which half of the guard runs:
"default"runs both halves."structural"runs only structural checks."perimeter"runs only perimeter checks.
[guard]
mode = "structural"
The --structural and --perimeter flags override the configured mode. See the command reference.
excludes here is added to whatever you set in [source].excludes; it never narrows the global list.
[source]
excludes = ["cache/**"]
[guard]
excludes = ["src/ThirdParty/**"]
Perimeter guard
The perimeter section defines dependency rules between parts of the project.
[guard.perimeter]
layering = [
"CarthageSoftware\\Domain",
"CarthageSoftware\\Application",
"CarthageSoftware\\UI",
"CarthageSoftware\\Infrastructure",
]
[guard.perimeter.layers]
core = ["@native", "Psl\\**"]
psr = ["Psr\\**"]
framework = ["Symfony\\**", "Doctrine\\**"]
[[guard.perimeter.rules]]
namespace = "CarthageSoftware\\Domain"
permit = ["@layer:core"]
[[guard.perimeter.rules]]
namespace = "CarthageSoftware\\Application"
permit = ["@layer:core", "@layer:psr"]
[[guard.perimeter.rules]]
namespace = "CarthageSoftware\\Infrastructure"
permit = ["@layer:core", "@layer:psr", "@layer:framework"]
[[guard.perimeter.rules]]
namespace = "CarthageSoftware\\Tests"
permit = ["@all"]
layering
An ordered list of namespaces, from the most independent core down to the outermost layer. Each layer can only depend on layers defined before it. A dependency that points to a layer further out triggers a violation.
Layer aliases
[guard.perimeter.layers] defines reusable groups of namespaces and paths, referenced from rules with @layer:<name>.
Rules
Each [[guard.perimeter.rules]] table defines one rule:
namespace: the namespace this rule applies to. Either a namespace ending in\or the special keyword@globalfor the global namespace.permit: the dependencies that are allowed. Either a list of strings or a list of detailed objects.
permit values
permit accepts paths. A path can be a keyword, a namespace, a symbol, or a glob pattern.
| Path | Description |
|---|---|
@global | Symbols defined in the global namespace. |
@all | Any symbol anywhere in the project, including vendor packages. Useful for tests. |
@self / @this | Any symbol within the same root namespace as the rule's namespace. |
@native / @php | PHP's built-in functions, classes, and constants. |
@layer:<name> | All namespaces and paths in the named alias from [guard.perimeter.layers]. |
App\Shared\\** | Glob pattern. * matches a single namespace segment, ** matches zero or more. |
App\Service | Exact fully qualified symbol name. |
App\Service\\ | Exact namespace. Allows symbols directly within it. |
You can narrow a permission by symbol kind using an object form:
[[guard.perimeter.rules]]
namespace = "DoctrineMigrations\\"
permit = [{ path = "@all", kinds = ["class-like"] }]
path: any of the path forms above.kinds: which kinds of symbols are permitted. Values areclass-like(covers classes, interfaces, traits, enums),function,constant, andattribute.
Dependency restrictions
[[guard.perimeter.restrictions]] defines target-oriented restrictions. Use these when a dependency must only be used from selected namespaces, or must be forbidden from selected namespaces.
[[guard.perimeter.restrictions]]
dependency = "App\\Http\\Controllers\\Controller"
allow-from = ["App\\Http\\Controllers\\"]
kinds = ["class-like"]
[[guard.perimeter.restrictions]]
dependency = "Illuminate\\Foundation\\Bus\\Dispatchable"
deny-from = ["App\\"]
| Key | Description |
|---|---|
dependency | Required symbol selector. Accepts an exact fully qualified name, a namespace ending in \, or a glob pattern. |
allow-from | Optional source namespace patterns. When non-empty, matching dependencies are only allowed from these namespaces. |
deny-from | Optional source namespace patterns. Matching dependencies are forbidden from these namespaces. |
kinds | Optional dependency-kind filter. Values: class-like, function, constant, attribute. An empty list applies to every kind. |
Restrictions are evaluated before ordinary permit rules and layering, so a permit cannot override a restriction. If both allow-from and deny-from match, deny-from wins. Matching allow-from only satisfies the restriction; ordinary perimeter rules and layering must still allow the dependency when configured. A configuration containing only restrictions allows unrelated dependencies; restrictions do not create an implicit allowlist.
Structural guard
[[guard.structural.rules]] defines structural conventions. Each entry combines selectors that pick which symbols to inspect with constraints that the selected symbols must satisfy.
[[guard.structural.rules]]
on = "CarthageSoftware\\UI\\**\\Controller\\**"
target = "class"
must-be-named = "*Controller"
must-be-final = true
must-be-readonly = true
reason = "Controllers must be final and follow naming conventions."
[[guard.structural.rules]]
on = "CarthageSoftware\\Domain\\**\\Repository\\**"
target = "interface"
must-be-named = "*RepositoryInterface"
reason = "Domain repository interfaces must follow a standard naming convention."
[[guard.structural.rules]]
on = "CarthageSoftware\\Infrastructure\\**\\Repository\\**"
target = "class"
must-be-final = true
must-extend = "CarthageSoftware\\Infrastructure\\Shared\\Repository\\AbstractRepository"
reason = "Infrastructure repositories must extend our abstract class."
[[guard.structural.rules]]
on = "CarthageSoftware\\Domain\\**\\Enum\\**"
must-be = ["enum"]
reason = "This namespace is designated for enums only."
Selectors
| Key | Description |
|---|---|
on | Required. Glob pattern matching the fully qualified name of the symbols this rule applies to. |
not-on | Optional glob pattern excluding symbols that would otherwise match on. |
target | Optional filter restricting the rule to one symbol kind. One of class, interface, trait, enum, function, constant. |
Constraints
| Key | Description |
|---|---|
must-be | Restrict the selected namespace to contain only the listed symbol kinds. Values: class, interface, trait, enum, function, constant. |
must-be-named | Glob pattern the symbol name must match (e.g. *Controller). |
must-be-final | Boolean. true requires final; false forbids it. |
must-be-abstract | Boolean. true requires abstract; false forbids it. |
must-be-readonly | Boolean. true requires readonly; false forbids it. |
must-implement | One or more interfaces the class must implement. |
must-extend | A class the symbol must extend. |
must-use-trait | One or more traits the symbol must use. |
must-use-attribute | One or more attributes the symbol must carry. |
only-public-methods | Public method names that matched classes may declare. |
reason | Human-readable explanation shown in error messages. |
Public method allowlists
only-public-methods applies to classes and lists allowed method names. Names are matched case-insensitively. The listed methods are allowed but are not required to exist.
[[guard.structural.rules]]
on = "App\\Http\\Controllers\\**"
target = "class"
only-public-methods = ["__construct", "__invoke"]
The rule checks public methods declared directly by each matched class, including methods with no explicit visibility because PHP treats them as public. Private and protected methods are unrestricted. Inherited methods and methods provided by traits are not checked.
Inheritance constraint shapes
must-implement, must-extend, must-use-trait, and must-use-attribute accept a single string, an array of strings (AND), or an array of arrays of strings (OR of ANDs). The literal "@nothing" forbids any value.
must-extend = "App\\BaseClass"
must-implement = ["App\\InterfaceA", "App\\InterfaceB"]
must-extend = [
["App\\AbstractA", "App\\AbstractB"],
["App\\AbstractC"],
]
must-implement = "@nothing"