← Back to Blog

Skills, Rules, Memory — Where Each One Actually Belongs (And Why Your CLAUDE.md Keeps Growing)

Skills, Rules, Memory — Where Each One Actually Belongs (And Why Your CLAUDE.md Keeps Growing)

Part of the Claude Code workflow series. Start with the install primer; then plan mode + CLAUDE.md + the slash commands that matter; then this post to split your growing CLAUDE.md into the four layers that compound instead of rot.

A CLAUDE.md that grew to 800 lines is the shape most projects reach around month three. You add a "please don't use any" rule. Then a "always run npm test before claiming done." Then a note about the one weird file the model keeps mis-reading. Then a list of the seven MCP servers attached. By the time you blink you've rebuilt a poorly-organized wiki inside one prompt header.

The fix is not a better CLAUDE.md. It's splitting the prompt surface into four layers — CLAUDE.md, rules, skills, memory — each smaller and more situational than the one before. Anthropic and Boris Cherny both describe this as progressive disclosure; the failure mode of one-big-file is what I'd call prompt hoarding.

The four layers, plain English

CLAUDE.md — always-true facts about the whole repo. Stack, purpose, deploy command, core conventions, anti-patterns. Every turn of every session sees this. Treat it like the brief a new teammate would read on Day 1.

Rules — file-scoped or directory-scoped constraints. "Files in src/auth/ must pass the security-review checklist before merge." "Any .sql change requires a migration note in the PR description." Applies only when Claude is working in that scope. Expensive to load globally; cheap when narrowly scoped.

Skills — repeatable, invokable procedures. Not prose — an actual parameterized recipe. "Generate a pre-deploy checklist for ." "Rebuild the tool-nav block and verify all 310 entries pass JSON-parse." Invoked with a slash command or referenced by other agents. Skills 2.0 (shipped 2026) made them programmable — inputs, outputs, composition with other skills.

Memory — learned facts that persist between sessions. "User prefers functional components over class-based." "The NextDNS profile ID is 5a7f2b." Memory sits outside CLAUDE.md because it's ambient — the model pulls it in when relevant, not on every turn.

Boundaries: always-true → CLAUDE.md. Scoped constraint → rule. Repeatable workflow → skill. Learned fact that should survive session death → memory.

A real example — splitting one rule out

Say your CLAUDE.md has grown to include this line:

- Any file in src/auth/ must maintain 100% test coverage on the happy path
  and must validate every input through zod. If adding a new auth endpoint,
  update docs/security.md with the threat model before shipping.

That rule is valuable. It's also scoped to src/auth/ and zero other sessions care about it. When Claude is editing src/components/Button.tsx, reading that rule is pure overhead. Worse, the longer CLAUDE.md gets, the less attention the model pays to any individual line — a prompt-engineering constant that hasn't changed since GPT-3.

Move it to .claude/rules/auth.md:

# src/auth rule

Applies to: src/auth/**

Every file in src/auth/:
- 100% test coverage on the happy path
- All inputs validated with zod before any logic runs
- New endpoints ship with a threat-model note in docs/security.md

Rationale: auth is the one place where a bug is a breach.

Now the rule fires only when Claude touches that path. Your CLAUDE.md drops one line. The precision of the rule goes up because it sits next to the code it governs.

Repeat this exercise for every scoped constraint and your CLAUDE.md shrinks by 30–50% without losing information.

When to promote a rule into a skill

Rules describe "here's what's true." Skills describe "here's what to do."

If you find yourself writing the same multi-step procedure in your CLAUDE.md — "to ship a new tool page, (1) add to registry, (2) run rebuild-nav, (3) inject watermark, (4) eleventy build, (5) manual-deploy via netlify" — that's not a rule. That's a skill.

Package it as .claude/skills/ship-new-tool.md:

# ship-new-tool

Ships a new tool page end-to-end. Invoke with /skill ship-new-tool <slug>.

Steps:
1. Add entry to src/_data/toolRegistry.json
2. Run `node scripts/rebuild-nav.mjs`
3. Run `node scripts/inject-watermarks.mjs`
4. Run `npx @11ty/eleventy`
5. Run `node deploy-site.mjs`

Accept arguments:
- slug: tool slug (required)
- group: audits | generators | utilities (default: audits)
- featured: boolean (default: false)

On failure in any step, stop and report which step failed with its exit code.

Now /skill ship-new-tool mega-privacy-analyzer does the whole chain. The CLAUDE.md entry that described the procedure is deleted.

When to move something into memory

Memory is the persistence layer for facts the model keeps relearning. If you've corrected Claude the same way three times, that's a memory entry.

Examples that belong in memory, not CLAUDE.md:

  • "User prefers TypeScript type over interface unless the shape needs extension."
  • "The production Netlify site ID is cda36d8e-2afb-442c-8bec-8e9383e0359c."
  • "User's standard git commit format is <tag>: <imperative summary> with optional body."

These are small, specific, and ambient. Putting them in CLAUDE.md forces every turn to re-read them. Putting them in memory means the model pulls them in when relevant — writing a commit message, naming a type, deploying — and ignores them the rest of the time.

Automatic Memory (2026) further blurs the line: the harness writes memories unprompted as it observes patterns. Review them weekly. Delete the ones that were wrong. Trust the rest.

Migration when your CLAUDE.md is already 800 lines

The one-shot cleanup that works:

Step 1 — print it out. Literally. Or open it full-screen. You need to read every line.

Step 2 — classify each line into one of four buckets. A sticky note per line: CLAUDE.md, rule, skill, memory, delete. Most lines fall into "rule" (scoped) or "delete" (stale / aspirational / one-time).

Step 3 — create the folder structure.

.claude/
├── rules/
│   ├── auth.md
│   ├── testing.md
│   ├── deployment.md
│   └── ...
├── skills/
│   ├── ship-new-tool.md
│   ├── rebuild-schema.md
│   └── ...
└── memory/ (managed by Claude, not you)

Step 4 — move the lines. Cut from CLAUDE.md, paste into the right file. Add a one-line rationale per rule. Add invocation syntax per skill.

Step 5 — shrink CLAUDE.md to ~100 lines. It now contains: project purpose, stack, commands, top-level code style, list of active rules + skills with their paths. Nothing scoped. Nothing one-time.

Step 6 — commit and test. Start a fresh session. Ask Claude to summarize the project. If the summary is coherent, your CLAUDE.md still works. If it's missing something, you cut too aggressively — put one thing back.

A 90-minute Saturday exercise saves 10× the time across the next six months of sessions.

Why files rot (and how to keep yours alive)

CLAUDE.md entropy comes from two sources:

  1. Nobody removes dead rules. The "always use function components" rule you added when you were on Svelte 3 is meaningless now that you migrated to Svelte 5. It still sits there, consuming attention.

  2. Aspirational rules. "We should always pair-program on security changes." That's not a rule, it's a wish. If the team isn't doing it, delete it — the model doesn't care about your aspirations; it'll just try to enforce them and confuse everyone.

A useful discipline: quarterly read-through. Every three months, open CLAUDE.md, read every line, delete anything that is no longer true or was aspirational. Takes 15 minutes. Prevents the slow slide to 800 lines.

Common mistakes

  • "I'll just add one more line to CLAUDE.md, this one is important." If you're about to add a scoped rule, put it in .claude/rules/. The threshold for new CLAUDE.md lines is "this is true for every file in the repo." Anything narrower goes elsewhere.
  • Skills that are really rules. If your "skill" is a one-paragraph description with no steps and no arguments, it's a rule. Move it.
  • Memory entries in CLAUDE.md. If the fact is about you (preferences, external IDs, past decisions) and would embarrass a teammate who read the file out of context, it belongs in memory, not CLAUDE.md.
  • No invocation syntax in skills. A skill without /skill <name> <args> documented at the top is a wiki page. Add the syntax.

Related reading

Fact-check notes and sources

Informational, not engineering consulting advice. Claude Code APIs and slash commands reflect the Q1 2026 surface. Verify against the official changelog before depending on any specific path or command in production. Mentions of Anthropic, Claude Code, third-party authors / publications are nominative fair use.

← Back to Blog

Accessibility Options

Text Size
High Contrast
Reduce Motion
Reading Guide
Link Highlighting
Accessibility Statement

J.A. Watte is committed to ensuring digital accessibility for people with disabilities. This site conforms to WCAG 2.1 and 2.2 Level AA guidelines.

Measures Taken

  • Semantic HTML with proper heading hierarchy
  • ARIA labels and roles for interactive components
  • Color contrast ratios meeting WCAG AA (4.5:1)
  • Full keyboard navigation support
  • Skip navigation link
  • Visible focus indicators (3:1 contrast)
  • 44px minimum touch/click targets
  • Dark/light theme with system preference detection
  • Responsive design for all devices
  • Reduced motion support (CSS + toggle)
  • Text size customization (14px–20px)
  • Print stylesheet

Feedback

Contact: jwatte.com/contact

Full Accessibility StatementPrivacy Policy

Last updated: April 2026