Enforce architecture boundaries in CI with dependency-cruiser or eslint-boundaries: layer direction, feature isolation, forbidden imports. Use when "enforce module boundaries" or "stop spaghetti imports". Advice only → audit-backend-architecture.
Installs into .claude/skills of the current project.
Are you the author of Enhance Arch Boundaries?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/kensaurus-enhance-arch-boundaries)
---
name: enhance-arch-boundaries
description: >
Enforce architecture boundaries in CI with dependency-cruiser or
eslint-boundaries: layer direction, feature isolation, forbidden imports.
Use when "enforce module boundaries" or "stop spaghetti imports". Advice
only → audit-backend-architecture.
license: MIT
effort: high
---
# enhance-arch-boundaries — Architecture as a fitness function
**Degree of freedom: MIXED.** Recovering the model
`[HIGH freedom]`; do-not-invent, shrink-only baseline, and deliberate-violation
probes `[LOW freedom — run exactly]`.
Codify the repo's intended structure as rules that block merge. **Import
spaghetti is how agents degrade architecture: each import looks locally
reasonable, no single diff is wrong, and after forty sessions the
layering is gone.** A rule in AGENTS.md is advisory. A dependency-cruiser
rule in the aggregator gate is physics.
## This skill vs neighbors
| Skill | Owns |
|---|---|
| **enhance-arch-boundaries** (this) | Mechanical boundary rules + shrink-only baseline |
| `audit-backend-architecture` | Advises which pattern to adopt — does not enforce |
| `housekeep-gates` | Wires this check into the aggregator |
| `docs-adr` | Records *why* the model was chosen |
| `enhance-agent-guardrails` | Broader guard install; this owns the import graph |
## How to reason
1. **Observe** — folder layout, existing conventions, any architecture audit
2. **Interpret** — what layering does the repo already mean to have?
3. **Classify** — recoverable model / no intended structure (stop) / inventing (forbidden)
4. **Severity** — client → server-only / service-role is the worst edge
## Worked example
> **Observe:** `app/dashboard/page.tsx` imports `@/lib/supabase/admin`
> (service-role). No boundary rule.
> **Interpret:** the intended split exists in folder names but is not physics.
> **Classify:** forbidden edge — client → server-only.
> **Fix:** dependency-cruiser / eslint-boundaries rule; grandfather other
> violations into a shrink-only baseline; probe a new forbidden import fails CI.
---
## Phase 0 — Recover the intended architecture (do not invent one) [LOW freedom — stop if none]
The rules must encode the architecture the repo *means* to have.
- Read folder structure and existing conventions (`features/*`, `app/`,
`lib/`, `server/`, `components/`, monorepo packages).
- Read `audit-backend-architecture` output if it exists — that is the
drift to stop.
- Confirm with the user in one pass: layers and allowed direction (e.g.
`ui → application → domain → infrastructure`, never reverse), feature
units that must stay isolated, special zones (server-only, secrets,
generated).
State the model in ten lines before writing any rule. If the repo
genuinely has no intended structure, **stop and say so** — enforcing a
structure nobody chose creates fights, not quality. Propose a minimal
layering first.
---
## Phase 1 — Install the rule set [HIGH freedom; mapped to the confirmed model]
Tool by stack: **dependency-cruiser** (framework-agnostic JS/TS),
**eslint-plugin-boundaries** (when living inside ESLint is preferable),
Nx module-boundary tags, import-linter (Python).
Core rules, each mapped to the confirmed model:
- **Layer direction** — lower layers cannot import upward; skipping
layers flagged where the model says so.
- **Feature isolation** — features import each other only via a public
surface (`features/x/index.ts`), never deep paths. Shared code goes
through `shared/`, not sideways.
- **No circular dependencies** — anywhere. Cycles are where "change one
thing" stops being possible.
- **Forbidden edges** — client importing server-only / service-role
modules (cross-ref `plan-rls-audit` / `plan-secrets-audit`), UI
importing the DB layer directly, production importing test utilities,
anything importing generated internals.
- **No orphans** — modules nothing reaches (feeds `workflow-housekeep`).
- **Dependency hygiene** — no `devDependencies` from shipped code;
deprecated internals marked un-importable so migration ratchets.
---
## Phase 2 — Grandfather, then ratchet [LOW freedom — shrink-only baseline]
Do not weaken the rules to fit existing violations, and do not block the
repo on fixing them all.
- Capture existing violations into the tool's **known-violations
baseline** so CI is green today.
- The baseline is a **shrink-only ratchet**: new violations fail;
existing ones are tracked debt; the baseline file can only get smaller
without review — same reset policy as `housekeep-gates`.
- File the grandfathered list as a burndown, worst edges first (cycles
and client→server-secrets before cosmetic layer skips).
---
## Phase 3 — Wire and make agent-legible [HIGH freedom]
- Add the check to CI wired into the aggregator gate (`housekeep-gates`)
and mirror it in local hooks (same command, two callers).
- Generate the dependency **graph visualization** into docs; regenerate
it on the scheduled run so it cannot go stale.
- Write the ten-line model + "how to fix a boundary violation" into
agent rules *referencing the mechanical check* — the rule text
explains, the gate enforces.
- Record the architecture decision as an ADR (`docs-adr`) so a future
session knows the layering was chosen, by whom, and why the rejected
alternative lost.
---
## Definition of Done
- [ ] Intended model recovered from the repo + confirmed with the user (or the no-structure finding raised)
- [ ] Rules installed: layer direction, feature isolation via public surfaces, no cycles, forbidden edges (incl. server-only → client), no orphans, dep hygiene
- [ ] Existing violations grandfathered into a shrink-only baseline; burndown filed worst-first
- [ ] Check in the aggregator gate + local hooks with one shared command
- [ ] Graph visualization generated into docs with a regeneration schedule
- [ ] Agent rules updated to state the model and point at the gate; decision recorded via `docs-adr`
- [ ] Deliberate-violation probe: a test import that breaks each rule class fails CI
## Self-critique before claiming done [LOW freedom — do not skip]
1. **Model confirmed** — or you stopped; you did not invent a layering
2. **Baseline shrink-only** — new violations fail; no silent growth
3. **Probe per rule class** — a test import failed CI
4. **Right owner** — pattern advice → `audit-backend-architecture`; why → `docs-adr`
5. **Aggregator wired** — `housekeep-gates`
## Output format
1. **Architecture model** — ten-line statement of layers, directions, features, special zones
2. **Rule set** — rule | what it forbids | why (mapped to the model)
3. **Grandfathered baseline** — count by rule | worst-first burndown
4. **Wiring** — gate job, hook parity, graph location, agent-rule text added
5. **Probe evidence** — violation per rule class | CI result
Applied directly (enhance-family). Pause for approval only on the model
confirmation and before committing the baseline.