Skip to main content

First Project

This guide walks through setting up Anvil in an existing TypeScript project with intentional architecture boundaries.

Scenario

You have a project with this structure:

my-app/
├── src/
│ ├── api/ # HTTP handlers
│ ├── services/ # Business logic
│ ├── repositories/ # Data access
│ └── utils/ # Shared utilities
├── package.json
└── tsconfig.json

You want to enforce these boundaries:

  • api/ can import from services/ but not repositories/
  • services/ can import from repositories/ and utils/
  • repositories/ can only import from utils/
  • utils/ cannot import from other layers

Step 1: Install and Initialise

pnpm add -D @eddacraft/anvil-cli
anvil init

Step 2: Define Architecture Boundaries

Edit anvil.config.json to add boundary rules:

{
"version": "1.0",
"gates": {
"architecture": {
"enabled": true,
"boundaries": [
{
"name": "api-layer",
"pattern": "src/api/**",
"allow": ["src/services/**", "src/utils/**"],
"deny": ["src/repositories/**"]
},
{
"name": "service-layer",
"pattern": "src/services/**",
"allow": ["src/repositories/**", "src/utils/**"],
"deny": ["src/api/**"]
},
{
"name": "repository-layer",
"pattern": "src/repositories/**",
"allow": ["src/utils/**"],
"deny": ["src/api/**", "src/services/**"]
},
{
"name": "utils",
"pattern": "src/utils/**",
"allow": [],
"deny": ["src/api/**", "src/services/**", "src/repositories/**"]
}
]
},
"antiPatterns": {
"enabled": true,
"patterns": ["AP-001", "AP-003", "AP-004", "AP-006"]
}
}
}

Step 3: Run Initial Check

anvil run

You might see existing violations:

🔨 Anvil Run

Checking architecture...
✗ ARCH-001: Boundary violation
src/api/handlers/user.ts imports from src/repositories/user.repo.ts
Rule: api-layer denies imports from src/repositories/**

Checking anti-patterns...
⚠️ AP-003: Explicit 'any' type
src/services/parser.ts:42:10

1 error, 1 warning found.
Gate status: FAIL

Step 4: Fix Violations

For architecture violations, you have two options:

Option A: Fix the Code

Refactor to respect boundaries. In the example above, the API handler should call a service, not a repository directly:

// Before (violation)
import { UserRepo } from '../repositories/user.repo';

// After (correct)
import { UserService } from '../services/user.service';

Option B: Suppress with Explanation

If the violation is intentional, add a suppression:

// @anvil-ignore ARCH-001 Legacy pattern, will refactor in Q2
import { UserRepo } from '../repositories/user.repo';
Suppressions require explanations. @anvil-ignore without a reason

will itself trigger a warning. :::

Step 5: Start Watch Mode

Once clean (or suppressions added), start watch mode:

anvil watch

Now any new violations will surface immediately when you save.

Step 6: Add to CI

Add Anvil to your CI pipeline:

# .github/workflows/ci.yml
- name: Run Anvil
run: pnpm anvil run --ci

The --ci flag produces machine-readable output and sets appropriate exit codes.

What You've Achieved

  • Anvil validates architecture boundaries on every save
  • New boundary violations are caught before commit
  • Anti-patterns surface immediately
  • CI blocks PRs with violations

Next: Experience your first gate moment →