| name | claude-md-rules-creator |
| description | Authors and audits CLAUDE.md, CLAUDE.local.md, and `.claude/rules/*.md`, covering the four scopes (managed, user-global, project-team, project-personal), `paths:` for path-scoped rules, `@path` imports, splitting an oversized file, and debugging instructions the model ignores. Use when standing instructions are being written or fixed. Triggers on "add to CLAUDE.md", "write a rule", "init memory", "global instructions", "team conventions", "project memory", "rules file", or a complaint that Claude is not following CLAUDE.md. Pair with `ac:prompt-writer` for the prose and `ac:skill-creator` when the content is really a skill. |
| when_to_use | Authoring, editing, or auditing any CLAUDE.md, CLAUDE.local.md, or `.claude/rules/*.md` file. |
CLAUDE.md and Rules Creator
You are about to write or edit a CLAUDE.md, CLAUDE.local.md, or .claude/rules/*.md file. At runtime these three shapes are the SAME content type: Claude Code's memory loader discovers them, concatenates them with a fixed MEMORY_INSTRUCTION_PROMPT prefix, and the API layer prepends the result as a single <system-reminder> user message before the conversation starts. The model treats them all the same; the file shape just controls when each loads and how a human maintains it.
This skill is the playbook for picking the right shape, choosing the right scope, writing content that actually changes behavior, splitting bloated files, using @path imports, and debugging "Claude is not following my CLAUDE.md". Target is Opus 5. Same rules work for Sonnet 5 at lower cost and for Haiku 4.5, which supports no effort parameter.
Three jobs, not one
Writing a CLAUDE.md or rule splits into three tasks. Conflating them is the most common authoring mistake.
- Surrounding skill shape. None. CLAUDE.md and
.claude/rules/*.md are not skills, not commands, not agents. They are plain markdown files the memory loader picks up. No frontmatter fields apply except paths: (only on .claude/rules/*.md). Route through ac:skill-creator ONLY if you are wrapping CLAUDE.md authoring inside a custom slash command or skill.
- CLAUDE.md / rule shape. Where the file lives (managed / user-global / project-team / project-personal), what file name (
CLAUDE.md / CLAUDE.local.md / .claude/rules/<topic>.md), paths: frontmatter for rules, @path imports, HTML comments. This file teaches that.
- Body content. The markdown text the model reads. This is a standing instruction set, a prompt at runtime. Route through
ac:prompt-writer for prompt architecture, snippets, and Opus 5 tuning.
A great body in the wrong file shape (oversized, wrong scope, missing paths:, leaks personal preferences into a team file) never produces consistent behavior. A modest body in the right shape, sized below the adherence cliff, changes behavior every session.
What CLAUDE.md actually is, mechanically
The lifecycle:
- Discovery. At session start, the loader walks: managed → user → project (root → cwd) → local → AutoMem/TeamMem. Within each project directory:
CLAUDE.md first, then .claude/CLAUDE.md, then .claude/rules/*.md (unconditional only - files without paths: or with paths: ['**']), then CLAUDE.local.md.
- Frontmatter strip + HTML comment strip. Each file's content is processed: YAML frontmatter is parsed (only
paths: is meaningful), and block-level HTML comments (<!-- ... -->) are stripped. Comments inside fenced code blocks survive. Inline HTML comments inside paragraphs survive.
- Conditional rule deferral.
.claude/rules/*.md files WITH a paths: frontmatter are held back from the initial concatenation. They activate later when Claude reads a file matching their glob.
- Concatenation. Eligible files are formatted as
Contents of <absolute-path><description>:\n\n<content> (description varies by type - "user's private global instructions for all projects", "project instructions, checked into the codebase", "user's private project instructions, not checked in", "user's auto-memory, persists across conversations"). All entries are joined with \n\n, prefixed with MEMORY_INSTRUCTION_PROMPT.
- Injection into the API call. The concatenated string becomes the
claudeMd field of the user context. The runtime wraps it together with currentDate inside a <system-reminder> block and prepends it as the first user message of the API call, with isMeta: true (the UI hides it; the model sees it). The trailing line softens the authority: "this context may or may not be relevant to your tasks. You should not respond to this context unless it is highly relevant to your task."
- Compact behavior. On
/compact or auto-compact, the runtime wipes the memory-file cache. The NEXT turn re-reads project-root CLAUDE.md, CLAUDE.local.md, and unconditional rules from disk and re-injects them. Path-scoped rules and nested-subdir CLAUDE.md files lazy-loaded into message history during the session are summarized away and reload only on the next matching file touch.
The model NEVER sees CLAUDE.md as the system prompt. It sees a <system-reminder>-wrapped meta-message that says "you can use the following context". This is the single most-misunderstood mechanic; debugging "Claude is not following my CLAUDE.md" always starts here.
Decision flow
Route by the user's request.
Is CLAUDE.md / rules the right tool at all?
├── Single fact never changes; behavior must hold every session → CLAUDE.md, continue.
├── Workflow with steps, invocable on demand → SKILL, route through `ac:skill-creator`.
├── User-typed `/name [args]` action → COMMAND, route through `ac:command-creator`.
├── Deterministic guarantee (must fire on every edit, no model judgment) → HOOK, configure in settings.json.
├── Custom-context worker → SUBAGENT, route through `ac:agent-creator`.
└── Standing rule, conventions, what-to-avoid, project facts → CLAUDE.md / rule, continue.
Which file shape inside the CLAUDE.md layer?
├── Universal rule, every session needs it, file stays under 200 lines → inline in `./CLAUDE.md` (project) or `~/.claude/CLAUDE.md` (user).
├── Personal override of a team rule → `./CLAUDE.local.md` (project-personal, gitignored).
├── Topic-focused team rule, want its own file → `./.claude/rules/<topic>.md` (no `paths:`, loads at session start).
├── Path-conditional rule (only matters in `src/api/`, only frontend, only migrations) → `./.claude/rules/<topic>.md` with `paths:` frontmatter.
├── Personal preference across all projects → `~/.claude/CLAUDE.md` or `~/.claude/rules/<topic>.md`.
└── Org-wide policy → managed CLAUDE.md (admin deploys).
Is this an audit or fix of an existing file?
├── YES → read `${CLAUDE_SKILL_DIR}/references/anti-patterns.md` first, then the specific reference as the symptom dictates.
└── NO → walk the Workflow below.
Frontmatter: only one shape takes any
CLAUDE.md and CLAUDE.local.md have NO frontmatter. They are pure markdown. Anything that looks like YAML at the top is treated as content.
.claude/rules/<topic>.md files accept ONE frontmatter field: paths:.
| Field | Required? | Behavior |
|---|
paths: | optional | Comma string or YAML list of gitignore-syntax globs. Without it, the rule loads at session start with the same priority as .claude/CLAUDE.md. With it, the rule loads on demand when Claude reads a file matching any glob. paths: ['**'] is treated identically to no paths: |
Everything else (name, description, model, effort, etc.) is ignored by the memory loader. Do not add fields that mean nothing in this context.
Escape convention used in this documentation. This SKILL.md is itself a skill body inside a plugin. The Claude Code loader substitutes plugin-context tokens before injecting the body. Real path references in this file using ${CLAUDE_SKILL_DIR}/references/<file>.md stay literal so the loader resolves them to actual files the model can Read. Documentation-context references that NAME the tokens without using them use the HTML entity $ so the docs survive intact. In CLAUDE.md and rule files you author, none of this applies, those files do not go through any substitution pass; tokens stay literal.
Where each file lives (verified paths)
| Type | Path |
|---|
| Managed CLAUDE.md | macOS: /Library/Application Support/ClaudeCode/CLAUDE.md; Linux/WSL: /etc/claude-code/CLAUDE.md; Windows: C:\Program Files\ClaudeCode\CLAUDE.md |
| Managed rules dir | <managed-policy-path>/.claude/rules/ |
| User CLAUDE.md | ~/.claude/CLAUDE.md |
| User rules dir | ~/.claude/rules/ - not ~/.claude/.claude/rules/ |
| Project CLAUDE.md | <dir>/CLAUDE.md AND <dir>/.claude/CLAUDE.md (both loaded per directory in the walk) |
| Project rules dir | <dir>/.claude/rules/ (per directory in the walk; recursive into subdirs) |
| Local CLAUDE.local.md | <dir>/CLAUDE.local.md (per directory in the walk; gitignored by convention) |
| Auto memory entrypoint | ~/.claude/projects/<project>/memory/MEMORY.md (200 lines / 25KB cap) |
The asymmetry to remember: USER rules live one level shallower than PROJECT rules. User: ~/.claude/rules/<topic>.md. Project: <dir>/.claude/rules/<topic>.md.
The four scopes
The runtime treats CLAUDE.md content identically regardless of scope. The scopes differ in WHO sees the file and WHEN it gets loaded.
| Scope | Path | Audience | Where it lives | Loaded |
|---|
| Managed policy | platform-specific path above | Every user on the machine; cannot be excluded by user settings | Org-deployed via MDM, Group Policy, Ansible | Always |
| User global | ~/.claude/CLAUDE.md, ~/.claude/rules/*.md | Just you, every project on this machine | Your dotfiles (personal); not in any repo | Always |
| Project team | ./CLAUDE.md, ./.claude/CLAUDE.md, ./.claude/rules/*.md | Everyone working on this repo | Committed to source control | Always (walked from filesystem root down to cwd) |
| Project personal | ./CLAUDE.local.md | Just you, just this project | Add to .gitignore; never committed | Always |
The litmus test: if the team gets value from this rule, it is project-team. If it is yours alone, it is user-global (cross-project) or project-personal (this project only). Org-wide compliance and security rules go to managed policy.
Full scope deep-dive, AGENTS.md interop, worktree handling, monorepo claudeMdExcludes, and --add-dir behavior: ${CLAUDE_SKILL_DIR}/references/scopes.md.
Core principles
These nine rules drive every authoring decision. Detail and source in the references.
- Concise wins adherence. Anthropic's docs target "under 200 lines per CLAUDE.md". Adherence drops as files grow; over 200 lines the model notices less of what is there. The hard cap is 40,000 characters per file (
MAX_MEMORY_CHARACTER_COUNT in the loader).
- Specificity beats vagueness. "Use 2-space indentation in TypeScript" beats "format code properly". "Run
pnpm test before committing" beats "test your changes". "API handlers live in src/api/handlers/" beats "keep files organized". The instruction must be concrete enough for the model to verify and apply.
- The "would removing this cause Claude to make mistakes?" test. Apply to every line. If the answer is no, cut it. CLAUDE.md is paid by the token on every request in the project; lines that do not change behavior are pure tax.
- No aspirations. "We aim for 90% test coverage" is not a rule the agent can enforce, and trying to satisfy aspiration produces irrelevant work. Write what is actually true and enforced. If it is true in CI, say what runs in CI.
- Standing instructions, not conversation echoes. CLAUDE.md is read once at session start (and re-injected after compact for project root). It must read sensibly cold. Avoid "as we discussed", "for this turn", "remember from last time".
- Match the scope to the audience. Project-team CLAUDE.md is shared via git; write what the team agrees on. User-global is yours alone. Project-personal CLAUDE.local.md is your private fixture for this repo. Rules leaking into the wrong scope is the most common source of friction.
- Point at sources of truth; do not duplicate them. A one-line
@docs/architecture.md import beats a ten-line summary that drifts. Use @path imports for content that lives elsewhere. Never inline answers that change faster than the file.
- No aggressive caps. "CRITICAL", "you MUST", "ALWAYS" wording produces compliance brittleness on modern Claude. The runtime already prepends
MEMORY_INSTRUCTION_PROMPT which contains an explicit "IMPORTANT: These instructions OVERRIDE any default behavior and you MUST follow them exactly as written." Your file does not need to repeat that authority; state the rule plainly.
- Audit the existing layered context before writing. Your new content does not land alone. It joins a stack: CC's built-in system prompt + managed CLAUDE.md + user-global + project + local + auto memory + path-scoped rules. Adding a rule that the CC system prompt already provides ("be concise", "no comments unless non-obvious", "reference code as file:line") or that another layer already covers is pure tax. Adding a rule that contradicts a higher-precedence layer creates a silent conflict. Before writing, run
/memory to see what is already loaded, Grep the loaded files for the topic, and decide one of three actions: skip (already covered), edit in place (existing file is wrong/outdated), or move to the right scope. See ${CLAUDE_SKILL_DIR}/references/layered-context.md for the audit protocol and the "do not restate" cheat sheet covering ~12 CC built-in defaults.
Choosing the file shape inside the CLAUDE.md layer
A 400-line CLAUDE.md and four 100-line .claude/rules/<topic>.md files (all loaded unconditionally, no paths:) have identical token cost and identical model behavior. Splitting is for human maintainability, plus the option to add paths: to scope a rule to part of the codebase.
| Pick | When | Loaded |
|---|
./CLAUDE.md (root) or ./.claude/CLAUDE.md | Universal rules every session needs; file under 200 lines | Always at session start |
./CLAUDE.local.md | Personal overrides of team rules; gitignored | Always at session start |
./.claude/rules/<topic>.md without paths: | Topic-scoped rule (testing, security, api) the team wants in its own focused file | Always at session start, same priority as .claude/CLAUDE.md |
./.claude/rules/<topic>.md with paths: | Path-conditional rule (only src/api/**, only **/*.tsx, only migrations) | On demand when Claude reads a matching file; loads into message history (summarized away by compact) |
~/.claude/CLAUDE.md | Personal preferences across all your projects | Always at session start |
~/.claude/rules/<topic>.md | Personal preferences split by topic | Always at session start; loads BEFORE project rules so project rules win on conflict |
Two caveats worth front-loading:
- Path-scoped rules and nested CLAUDE.md files do NOT survive compaction the same way. They are injected into message history when triggered (not into the user-context message), so compact summarizes them away. They reload only when Claude next reads a matching file. If a rule MUST hold across compact, drop
paths: or move it to project-root CLAUDE.md.
- Subdirectory CLAUDE.md (e.g.,
packages/web/CLAUDE.md when cwd is the monorepo root) loads on demand the same way. Useful for monorepo per-package rules without bloating root context.
Full splitting strategy, topic-file naming conventions, and paths: glob design: ${CLAUDE_SKILL_DIR}/references/rules-writing.md.
Five questions every project CLAUDE.md should answer
A pragmatic frame:
- What is the stack? One paragraph: language, framework, runtime, package manager.
- Where does code live? Top-level directories with one-line meanings - only when non-obvious.
- How do I run things? Dev server, tests, lint, type-check, build, deploy. Exact strings.
- What are the conventions? Style rules that differ from defaults, naming patterns, architectural rules.
- What is off-limits? "Do not edit
migrations/", "never push directly to main", "do not run npm install (use pnpm)".
If your CLAUDE.md does not answer these five, add the missing ones. If it answers more than five, audit whether the extras pull weight. Full INCLUDE/EXCLUDE coverage with examples: ${CLAUDE_SKILL_DIR}/references/content-rules.md.
@path imports
The loader recognizes a @path syntax for splitting content across files (four hops of importing):
- Syntax:
@path, @./relative, @~/home, @/absolute. The regex requires whitespace or start-of-line before the @.
- Imports recurse up to four hops. The loader's
MAX_INCLUDE_DEPTH = 5 (utils/claudemd.ts:537) is an exclusive bound on a zero-indexed depth (:630, depth >= MAX_INCLUDE_DEPTH), so levels 0 through 4 are processed and four levels of importing land; the docs state the same as "a maximum depth of four hops". Cycles are detected and broken via path tracking.
- Only text-file extensions (~70 are listed) -
.md, .txt, .json, .ts, .py, etc. Binary files (images, PDFs) are silently skipped.
- Imports inside fenced code blocks and codespans are NOT followed (the marked lexer respects token boundaries).
- Imports inside block-level HTML comments are NOT followed (comments are stripped before lex).
- Fragment identifiers (
@path#heading) are stripped before resolution.
- External imports (paths outside cwd) trigger a one-time approval dialog the first time the runtime sees them, except in User memory which always permits externals.
Use imports to point at sources of truth (@docs/architecture.md, @AGENTS.md, @README.md), share personal content across worktrees (@~/.claude/<project>-instructions.md), and avoid duplicating long content. Imports help organization - they do NOT reduce context cost; imported content lands in context the same as inlined content.