Skip to content

Architecture as code

Architecture Guardian checks whether the dependencies in your C# code follow the boundaries your team declares. The policy lives in architecture.guardian.yaml, so architecture changes can be reviewed alongside implementation changes.

You choose the architecture. Names such as Domain, Application and Billing have no built-in behavior: project selectors and explicit permissions give them meaning. The same approach supports Clean Architecture, a modular monolith, or a simpler application with a few boundaries worth protecting.

ConceptQuestion it answers
ModuleWhich business or functional boundary owns this project?
LayerWhich technical responsibility does this project belong to?
Public contractWhich whole projects may be consumed as this module’s API?
Dependency permissionWhich outgoing module, contract or layer dependencies are intentional?
RestrictionWhich assemblies or namespace trees must this boundary avoid?
Rule and gateWhich checks run, at which severities, and what blocks the scan?

Modules and layers are independent dimensions. Orders can contain Domain, Application and Infrastructure projects; the Domain layer can contain projects from several modules. See modules, layers and contracts.

How a scan works diagram
How a scan works diagram
100%
View diagram source
flowchart LR
Policy["YAML policy<br/>Ownership and constraints"] --> Resolve["Resolve every loaded project"]
Input["Restored solution or project<br/>Configuration and framework"] --> Resolve
Resolve --> Dependencies["Observe references and bound C# uses"]
Dependencies --> Rules["Evaluate selected rules"]
Rules --> Result["Diagnostics, coverage and gate outcome"]

The tool loads the selected build context, resolves ownership, observes actual references and semantic uses, and evaluates the rules selected in YAML. It does not treat a namespace mentioned in a comment or an unused using directive as a dependency. See dependency analysis.

The policy declares constraints; it does not create C# references, change access modifiers, or prevent compilation by itself. Install the compiler analyzer for build/editor feedback and run a solution scan to enforce a CI gate.

Choose the checks that express your intent

Section titled “Choose the checks that express your intent”
GoalRules to consider
Keep layer dependencies pointing inwardAG002
Permit only declared cross-module dependenciesAG001
Prevent logical module cyclesAG003
Keep another module’s implementation privateAG004
Ban particular assembly or namespace dependenciesAG005
Protect a layer from infrastructure technologies, with narrow exceptionsAG006

Only rules listed under rules run. Defining modules or restrictions does not implicitly enable a corresponding check. Start with constraints your team agrees to maintain, inspect the resolved ownership, then expand enforcement deliberately. The rule catalog explains each decision and its limits.

CLI and MCP share solution-wide analysis. The compiler analyzer checks the current compilation and gives earlier feedback on supported explicit C# uses. It does not check AG003 module cycles or establish coverage of the whole solution.

Use the right checkpoint diagram
Use the right checkpoint diagram
100%
View diagram source
flowchart TD
Policy["One shared YAML policy"] --> Editor["IDE and build analyzer<br/>Feedback in the current compilation"]
Policy --> Scan["CLI or MCP solution scan<br/>Full selected build context"]
Editor --> Change["Developer or agent corrects code"]
Scan --> Change
Change --> Gate["Fresh scan plus normal build, tests and review"]

Keep the engine differences visible when comparing results. A completed scan covers one configuration/framework context, not every possible build of the repository.

For a new repository, use the quick start to define your first policy and gate. For an existing repository, first inspect current findings. Correct immediate problems, then use a reviewed baseline to record accepted debt or a Git comparison to gate new findings.

Keep a full scan available: a passing new-finding gate may retain existing errors. An incomplete scan never proves compliance, even with an empty diagnostic list. Read diagnostics and outcomes, then choose a practical use case to apply in your own codebase.