> Validate architectural layer boundaries and detect dependency violations. No code may violate layer constraints — this is a hard gate, not a suggestion.
Installs into .claude/skills of the current project.
Are you the author of Enforce Architecture?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/intense-visions-enforce-architecture)
# Enforce Architecture
> Validate architectural layer boundaries and detect dependency violations. No code may violate layer constraints — this is a hard gate, not a suggestion.
## When to Use
- Before approving any pull request or merge
- After writing new imports or module references
- When adding a new module or package to the project
- When `on_pre_commit` or `on_architecture_check` triggers fire
- After refactoring that moves code between layers or modules
- NOT when editing documentation, configuration, or non-code files
- NOT when the violation is intentional and requires a constraint update (escalate instead)
## Process
### Phase 1: Load Constraints
1. **Read `harness.config.json`** to understand the project's architectural constraints. The config defines:
- **Layers** — ordered list of architectural layers (e.g., `ui -> service -> repository -> domain`)
- **Dependency rules** — which layers may import from which (typically: layers may only import from layers below them)
- **Forbidden imports** — specific import paths that are never allowed in certain contexts
- **Boundary definitions** — which directories/packages belong to which layer
- **Design constraints** — when `design` config exists, also load design constraint rules:
- Token compliance — components must reference design tokens, not hardcoded values
- Accessibility compliance — color pairs must meet WCAG contrast ratios
- Anti-pattern enforcement — project-specific anti-patterns from `design-system/DESIGN.md`
- Platform binding — tokens must have appropriate platform bindings for enabled platforms
2. **Understand the layer model.** In a typical layered architecture:
- Higher layers depend on lower layers (UI depends on Service, Service depends on Repository)
- Lower layers NEVER depend on higher layers (Repository must not import from UI)
- Same-layer imports may or may not be allowed depending on project config
- Cross-cutting concerns (logging, config) have their own rules
### Graph-Enhanced Context (when available)
When a knowledge graph exists at `.harness/graph/`, use graph queries for faster, more accurate violation detection:
- `query_graph` — traverse `imports` edges against layer constraint nodes to find all violations in a single query
- `get_relationships` — find all code dependent on a violation target to show the full scope of impact
Graph queries show the complete violation scope (not just the first occurrence per file) and reveal transitive violations that single-file analysis misses. Fall back to file-based commands if no graph is available.
### Phase 2: Run Dependency Checks
1. **Run `harness check-deps`** to analyze all import statements against the constraint model. Capture the full JSON output.
1b. **Optionally run `harness check-arch`** for comprehensive architecture analysis beyond dependency checking. This covers circular dependencies, complexity, coupling, module size, and dependency depth in addition to layer violations.
2. **Parse the results.** Each violation includes:
- The violating file and line number
- The forbidden import target
- The source layer and target layer
- The specific rule being violated
### Phase 3: Analyze Violations
For each violation, determine:
1. **Which layers are involved.** Identify the source file's layer and the imported module's layer. Map them to the constraint model.
2. **What rule is violated.** Common violation types:
- **Upward dependency** — a lower layer imports from a higher layer (e.g., repository importing from UI). This is the most serious type. It creates coupling that makes the lower layer untestable in isolation.
- **Skip-layer dependency** — a layer reaches past its immediate neighbor (e.g., UI importing directly from Repository, bypassing Service). This breaks encapsulation and makes the middle layer pointless.
- **Circular dependency** — two modules or layers depend on each other. This creates fragile coupling where changing either module risks breaking the other.
- **Forbidden import** — a specific import that is explicitly banned (e.g., importing a database driver outside the repository layer). This prevents implementation details from leaking.
- **Design constraint violation** — a component uses hardcoded values instead of design tokens, or violates a declared anti-pattern. Severity depends on `design.strictness` in config. These violations surface as DESIGN-xxx codes:
- `DESIGN-001` [warn] — Hardcoded color/font/spacing instead of token reference
- `DESIGN-002` [warn] — Value matches a project anti-pattern
- `DESIGN-003` [error] — WCAG contrast ratio failure (error in strict mode)
- `DESIGN-004` [info] — Missing platform binding for enabled platform
3. **Explain the impact.** For each violation, state:
- WHY the constraint exists (what architectural property it protects)
- WHAT would happen if the violation were allowed to persist
- HOW it affects testability, maintainability, and changeability
### Phase 3.5: Apply Safe Architecture Fixes
Some architecture violations can be auto-fixed. Apply these before surfacing remaining violations.
**Import ordering violations:**
1. Identify files where imports are not ordered according to the project's layer convention.
2. Reorder imports: external packages first, then by layer (lowest to highest), then relative imports.
3. Verify with lint + typecheck. This is a safe, mechanical fix.
**Forbidden import replacement (with configured alternative):**
1. Check `harness.config.json` for `forbiddenImports` entries that include an `alternative` field.
2. For each violation where an alternative exists, replace the import path with the alternative.
3. Verify with typecheck + test. This is "probably safe" -- present as a diff for approval in interactive mode, apply silently in CI mode.
**Design token substitution (unambiguous mapping):**
1. When a hardcoded value has exactly one matching design token, replace the literal with the token reference.
2. Verify with typecheck + test.
3. If the mapping is ambiguous (multiple candidate tokens), surface to user.
**Never auto-fix these (always surface to user):**
- Upward dependencies
- Skip-layer dependencies
- Circular dependencies
- Forbidden imports without a configured alternative
### Phase 3.6: Convergence Loop (Standalone)
When running standalone (not through the orchestrator), apply a single-concern convergence loop:
1. **Re-run detection.** After applying all safe/probably-safe fixes, run `harness check-deps` again.
2. **Check if violation count decreased.** Compare the new count to the previous count.
3. **If decreased: loop.** Fixing one violation can resolve others (e.g., replacing a forbidden import may eliminate a transitive skip-layer violation). Go back to Phase 2 with the new results.
4. **If unchanged: stop.** Proceed to Phase 4 (Guide Resolution) for remaining violations.
5. **Maximum iterations: 5.** To prevent infinite loops.
**Verification gate:** After each fix batch, run:
```
pnpm lint && pnpm tsc --noEmit && pnpm test
```
If any command fails, revert the batch and reclassify those findings as unsafe.
### Phase 4: Guide Resolution
For each violation, provide a specific fix:
- **Upward dependency:** Introduce an interface or abstraction in the lower layer. The higher layer implements it; the lower layer depends only on the abstraction. Alternatively, use dependency injection.
- **Skip-layer dependency:** Route the call through the intermediate layer. Add a method to the Service layer that delegates to the Repository, then have the UI call the Service.
- **Circular dependency:** Break the cycle by extracting shared types into a common module that both can depend on, or restructure so the dependency flows in one direction only.
- **Forbidden import:** Check `harness.config.json` for an `alternative` field. If present, this should have been auto-fixed in Phase 3.5. If not present, replace the forbidden import with the approved alternative or restructure the code.
- **Design constraint violation:** Replace hardcoded values with token references from `design-system/tokens.json`. For anti-pattern violations, consult `design-system/DESIGN.md` for the project's aesthetic intent and approved alternatives. For contrast failures, use `harness-accessibility` to find compliant color pairs.
## Common Violation Patterns
### Pattern: "I just need one thing from that layer"
A UI component imports a repository function directly because "it is just one query." Fix: add the query to the Service layer. The extra indirection is the architecture working correctly.
### Pattern: "Shared types across layers"
Two layers both need the same type definition. Fix: place shared types in the lowest layer that both depend on, or create a dedicated `types` or `shared` module at the bottom of the layer stack.
### Pattern: "Test utilities importing production code from wrong layer"
Test helpers import across layer boundaries for convenience. Fix: each layer's tests should only import from that layer and below. Test utilities should follow the same constraints as production code.
### Pattern: "Hardcoded colors in components"
A component uses `#3b82f6` directly instead of referencing `color.primary` from the design token system. Fix: import and reference the token. In Tailwind: use the token-mapped utility class. In CSS: use the custom property `var(--color-primary)`.
### Pattern: "Circular dependency through re-exports"
Module A re-exports from Module B, and Module B imports from Module A. The circular dependency is hidden by the re-export. Fix: identify the true dependency direction and remove the reverse path.
## Harness Integration
- **`harness check-deps`** — Primary tool. Analyzes all imports against the layer model defined in `harness.config.json`. Returns structured violation data including file, line, source layer, target layer, and rule violated.
- **`harness check-deps --json`** — Machine-readable output for automated pipelines. Use this when parsing results programmatically.
- **`harness validate`** — Includes dependency checking as part of full project validation. Use when you want a complete health check, not just architecture.
- **`harness-design-system`** — Provides the design token source of truth (`tokens.json`) that constraints validate against.
- **`harness-accessibility`** — Provides WCAG contrast validation used by DESIGN-003 constraints.
- **Design constraint category** — Controlled by `design.strictness` in `harness.config.json`. Design violations surface alongside architectural violations in the same report.
- **`harness check-arch`** — Architecture assertion framework. Runs all 7 metric collectors against baseline and thresholds. Use for comprehensive structural health checks beyond layer dependencies. Supports `--update-baseline` to capture current state and `--json` for machine-readable output.
- **`harness check-arch --module <path>`** — Scoped architecture check for a single module. Use when validating a specific subsystem.
## Success Criteria
- `harness check-deps` reports zero violations
- All imports flow downward through the layer stack (or follow explicitly configured exceptions)
- No circular dependencies exist between modules or layers
- No forbidden imports are present anywhere in the codebase
- Every new module is assigned to the correct layer in the config
- The layer model in `harness.config.json` accurately reflects the intended architecture
## Examples
### Example: Service layer importing from UI layer
**Violation from `harness check-deps`:**
```
VIOLATION: Upward dependency
File: src/services/user-service.ts:12
Import: import { UserForm } from '../components/UserForm'
Source layer: service (level 2)
Target layer: ui (level 3)
Rule: service layer must not depend on ui layer
```
**Impact:** The UserService now depends on a React component. It cannot be used in a CLI tool, a background job, or tested without a DOM. The service layer should be framework-agnostic.
**Resolution:**
```typescript
// BEFORE (violating)
import { UserForm } from '../components/UserForm';
const data = UserForm.defaultValues; // using UI defaults in service
// AFTER (fixed)
// Define the defaults where they belong — in the service layer
const DEFAULT_USER_DATA: UserInput = { name: '', email: '' };
```
### Example: Circular dependency between modules
**Violation from `harness check-deps`:**
```
VIOLATION: Circular dependency detected
Cycle: src/services/order-service.ts -> src/services/inventory-service.ts -> src/services/order-service.ts
order-service imports checkStock from inventory-service
inventory-service imports getOrderQuantity from order-service
```
**Resolution:** Extract the shared concern into a new module:
```typescript
// src/services/stock-calculator.ts (new, shared module)
export function calculateRequiredStock(quantity: number, reserved: number): number {
return quantity - reserved;
}
```
Both services import from `stock-calculator` instead of from each other. The cycle is broken.
## Gates
These are hard stops. Architecture violations are not warnings — they are errors.
- **No code with layer violations may be approved or merged.** If `harness check-deps` reports violations, the code must be fixed before it proceeds.
- **No new modules without layer assignment.** Every new directory or package must be mapped to a layer in `harness.config.json` before code is written in it.
- **No "temporary" violations.** There is no TODO for architecture. Either the code respects the constraints or it does not ship.
- **No suppressing violations without team approval.** If a violation needs to be allowed, the constraint in `harness.config.json` must be explicitly updated with a comment explaining why.
## Evidence Requirements
When this skill makes claims about existing code, architecture, or behavior,
it MUST cite evidence using one of:
1. **File reference:** `file:line` format (e.g., `src/auth.ts:42`)
2. **Code pattern reference:** `file` with description (e.g., `src/utils/hash.ts` —
"existing bcrypt wrapper")
3. **Test/command output:** Inline or referenced output from a test run or CLI command
4. **Session evidence:** Write to the `evidence` session section via `manage_state`
**Uncited claims:** Technical assertions without citations MUST be prefixed with
`[UNVERIFIED]`. Example: `[UNVERIFIED] The auth middleware supports refresh tokens`.
## Red Flags
### Universal
These apply to ALL skills. If you catch yourself doing any of these, STOP.
- **"I believe the codebase does X"** — Stop. Read the code and cite a file:line
reference. Belief is not evidence.
- **"Let me recommend [pattern] for this"** without checking existing patterns — Stop.
Search the codebase first. The project may already have a convention.
- **"While we're here, we should also [unrelated improvement]"** — Stop. Flag the idea
but do not expand scope beyond the stated task.
### Domain-Specific
- **"Auto-fixing this import to use the correct layer"** without verifying the replacement module exists — Stop. Verify the target exists and exports the needed symbol before rewriting an import.
- **"This file is in a test directory, skipping violation"** — Stop. Test directories have architectural rules too. Check the constraint definition before assuming tests are exempt.
- **"Removing this circular dependency by moving the import"** without tracing downstream effects — Stop. Moving imports can break consumers. Trace the dependency chain first.
- **"This violation is from generated code, ignoring"** — Stop. Generated files can still violate architecture if the generator is misconfigured. Check the source template.
## Rationalizations to Reject
### Universal
These reasoning patterns sound plausible but lead to bad outcomes. Reject them.
- **"It's probably fine"** — "Probably" is not evidence. Verify before asserting.
- **"This is best practice"** — Best practice in what context? Cite the source and
confirm it applies to this codebase.
- **"We can fix it later"** — If it is worth flagging, it is worth documenting now
with a concrete follow-up plan.
### Domain-Specific
| Rationalization | Reality |
| ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
| "The violation is minor — just one import" | One violation sets a precedent. Enforce the constraint or document an explicit exception with rationale. |
| "It works, so the architecture must be fine" | Working code with bad architecture is technical debt with compound interest. Correct function does not excuse structural violations. |
| "This is a legacy module, different rules apply" | Legacy does not mean exempt. Either the constraint applies or it needs an explicit documented exception. |
## Escalation
- **When a violation seems impossible to fix within the current architecture:** The architecture may need to evolve. Escalate to the human with a clear explanation of the constraint, the use case, and why they conflict. Propose options: update the constraint, restructure the code, or add a new layer.
- **When `harness check-deps` reports false positives:** Verify the layer assignments in `harness.config.json` are correct. If a file is assigned to the wrong layer, fix the config. If the tool is genuinely wrong, report the issue.
- **When fixing one violation creates another:** This usually indicates a deeper structural issue. Step back and look at the dependency graph as a whole rather than fixing violations one at a time.
- **When the team wants to change the layer model:** This is a significant architectural decision. All existing code must be migrated to the new model. Plan this as a dedicated refactoring effort, not a side task.