Harness-engineering enforce-architecture
<!-- Generated by harness generate-slash-commands. Do not edit. -->
git clone https://github.com/Intense-Visions/harness-engineering
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/commands/codex/harness/enforce-architecture" ~/.claude/skills/intense-visions-harness-engineering-enforce-architecture && rm -rf "$T"
agents/commands/codex/harness/enforce-architecture/SKILL.mdEnforce 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
oron_pre_commit
triggers fireon_architecture_check - 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
- Read
to understand the project's architectural constraints. The config defines:harness.config.json- 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
- Layers — ordered list of architectural layers (e.g.,
- Design constraints — when
config exists, also load design constraint rules:design- 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
- 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:
— traversequery_graph
edges against layer constraint nodes to find all violations in a single queryimports
— find all code dependent on a violation target to show the full scope of impactget_relationships
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
- Run
to analyze all import statements against the constraint model. Capture the full JSON output.harness check-deps
1b. Optionally run
for comprehensive architecture analysis beyond dependency checking. This covers circular dependencies, complexity, coupling, module size, and dependency depth in addition to layer violations.harness check-arch
- 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:
-
Which layers are involved. Identify the source file's layer and the imported module's layer. Map them to the constraint model.
-
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
in config. These violations surface as DESIGN-xxx codes:design.strictness
[warn] — Hardcoded color/font/spacing instead of token referenceDESIGN-001
[warn] — Value matches a project anti-patternDESIGN-002
[error] — WCAG contrast ratio failure (error in strict mode)DESIGN-003
[info] — Missing platform binding for enabled platformDESIGN-004
-
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:
- Identify files where imports are not ordered according to the project's layer convention.
- Reorder imports: external packages first, then by layer (lowest to highest), then relative imports.
- Verify with lint + typecheck. This is a safe, mechanical fix.
Forbidden import replacement (with configured alternative):
- Check
forharness.config.json
entries that include anforbiddenImports
field.alternative - For each violation where an alternative exists, replace the import path with the alternative.
- 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):
- When a hardcoded value has exactly one matching design token, replace the literal with the token reference.
- Verify with typecheck + test.
- 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:
- Re-run detection. After applying all safe/probably-safe fixes, run
again.harness check-deps - Check if violation count decreased. Compare the new count to the previous count.
- 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.
- If unchanged: stop. Proceed to Phase 4 (Guide Resolution) for remaining violations.
- 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
for anharness.config.json
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.alternative - Design constraint violation: Replace hardcoded values with token references from
. For anti-pattern violations, consultdesign-system/tokens.json
for the project's aesthetic intent and approved alternatives. For contrast failures, usedesign-system/DESIGN.md
to find compliant color pairs.harness-accessibility
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
— Primary tool. Analyzes all imports against the layer model defined inharness check-deps
. Returns structured violation data including file, line, source layer, target layer, and rule violated.harness.config.json
— Machine-readable output for automated pipelines. Use this when parsing results programmatically.harness check-deps --json
— Includes dependency checking as part of full project validation. Use when you want a complete health check, not just architecture.harness validate
— Provides the design token source of truth (harness-design-system
) that constraints validate against.tokens.json
— Provides WCAG contrast validation used by DESIGN-003 constraints.harness-accessibility- Design constraint category — Controlled by
indesign.strictness
. Design violations surface alongside architectural violations in the same report.harness.config.json
— Architecture assertion framework. Runs all 7 metric collectors against baseline and thresholds. Use for comprehensive structural health checks beyond layer dependencies. Supportsharness check-arch
to capture current state and--update-baseline
for machine-readable output.--json
— Scoped architecture check for a single module. Use when validating a specific subsystem.harness check-arch --module <path>
Success Criteria
reports zero violationsharness check-deps- 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
accurately reflects the intended architectureharness.config.json
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:
// 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:
// 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
reports violations, the code must be fixed before it proceeds.harness check-deps - No new modules without layer assignment. Every new directory or package must be mapped to a layer in
before code is written in it.harness.config.json - 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
must be explicitly updated with a comment explaining why.harness.config.json
Evidence Requirements
When this skill makes claims about existing code, architecture, or behavior, it MUST cite evidence using one of:
- File reference:
format (e.g.,file:line
)src/auth.ts:42 - Code pattern reference:
with description (e.g.,file
— "existing bcrypt wrapper")src/utils/hash.ts - Test/command output: Inline or referenced output from a test run or CLI command
- Session evidence: Write to the
session section viaevidencemanage_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
| 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
reports false positives: Verify the layer assignments inharness check-deps
are correct. If a file is assigned to the wrong layer, fix the config. If the tool is genuinely wrong, report the issue.harness.config.json - 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.