CLAUDE.md example for a SaaS codebase
A real CLAUDE.md for a multi-module TypeScript SaaS: what to include, how it loads with AGENTS.md, and which rules belong in lint and hooks instead.
A CLAUDE.md file is the project briefing Claude Code reads at the start of every
session. Each session begins with an empty context window, so this file is how
knowledge about your codebase survives from one session to the next: how to run
it, how it is laid out, and what never to do.
Code for this guide: https://github.com/KonixDev/claude-code-guardrails — the open-source (MIT) claude-code-guardrails kit.
Most guides stop at "put your commands and conventions in it". This one is about
a specific kind of project — a multi-module TypeScript SaaS — and about the
part most CLAUDE.md files get wrong: they ask for things that should be
enforced.
Where CLAUDE.md lives and when it loads
- Project root (
./CLAUDE.mdor./.claude/CLAUDE.md): loaded at session start. Commit it; it is for the whole team. CLAUDE.local.md: your personal notes for this project. Keep it out of git.- Your user folder (
~/.claude/CLAUDE.md): your defaults for every project. - Subdirectories: a
CLAUDE.mdinsideapps/server/loads when Claude reads files there, not at launch. .claude/rules/: rule files that can be scoped to paths, so they load only when Claude works on matching files.- Imports: a line like
@AGENTS.mdpulls another file in. That organizes a long file; it does not make it cheaper — the docs are explicit that imported files load together with the file that imports them.
Anthropic's guidance is to keep each CLAUDE.md under about 200 lines: longer
files cost more context and get followed less. To shrink it, move what only
matters for one part of the repo into that folder's CLAUDE.md or a path-scoped
rule in .claude/rules/.
CLAUDE.md or AGENTS.md?
AGENTS.md is the tool-neutral version of the same idea: Cursor and Codex read
it, and recent Claude Code versions (2.1.277+) read it when there is no
CLAUDE.md in the project. If you use more than one agent, keep the rules in
AGENTS.md and make CLAUDE.md a thin wrapper:
@AGENTS.md
## Claude Code specifics
- Hooks in `.claude/hooks/` lint every edit and send you back once if you
try to finish while `npm run guardrails` fails. Treat their output as a
failing test.
- Use the `architecture-reviewer` subagent before reporting a non-trivial
change as done.One rule set, every agent reads it, and the Claude-only notes stay out of the other tools' way.
A CLAUDE.md for a multi-module SaaS
Here is a generalized version of the one in useDeploy (which is longer and
uses Bun): one folder per bounded context under src/modules/ (billing,
tenancy, identity…), each split into domain/, application/,
infrastructure/ and interfaces/.
# Project briefing
## Run it
- `npm run dev` — app on :3000, API on :3005
- `npm run guardrails` — lint + typecheck. Must pass before you say "done".
- `npm test` — unit tests. Add one for every behavior change.
## Layout
One folder per bounded context in `src/modules/<context>/`:
domain/ (entities, no I/O) → application/ (use cases, ports)
→ infrastructure/ (adapters) → interfaces/ (HTTP).
Dependencies point inward. See AGENTS.md for the full rules.
## Contracts
Request/response schemas live in `packages/contracts`. The UI imports them;
never re-declare a server field on the client.
## When you change an endpoint
Regenerate the API types (`npm run generate:api`) and commit them in the
same change. CI fails if they are stale.
## Don't
- Don't add a dependency without saying why.
- Don't edit generated files (`openapi.json`, `*.generated.ts`).
- Don't disable a lint rule to get green — fix the cause or ask.What makes it work:
- Commands first. The single most useful thing in the file is how to verify
a change. An agent that knows
npm run guardrailsexists will run it. - The layout in four lines. Enough for Claude to put new code in the right
folder; the detail lives in
AGENTS.md. - The traps, stated once. Generated files, stale API types, a client form that re-declares a server field. Each line is there because skipping it breaks something CI or users will notice.
- No style guide. Formatting belongs to Prettier and ESLint, not to prose the model has to remember.
What CLAUDE.md can't do
Anthropic's documentation is direct: Claude treats CLAUDE.md as context, not
as enforced configuration, and to block an action regardless of what Claude
decides it points you to a PreToolUse hook. (Why that matters for
architecture.) In
practice, move each rule that must never break into something that fails:
| Rule in prose | Where it should be enforced |
|---|---|
| "domain/ never imports a framework" | ESLint no-restricted-imports (the exact config) |
| "modules only talk through types" | @typescript-eslint/no-restricted-imports with allowTypeImports |
| "run the checks before you finish" | a Claude Code Stop hook that sends Claude back once if they fail |
| "fix lint errors as you go" | a PostToolUse hook that lints every edited file |
| "regenerate API types" | a CI job that diffs the generated files |
Keep the sentence in CLAUDE.md — it tells Claude why — and let the tooling
say no. The next guide shows the two hooks:
Claude Code hooks that enforce your architecture.
Get the files
Everything above — AGENTS.md, the CLAUDE.md wrapper, the ESLint boundary
config, both hooks, a review subagent and a Cursor rule — is open source and
copy-in: claude-code-guardrails on GitHub
(MIT). It ships with tests that run each rule against real violations.
FAQ
How long should a CLAUDE.md be?
Anthropic suggests under about 200 lines per file. Move folder-specific
sections into that folder's CLAUDE.md or a path-scoped .claude/rules/ file;
imports organize a file but don't reduce what gets loaded.
Does Claude Code read AGENTS.md?
Yes (2.1.277+), when the project has no CLAUDE.md. If you have both, import it from
CLAUDE.md with an @AGENTS.md line so Claude reads the same rules as Cursor
and Codex.
Should I put coding style in CLAUDE.md? Only what a formatter or linter can't check. Everything they can check is cheaper and more reliable as config.
Can Claude ignore my CLAUDE.md? It is context, not a constraint, so yes — especially deep into a long task. That is why the rules that must never break belong in lint, hooks and CI.
useDeploy is a TypeScript SaaS boilerplate that ships this setup — AGENTS.md,
the hooks and the ESLint boundaries — on top of auth, organizations and billing. If you'd rather start from a base where the
guardrails already pass, see what's included.