CLAUDE.md — [Project Name] Architectural Constitution

#

TIER: Project root

JOB: The architectural constitution for this project. Names the domain, the layers,

the entities, the error classes, and the dependency rules. Prevents the AI from

re-opening decisions that have already been made.

#

Usage: Place at project root as CLAUDE.md. Fill in every section with your domain.

Replace ALL placeholders in [brackets]. Commit before the first session begins.

This file is read alongside the workspace-level CLAUDE.md — do not repeat

cross-project standards here. Only what is specific to this project.


Project Identity

  • Name: [Project Name]
  • Domain: [One sentence describing what this system does and for whom]
  • Stack: [Language, framework, database, runtime]

Architecture

Layer Map

[API Layer (src/api/)]           ← Validates input. Returns responses. NO business logic.
[Service Layer (src/services/)]  ← Orchestrates rules. Depends on interfaces only.
[Domain (src/domain/)]           ← Pure data + behavior. NO I/O. NO framework imports.
[Repository Interfaces]          ← Contracts owned by the domain layer.
[Repository Implementations]     ← Data access. Implements interfaces. NO business rules.
[Config (src/config/)]           ← All env vars. Validated at startup.

Dependency Rules

  • [API layer] imports [service interfaces] only. Never repositories.
  • [Service layer] imports [repository interfaces] only. Never concrete classes.
  • [Domain] imports nothing. Not even language built-ins.
  • Concrete classes are wired in src/index.ts (composition root). Nowhere else.

Domain Model

Core Entities

[EntityName]
  - [field]: [type]    ← [what it represents]
  - [field]: [type]

[EntityName]
  - [field]: [type]

State Machine (if applicable)

[Status]: [STATE_A] → [STATE_B] → [STATE_C]
[STATE_A] → [STATE_CANCELLED] (condition: [when])
No other transitions are valid.

Error Hierarchy

[AppError] (base)
  ├── [EntityNotFoundError]    { [entityId], operation }
  ├── [InvalidStateError]      { from, to, [entityId] }
  └── [BusinessRuleViolation]  { rule, context }

Every error carries: the entity id, the operation name, a human-readable message.


Naming Conventions

  • Files: kebab-case.ts — [entity]-service.ts, [entity]-repository.ts
  • Interfaces: PascalCase — [Entity]Repository, [Entity]Service
  • Entities/types: PascalCase — [Entity], [ValueObject]
  • Functions: camelCase, verb-first — create[Entity], find[Entity]ById
  • Constants: UPPER_SNAKE_CASE — MAX_[THING], DEFAULT_[THING]

Architecture Decision Records

Document significant decisions in docs/adr/. Stubs:

  • ADR-001: Why [architecture choice]?
  • ADR-002: Why [technology choice]?

When the AI is about to make a significant architectural decision, it must create an ADR first. ADRs record what was decided and why. The AI reads them at session start and does not re-open closed decisions.


What This Constitution Protects

  • Layer boundaries — the AI never skips a layer or imports across boundaries.
  • State machine transitions — only allowed transitions are generated.
  • Error types — no bare throws, no string-based errors, no generic Error.
  • Naming conventions — consistent across every file in the project.
  • Composition root — dependencies are wired in one place.

If the AI proposes something that violates any of the above, reject it and reference this file.


Generative Specification methodology: https://doi.org/10.5281/zenodo.19637142