# Why CLAUDE.md Is Not Enough to Protect Your Architecture

> Source: <https://dev.to/errrt/why-claudemd-is-not-enough-to-protect-your-architecture-2bl5>
> Published: 2026-08-25 13:59:10+00:00

Files such as `CLAUDE.md`

and `AGENTS.md`

are useful for explaining a project to coding agents.

They can describe decisions like:

The problem is that these are still instructions, not enforcement.

An agent can understand a rule and still violate it during a large change. The generated code may compile and pass its tests while quietly introducing an architectural dependency that the project was supposed to avoid.

Humans do this too. The problem is not specifically AI-generated code. AI agents simply make it easier to produce larger changes faster, which makes architectural drift easier to miss.

I wanted the most important architecture decisions to behave more like lint rules.

That led me to build [ArchLint](https://github.com/errrt/archlint), a small open-source CLI that checks Git changes against architecture rules stored in the repository.

The basic flow is:

```
AI agent or developer changes code
                  ↓
               Git diff
                  ↓
               ArchLint
                  ↓
           PASS or BLOCKED
```

ArchLint does not need to know whether the change came from Claude Code, Codex, Cursor, or a human contributor. It evaluates the resulting Git diff.

A project can define its rules in `.archlint.yml`

:

```
version: 1

rules:
  - id: no-firebase
    type: forbidden_dependency
    packages:
      - firebase
    message: "Use Supabase Auth only."

  - id: db-boundary
    type: import_boundary
    from:
      - "src/components/**"
    deny:
      - "src/db/**"
    message: "UI components must not access the database directly."

  - id: protect-auth
    type: protected_path
    paths:
      - "src/auth/**"
    severity: warning
```

These rules express three different decisions:

The configuration lives beside the code, so it can be reviewed and versioned like any other architectural decision.

From the root of a Git repository:

```
npx archlint-ai init
npx archlint-ai check
```

The first command creates a starter configuration. The second checks staged, unstaged, and untracked changes.

No account, API key, dashboard, or global installation is required.

A successful check looks like this:

```
✓ 3 rules passed

NO ARCHITECTURE DRIFT DETECTED
```

When a rule is broken, ArchLint reports the rule, file, evidence, and message:

```
[no-firebase]

src/auth/firebase.ts:1

Use Supabase Auth only.

Evidence: firebase
Severity: ERROR
```

The same check can run in GitHub Actions:

```
name: ArchLint

on:
  pull_request:

jobs:
  archlint:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - run: npx archlint-ai check --base origin/${{ github.event.repository.default_branch }}
```

If a pull request introduces an error-level violation, the command exits with a non-zero status and the check fails.

At that point, the team has two choices:

`.archlint.yml`

because the architecture decision itself has intentionally changed.The second option is important. Architecture rules should not be permanent by accident. They should be explicit and reviewable.

ArchLint primarily checks additions in the current diff rather than scanning the entire repository.

This has two practical benefits:

It also keeps the tool focused on one question:

Did this change make the architecture worse?

An LLM could review a diff and decide whether it violates an architectural principle. That may become useful for rules that cannot be expressed structurally.

However, many important constraints do not require an LLM:

For these rules, deterministic checks are faster, cheaper, easier to understand, and produce repeatable results.

ArchLint v0.1 therefore focuses on deterministic rules. It defines an experimental provider-neutral interface for future semantic checks, but the current package does not send repository code to an LLM.

ArchLint is still an early release.

The current dependency and import checks focus on JavaScript and TypeScript syntax. Import-boundary rules are path-based, and the project does not yet attempt to understand every framework or programming language.

That is intentional. I wanted to start with a small tool that solves a clear problem before expanding the rule system.

The next rules should be driven by real projects rather than guesses.

ArchLint is not intended to replace `CLAUDE.md`

, `AGENTS.md`

, architecture decision records, or code review.

Those documents explain the reasoning and help agents make better choices.

ArchLint handles the smaller set of decisions that are important enough to enforce automatically.

A useful separation is:

```
Documentation explains the architecture.
ArchLint protects its critical boundaries.
Code review handles context and judgment.
```

The project is available on GitHub:

[https://github.com/errrt/archlint](https://github.com/errrt/archlint)

It can be tried with:

```
npx archlint-ai init
npx archlint-ai check
```

I would especially like feedback from developers using coding agents on real repositories:

**Which architecture rule would you want to enforce first?**
