ark
Architectural boundary enforcer for .NET solutions. Parses .csproj project graphs and C# source files to catch layer violations before they reach CI.
$ ark check
× Domain → Infrastructure dependency forbidden
╭─[MyApp.Domain/Repositories/UserRepo.cs:3:7]
3 │ using MyApp.Infrastructure.Data;
· ────────────────────────
╰─
What it checks
| Check | What it catches |
|---|---|
| Project references | .csproj <ProjectReference> that cross forbidden layer boundaries |
| Package policies | <PackageReference> packages banned from specific layers (e.g. EF Core in Domain) |
| Source imports | using directives in .cs files referencing a forbidden layer's namespace (tree-sitter) |
Violations are reported with source spans pointing directly to the offending line.
Quick start
# 1. Generate a starter config in your solution root
# 2. Edit architecture.toml to match your layers, then:
Installation
Or build from source:
# binary: target/release/ark
Configuration
ark reads architecture.toml from the solution root. Run ark init to generate a starter file, or write one by hand:
[[]]
= "Domain"
= ["*.Domain", "*.Core"]
# Optional: enables C# using-directive checks for this layer
= ["MyApp.Domain.*"]
[[]]
= "Application"
= ["*.Application", "*.UseCases"]
[[]]
= "Infrastructure"
= ["*.Infrastructure"]
[[]]
= "Presentation"
= ["*.Api", "*.Web", "*.Host"]
[[]]
= "Presentation"
= "Application"
= true
[[]]
= "Application"
= "Domain"
= true
[[]]
= "Infrastructure"
= "Domain"
= true
[[]]
= "Domain"
= "Infrastructure"
= false
[[]]
= "Domain"
= ["Microsoft.EntityFrameworkCore", "Microsoft.AspNetCore"]
= ["*.Tests", "*.Specs", "*.IntegrationTests"]
Layer patterns use glob syntax (* matches any sequence of non-separator characters). Any dependency not listed in dependency_rules is forbidden by default.
namespace_patterns activates the C# source scan for a layer — omit it to skip tree-sitter parsing for that layer.
Commands
ark check
Run all architectural checks and report violations.
ark baseline
Snapshot current violations so ark check only fails on new ones. Useful for gradual adoption in brownfield solutions — lock in existing debt without silencing the tool.
ark-baseline.json should be committed alongside your config. Stale entries (violations that no longer exist) are reported as warnings so you can clean them up over time.
ark explain
Show which layer a project belongs to and what it can and cannot depend on.
Project: MyApp.Domain
Layer: Domain
Dependency rules:
→ Application forbidden [default]
→ Infrastructure forbidden [explicit]
→ Presentation forbidden [explicit]
Other projects in this layer:
MyApp.Core
Useful when a project shows up as unmatched, or when onboarding to an unfamiliar solution.
ark graph
Export the project dependency graph.
ark init
Generate a starter architecture.toml in the solution root.
CI integration
GitHub Actions
- name: Check architecture
run: |
cargo install ark-cli --quiet
ark check
ark exits 0 on clean, 1 on violations — no external dependencies required.
Global flags
ark --root <path> # solution root (default: current directory)
ark --config <path> # config file (default: architecture.toml)
These apply to all subcommands and are useful when running ark from a different directory:
Exit codes
| Code | Meaning |
|---|---|
0 |
No violations |
1 |
One or more violations found |
Use --strict to also exit 1 on warnings (e.g. projects that match no layer).
Performance
ark uses rayon for parallel project and file parsing.
| Operation | Target | Typical (ABP Framework, ~500 projects) |
|---|---|---|
| Project graph scan | < 50 ms | ~30 ms |
| Full source scan (tree-sitter) | < 500 ms | ~200 ms |
License
MIT