---
title: "A CLAUDE.md for Modern Angular: Memory, Not Just Rules"
description: "How Claude Code's memory system works for an Angular codebase: where CLAUDE.md lives, why you import AGENTS.md instead of duplicating it, and how path-scoped rules keep component, state, and testing guidance out of one file that quietly goes stale."
deck: "Claude Code does not read your `AGENTS.md`. It reads [`CLAUDE.md`](https://code.claude.com/docs/en/memory), and it loads that file into every session automatically. [`ng generate ai-config --tool claude`](https://angular.dev/cli/generate/ai-config) writes one to `.claude/CLAUDE.md`, a path Claude Code already treats as project memory. The win for an Angular repo is not a longer rules file. It is structure: a hierarchy, imports, and path-scoped rules that line up with how the workspace is already organized."
author: "André Ramos"
url: "https://andreramos.dev/angular/claude-md-for-modern-angular/"
lang: "en"
type: "article"
---

# A CLAUDE.md for Modern Angular: Memory, Not Just Rules

> Claude Code does not read your `AGENTS.md`. It reads [`CLAUDE.md`](https://code.claude.com/docs/en/memory), and it loads that file into every session automatically. [`ng generate ai-config --tool claude`](https://angular.dev/cli/generate/ai-config) writes one to `.claude/CLAUDE.md`, a path Claude Code already treats as project memory. The win for an Angular repo is not a longer rules file. It is structure: a hierarchy, imports, and path-scoped rules that line up with how the workspace is already organized.

## AGENTS.md is the what, CLAUDE.md is how Claude Code loads it

If you already wrote an `AGENTS.md` for your Angular repo, there is a detail that catches teams out: Claude Code does not read it. It reads `CLAUDE.md`, and it reads it on its own. At the start of a session it walks up the directory tree and loads every `CLAUDE.md` it finds, so the file is already in context before you type anything. An `AGENTS.md` sitting next to it is ignored unless you pull it in on purpose.

There are two project-level spots Claude Code accepts: `./CLAUDE.md` at the repo root, or `./.claude/CLAUDE.md` inside the `.claude/` folder. They count the same. That second path is the one that matters for Angular, because `ng generate ai-config --tool claude` writes exactly there. The file the CLI scaffolds is already a memory file Claude Code will load, so you do not have to move it.

The constraints that go inside, the version pin, the Signals and RxJS boundary, the template rules, are the same ones I worked through for [an AGENTS.md](/angular/agents-md-for-modern-angular). That guide is the what. This one is about how Claude Code loads and organizes them, which is where the leverage is.

| File | When it loads | What it is for |
|---|---|---|
| ~/.claude/CLAUDE.md | Every session, every project | Your personal defaults, not the team's |
| .claude/CLAUDE.md or ./CLAUDE.md | At session start, top of the tree | The Angular rules the whole team shares |
| CLAUDE.local.md | At session start, after CLAUDE.md | Your machine-only notes, gitignored |
| src/app/feature/CLAUDE.md | On demand, when Claude opens files there | Rules for one feature or library |

## Import AGENTS.md, do not copy it into CLAUDE.md

The wrong way to keep both files is to paste the Angular rules into each. Now you have two copies that drift, and `ng generate ai-config` will happily regenerate one of them out from under you. Claude Code has an import for this. A line that starts with `@` pulls another file into `CLAUDE.md` when it loads, so one source of truth feeds both tools.

I keep the Angular constraints in `AGENTS.md`, the file the CLI maintains, and let `CLAUDE.md` import it and add only the Claude-specific part: when to use plan mode, which directories are off-limits, how this team runs tests. Imports resolve relative to the file and go up to four levels deep, which is more than enough for one `@AGENTS.md`.

*A CLAUDE.md that imports AGENTS.md and adds the Claude-specific part*

```text
# CLAUDE.md

@AGENTS.md

## Working in this repo
- Ask before adding a dependency; this repo stays lean.
- Use plan mode before touching anything under src/app/**/state/.
- Run tests with `npm test` (Vitest). Do not bring Karma back.
- Never edit files under src/generated/.
```

## Path-scoped rules line up with an Angular workspace

A single rules file tries to cover components, state, and tests at once, and the agent reads all of it whether it is writing a pipe or a spec. Claude Code can scope rules to paths instead. A file in `.claude/rules/` with a `paths` glob in its frontmatter loads only when Claude opens a file that matches. An Angular workspace already has those boundaries: specs, components, state.

This is where the testing rules earn their own file. The advice that matters in a `.spec.ts`, use Vitest, the `fakeAsync` helpers need the zone patch, do not call `detectChanges` after every change, is noise in a file about components. It is also [a decision in its own right](/angular/move-angular-test-suite-to-vitest). Scope those rules to the specs and they show up exactly when the agent is writing one.

*.claude/rules/testing.md, scoped to spec files*

```text
---
paths:
  - "src/app/**/*.spec.ts"
---

# Testing rules

Use Vitest. Do not reintroduce Karma or Jasmine.
fakeAsync, tick, and flush only work with the zone.js vitest-patch enabled.
Prefer fake timers or native async over fakeAsync in new specs.
Do not call detectChanges after every mutation; it hides missing notifications.
```

## Keep the root file short; let the tree carry the rest

Memory is not free. Everything in `CLAUDE.md` and everything it imports sits in context for the whole session, and a bloated file does not just cost tokens, it gets followed less reliably. The guidance is to keep a `CLAUDE.md` under about two hundred lines and push detail outward: imports for the shared rules, path-scoped files for the parts that only matter sometimes.

An Angular monorepo gives you the other axis for free. A `CLAUDE.md` inside a feature library loads only when Claude is working in that library, so per-app and per-lib rules do not weigh on every session. `/init` drafts a starter file from your codebase, and `/memory` lists what is actually loaded right now, which is the fastest way to catch a file you forgot was there.

| Rule | Where it goes | Why |
|---|---|---|
| Version pin, Signals/RxJS boundary, template syntax | AGENTS.md, imported into CLAUDE.md | One source the CLI keeps current |
| Plan mode, off-limits dirs, how to run tests | CLAUDE.md root | Claude-specific, always true |
| Vitest and fakeAsync rules | .claude/rules/testing.md, scoped to *.spec.ts | Loads only when writing a spec |
| State and store conventions | .claude/rules/state.md, scoped to the state dir | Loads only in state code |
| One library's quirks | lib/CLAUDE.md | Lazy-loaded when working in that library |

## A stale CLAUDE.md misleads on every session

Every file here has the same failure mode as a hand-written rules file, with one twist: because `CLAUDE.md` loads on every session, a stale line is not a document someone might read wrong. It is an instruction the agent follows on every task, quietly, until someone notices the generated code is a version behind.

So the maintenance rule is the one I tie to `AGENTS.md`: when the team bumps an Angular major, the memory files get the same review as the dependencies. The version pin, the experimental-API list, the testing notes, all of it. A `CLAUDE.md` that still calls Signal Forms experimental will steer an agent away from an API that went stable in v22, with full confidence, on every run.

## Reusable artifact: A CLAUDE.md setup for an Angular repo

- Memory file at .claude/CLAUDE.md or ./CLAUDE.md (both load); the ai-config CLI writes the first.
- AGENTS.md imported with @AGENTS.md, not copied, so the CLI-maintained rules stay the single source.
- Testing rules scoped to *.spec.ts in .claude/rules/, so Vitest and fakeAsync notes load only on specs.
- State and component rules path-scoped the same way; the root file holds only what is always true.
- Root CLAUDE.md under about 200 lines; a per-library CLAUDE.md for monorepo features.
- A review trigger tied to Angular majors, so the version pin and experimental-API list never go stale.

## Sources checked

- https://code.claude.com/docs/en/memory
- https://code.claude.com/docs/en/claude-directory
- https://angular.dev/cli/generate/ai-config
- https://angular.dev/ai/develop-with-ai
- https://angular.dev/ai
- https://angular.dev/ai/mcp
- https://angular.dev/guide/testing
- https://angular.dev/style-guide
- https://blog.angular.dev/announcing-angular-v21-57946c34f14b

## Related

- [An AGENTS.md That Makes AI Write Modern Angular](https://andreramos.dev/angular/agents-md-for-modern-angular/)
- [Angular CLI MCP and AI-Generated Angular Code](https://andreramos.dev/angular/angular-cli-mcp-ai-generated-angular-code/)
- [WebMCP in Angular: How to Expose Tools to the Browser's AI Agent (and When to Wait)](https://andreramos.dev/angular/web-mcp-in-angular/)
