Originally built this as a side project — sharing what I've learned along the way.
Your CI pipeline probably does a lot.
It runs unit tests, scans for vulnerabilities, lints your API spec, builds and pushes a container image.
What it almost certainly doesn't do is check whether your architecture is still what you agreed to build.
The problem isn’t that teams don’t care.
It’s that architecture lives in docs — and CI can’t read docs.
The gap nobody talks about
When a team agrees on a service boundary — no direct database access, auth required on every HTTP entry — that agreement lives in a Confluence doc or a Miro board.
Nothing in your pipeline can read those. So nothing enforces them.
A direct DB connection can merge. A missing auth boundary can ship. Not because nobody cared. Because nothing was gating on it.
Code review is the current answer. But code review happens after implementation. The architecture decision has already been made and built. At that point you're reviewing a fait accompli.
The post-code tools don't close this gap
ArchUnit, Spectral, Axivion, OPA — all solid tools. All operating on code, specs, or running systems that already exist.
The intervention point is after the first commit.
None of them can catch an architecture violation before a line of code is written.
What a pre-code gate looks like
Your architecture is a graph — services are nodes, dependencies are edges. Express it as a machine-readable IR. Run a deterministic compiler on it before code generation begins.
# Use your existing OpenAPI spec — no IR authoring required
npx @archrad/deterministic ingest openapi --spec your-api.yaml --out graph.json
npx @archrad/deterministic validate --ir graph.json
No security definitions in your spec → IR-LINT-MISSING-AUTH-010 fires automatically:
⚠️ IR-LINT-MISSING-AUTH-010: HTTP entry node "payment-api" has no auth node
or auth config in its immediate graph neighbourhood
Fix: Add an auth/middleware node or set config.authRequired: false for
intentionally public endpoints.
Impact: Unauthenticated HTTP entry points are a compliance gap in regulated
environments and a common attack surface.
Direct DB connection in the graph → IR-LINT-DIRECT-DB-ACCESS-002:
⚠️ IR-LINT-DIRECT-DB-ACCESS-002: API node "payment-api" connects directly
to datastore node "card-db"
Fix: Introduce a service or domain layer between HTTP handlers and persistence.
Impact: Harder to test, swap storage, or enforce invariants at a single boundary.
Same graph. Same compiler version. Same findings. Every time.
High level flow
graph IR (JSON/YAML)
↓
archrad validate ← blocks on violations
↓
archrad export
↓
code + OpenAPI + Docker
↓
archrad validate-drift ← blocks on divergence
↓
rest of CI (tests, security scans)
Machine-readable JSON output. CI-gateable. Blocks the PR.
Honest limits
Cold start is real. You have to get your architecture into graph IR format. OpenAPI ingestion helps for teams that already have specs. IaC ingestion — Terraform, CloudFormation — is roadmap, not shipped.
This doesn't prove semantic correctness. Drift detection means "code matches what the IR would generate" — not that your code is correct or matches production behavior. That's your tests.
No round-trip. Once you edit generated code there's no built-in path back to the IR. Think of it as scaffold plus contract validation, not full lifecycle sync.
The CI pipeline this enables
graph.json committed to repo
↓
archrad validate --fail-on-warning ← blocks PR if architecture violated
↓
archrad validate-drift ← blocks PR if code drifted from IR
↓
Spectral ← lint generated OpenAPI spec
↓
Snyk / Semgrep ← scan generated code
↓
Merge → deploy → operate
ArchRad runs first because structural violations should block before other tools waste time scanning code that shouldn't exist yet.
Try it
OSS under Apache-2.0. No IR authoring needed to get started:
# Ingest your existing OpenAPI spec
npx @archrad/deterministic ingest openapi --spec your-api.yaml --out graph.json
npx @archrad/deterministic validate --ir graph.json
# Or run against the built-in ecommerce fixture
npx @archrad/deterministic validate --ir fixtures/ecommerce-with-warnings.json
👉 github.com/archradhq/arch-deterministic
📦 npm install -g @archrad/deterministic
Closing question: does your CI pipeline gate on architecture today?
And if not — is that a tooling problem, a process problem, or just accepted as inevitable?
Top comments (0)