YAML Schema Reference¶
The machine-readable root/effective-policy schema is schema/dependencies.arch.schema.json. Imported fragments use schema/dependencies.arch.fragment.schema.json.
This page explains the stable shape that users need most often; the JSON Schema and arch-linter-net schema print remain the exact field/type authority.
Discover the installed schemas¶
arch-linter-net schema list
arch-linter-net schema print policy-root
Persisted format schemas are versioned independently from package SemVer. Do not synthesize schema URLs from the tool package version.
Immutable release-qualified schema IDs remain valid when the version is itself the machine contract. Policy root/fragment schemas currently use https://archlinternet.dev/schema/0.8.0/dependencies.arch.schema.json and https://archlinternet.dev/schema/0.8.0/dependencies.arch.fragment.schema.json; other frozen registry entries retain their immutable 0.5.1 or 0.6.1 identities. These numbers are schema-contract identities, not the identity of this evergreen page.
Root and fragment schemas¶
| Document | Repository schema | Purpose |
|---|---|---|
| Selected root/effective policy | schema/dependencies.arch.schema.json |
The one path passed to validation or policy check. |
| Imported fragment | schema/dependencies.arch.fragment.schema.json |
Mergeable content reached through the root's ordered imports. |
The root schema requires version, name, layers, analysis, and contracts. A root may keep an empty container when imported fragments contribute its entries.
Minimal root¶
For new v0.8 policy authoring, prefer policy version: 2 so strict structured-waiver lifecycle defaults are explicit:
version: 2
name: My Architecture Contract
layers:
domain:
namespace: MyApp.Domain
analysis:
solution: MyApp.sln
contracts: {}
The schema accepts policy versions 1 and 2:
- version 1 preserves compatibility waiver defaults for existing policies;
- version 2 defaults to strict structured-waiver lifecycle governance.
The policy version is a persisted policy-contract version, not the NuGet package SemVer. Existing v1 policies remain supported; move to v2 deliberately when their manual ignores are ready for strict lifecycle behavior. name is the human-readable policy identity. See Structured waivers and the extended-governance adoption guide.
Layers¶
A layer can be matched by namespace, by semantic selector, or by both.
layers:
domain:
namespace: MyApp.Domain
commands:
selector:
role: command
metadata:
bounded_context: Sales
sales_commands:
namespace: MyApp.Sales
selector:
role: command
namespace is not required when a valid selector is present. Selector-only layers are runtime-supported.
When both namespace and selector are present, matching uses AND semantics: a type must satisfy both.
Relevant layer fields include:
layers:
<name>:
namespace: MyApp.Features.* # optional when selector is present
namespace_suffix: Application # optional; requires namespace
selector: # optional when namespace is present
role: application_service
metadata:
bounded_context: Sales
when: "subject.type.kind == 'class'"
external: false
exclude:
- namespace: MyApp.Features.Generated
reason: Generated code is outside this boundary.
overlaps_with: [another_layer]
Namespace matching supports literal prefixes and constrained full-segment * globs. It does not provide arbitrary regular expressions. See Layers and namespace patterns and Semantic classification.
Imports¶
imports is an ordered list of repository-local fragment paths. Runtime composition resolves imports deterministically and validates the effective policy.
imports:
- policy/domain.arch.yml
- policy/infrastructure.arch.yml
Fragments use the fragment schema and contain only mergeable policy sections. See Policy imports.
External, package, and framework groups¶
Policies can name reusable dependency groups:
external_dependencies:
logging:
namespace_prefixes: [Serilog]
packages:
persistence:
package_ids: [Npgsql]
package_prefixes: [Microsoft.EntityFrameworkCore]
framework_references:
aspnet:
framework_names: [Microsoft.AspNetCore.App]
Use the corresponding contract families rather than modeling project/package facts as fake namespaces.
Source sets¶
source_sets provide bounded reusable layer, assembly, or project inputs:
source_sets:
modules:
kind: assembly
globs: [MyApp.Modules.*]
Supported families can expand sources/source_sets into one concrete contract instance per resolved source; selected list-shaped fields union resolved set members instead. Resolution never widens beyond the policy's declared analysis universe and fails closed on unknown, mismatched, or unreviewed empty inputs.
Classification¶
Semantic classification can derive role/metadata from implemented attribute, assembly-attribute, inheritance, and namespace rules. Selector-backed layers and contextual contracts consume the resulting per-run index.
classification:
namespace:
- namespace: MyApp.Features.*
role: feature
The full implemented/deferred semantics are documented in Semantic classification. Schema presence alone is not proof that an analysis source is implemented.
Analysis¶
Common analysis fields include:
analysis:
solution: MyApp.sln
projects: []
project_include: []
project_exclude:
- "**/*.Tests/**"
target_assemblies: []
assembly_search_paths: []
source_roots: []
configuration: Debug
target_framework: ""
condition_sets: {}
default_condition_set: ""
unmatched_ignored_violations: error
policy_consistency: error
coverage: error
policy_weakening: error
waiver_lifecycle_profile: strict # strict or compatibility; v2 defaults to strict
Policies may use explicit target assemblies or project/solution discovery. Normal validation does not silently build. --ensure-built is an explicit CLI workflow that builds the selected project graph, verifies the build receipt, then validates.
Architecture-waiver lifecycle¶
ignored_violations retains its legacy matcher shape for version-1 policies. A version-2 policy defaults to the strict waiver-lifecycle profile: every manually authored waiver must name an immutable target fingerprint, owner, tracking issue, introduced date, and expiry date. Use compatibility explicitly only while migrating existing legacy entries.
ignored_violations:
- id: ARCH-IGN-042
source_type: MyApp.Application.Legacy.LegacyUseCase
forbidden_reference: MyApp.Infrastructure.LegacyGateway
target:
fingerprint: sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
reason: Temporary migration seam while the gateway is extracted.
owner: architecture-team
issue: ARCH-231
introduced: 2026-08-01
expires: 2026-10-01
Use ArchitectureWaiverTargetFingerprint.Create from the Core API to create a target value from the exact violation identity. The linter does not treat the display matchers as the target: the fingerprint prevents the waiver from silently covering another occurrence that happens to have the same text. A fingerprint is sha256: followed by 64 lowercase hexadecimal characters; uppercase hexadecimal is rejected as non-canonical. An incomplete manual waiver under the strict profile is reported as fail-closed invalid lifecycle evidence and does not suppress a finding. Under compatibility semantics, a legacy matcher-only entry remains visible as metadata_incomplete debt.
Contracts¶
contracts contains strict and audit groups. Every currently supported family, its group names, and its dedicated reference are listed in Contract families.
Examples:
contracts:
strict:
- id: app-no-infra
name: app-no-infra
source: application
forbidden: [infrastructure]
reason: Keep the application boundary independent of infrastructure.
strict_coverage:
- id: namespace-coverage
name: namespace-coverage
scope: namespace
roots:
- namespace: MyApp
reason: Every first-party namespace must be governed.
Do not invent group names or fields; use the machine inventory and schema.
Validate authoring before architecture analysis¶
arch-linter-net policy check --policy architecture/arch.yml
policy check validates policy syntax, imports, composition, static declarations, references, and static configuration without claiming architecture compliance for checks that require project/assembly/source facts.
For the effective policy facts seen by an agent or reviewer:
arch-linter-net policy context --policy architecture/arch.yml --format json
Then run normal strict/audit validation.
Unknown and deferred fields¶
Use schema validation even though some deserialization paths are intentionally tolerant for compatibility. Raw validators additionally fail closed for selected high-risk vocabularies.
A field explicitly documented as deferred/no-op remains unsupported behavior even if the schema accepts it. The capability boundary distinguishes implemented behavior from non-goals.