Seven files that make your AI remember your project, taken from a system that runs a real business unattended.
Get the seven filesIt makes the same mistake it made last month. You paste the same context you pasted yesterday. You catch yourself typing "I already told you that." The model is fine. What is missing is where it writes things down.
These are the seven files that fix it, in the order they matter, with the one most people skip.
Straight to the page. No drip sequence.
What you get
Most memory setups fail the same way: everything gets dumped into one file that loads every session, so context fills with things the model does not need. The split below is the part that makes it hold.
~/.claude/CLAUDE.md Who you are and how you work, loaded in every project. Most people put project details here and wonder why it bloats every session. This file should be short and almost never change.
# Global rules -> ~/.claude/CLAUDE.md
<!-- Loaded in EVERY project, every session. Keep it short.
If it only matters in one repo, it belongs in that repo's CLAUDE.md. -->
## Who I am
- [Your name], [what you do]. I work mainly in [languages/stack].
- Time zone [X]. When I say "prod" I mean [what that means for you].
## How I want you to work
- Do what was asked. Nothing more, nothing less.
- Read a file before editing it.
- Never create documentation files unless I ask.
- Never commit secrets, credentials, or .env files.
- If tests exist, run them after changing code.
- When you are unsure between two readings of my request, ask ONE question
rather than building both.
## How I want you to talk
- Lead with the answer. Put the reasoning after it.
- If something failed, say it failed and show the output. Do not soften it.
- No preamble. No summary of what you are about to do. Unlocks with the form above.
CLAUDE.md The rules for THIS codebase, including the ones you are tired of repeating. If you have said it twice in chat, it belongs here instead.
# Project rules -> CLAUDE.md (repo root)
<!-- Loaded every session IN THIS REPO. This is where the things you are tired
of repeating in chat go. Rule of thumb: said it twice? Put it here. -->
# [Project name]
[One paragraph: what this is, who uses it, what breaks if it goes down.]
## Architecture facts that are not obvious from the code
- [e.g. "The X service writes to Y, not Z, despite the name."]
- [e.g. "Anything under /legacy is frozen. Do not refactor it."]
## Commands
- Build: `[command]`
- Test: `[command]`
- Deploy: `[command]` <!-- name the ONE correct way, so it stops guessing -->
## Rules specific to this codebase
- [The rule you have repeated most in chat this month.]
- [The mistake it made that cost you time. State it as a rule.]
## Always persist what you learn
Whenever you research something non-obvious about this project (how a subsystem
works, where a thing lives, a deploy step, a gotcha, WHY something is the way it
is) write it down as a memory file immediately. Treat "I just looked this up" as
the trigger to save it. The goal: every lookup happens at most once. Unlocks with the form above.
MEMORY.md One line per fact, with a link. This is the file that actually loads every session. Getting this right is the whole trick: the index is always in context, the facts themselves are not.
# Memory index -> MEMORY.md
<!-- THIS is the file that loads every session. The facts themselves do NOT.
That split is the whole trick: the index stays cheap, the detail is
fetched only when relevant. One line per fact, with a hook after the dash
so the model can tell whether it needs to open it. -->
# Memory Index
- [Deploy runs from a script, not the CLI](deploy-is-a-script.md) - the obvious
command silently deploys the wrong config and still exits 0.
- [Why the cache layer exists](cache-rationale.md) - it looks redundant; it is
not. Removing it caused an outage.
- [TRAP: timestamps are two different formats](timestamp-trap.md) - comparing
them as strings gives wrong answers that look right.
- [Customer avatar](customer-avatar.md) - who actually reads what we write.
<!-- Keep lines scannable. The hook after the dash is what lets the model
decide to open the file. A line that just says "Deploy notes" tells it
nothing, so it either opens everything or opens nothing. --> Unlocks with the form above.
memory/*.md One fact per file, with frontmatter so it can be found. Not a journal, not a changelog. A fact you had to dig for once and never want to dig for again.
---
name: deploy-is-a-script
description: "Deploy runs from scripts/deploy.sh, never the raw CLI - the raw
command silently targets the wrong config and looks like it succeeded."
metadata:
type: project # user | feedback | project | reference
---
<!-- ONE fact per file. Not a journal. Not a changelog. A thing you had to dig
for once and never want to dig for again. -->
**The rule:** deploy with `./scripts/deploy.sh`. Never the raw CLI.
**Why:** the raw command defaults to the config in the working directory, which
is the staging config. It exits 0 and prints "deployed", so it looks like it
worked. It cost [X] to find that [what actually went wrong].
**How to verify it actually shipped:** [the concrete check - grep the running
box, hit the health endpoint, whatever PROVES it rather than implies it.]
Related: [[other-fact-name]]
<!-- Link liberally. A [[link]] to a file that does not exist yet is fine - it
marks something worth writing later, not an error. --> Unlocks with the form above.
.claude/skills/ The difference between "remember how to deploy" and being able to say "deploy" and have it happen the same way every time. Steps, not prose.
---
name: deploy
description: "Deploy to production and VERIFY it shipped. Use whenever
deploying, releasing, or pushing changes live."
---
<!-- A skill is a procedure, not prose. The test: could someone who has never
seen this project follow it exactly and get the right result? -->
# Deploy
## Before you start
- [ ] Tests pass locally
- [ ] You are not on the default branch (or you intend to be)
## Steps
1. Run `./scripts/deploy.sh`
2. Wait for the line `==> Deploy complete.` Anything else is a failure, even
if the exit code is 0.
3. Verify the change is actually on the box:
`[the concrete grep/curl that proves it]`
4. Check logs for new errors: `[command]`
## It is not done until
All three of: the completion line printed, the change greps on the box, and the
logs are clean. Two out of three is a failed deploy that looks fine.
## If it fails
- `[known failure 1]` -> `[fix]`
- `[known failure 2]` -> `[fix]` Unlocks with the form above.
.claude/settings.json Rules live in a file the model reads. Hooks live in the harness that runs regardless. Knowing which of your rules belongs in which is what separates a system that holds from one that drifts.
{
"//": "-> .claude/settings.json Hooks run in the HARNESS, not the model.",
"//2": "A rule in CLAUDE.md is something the model SHOULD do. A hook is",
"//3": "something that happens whether or not it decides to. Knowing which",
"//4": "of your rules needs which is what stops the drift.",
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATHS\" 2>/dev/null || true"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "echo \"session ended\" >> .claude/session.log"
}
]
}
]
},
"//5": "PreToolUse can BLOCK a call. PostToolUse reacts after it happened.",
"//6": "Stop fires when the assistant finishes a response.",
"//7": "Start with ONE hook. A wall of them is harder to debug than none."
} Unlocks with the form above.
the habit, not a file Telling it "make no mistakes" does nothing. Writing the correction into the file it reads next session is the entire mechanism. This is the one most people skip, and it is the one that compounds.
# The correction loop (the one most people skip)
<!-- Paste this into your project CLAUDE.md. It is not a file you create once.
It is the habit that makes the other six compound. -->
## Why "be more careful" does nothing
Telling a model "do not make mistakes" adds no information. It already intended
to be correct. The instruction changes nothing, because the failure was never a
lack of intent. It was a lack of the specific fact.
## The mechanism
When it gets something wrong, do not correct it in chat and move on. Write the
correction into the file it reads next session.
It broke -> you explain in chat -> fixed today, breaks again next week
It broke -> you write the fact -> never breaks again
That is the entire difference between an assistant that plateaus and one that
gets sharper every week.
## What to write
Not "do not do X". Write the fact that makes X obviously wrong:
WEAK: Do not use the raw deploy command.
STRONG: The raw deploy command targets the staging config and exits 0, so
it prints success while shipping nothing. Deploy runs from
./scripts/deploy.sh. Verify with [concrete check].
The second survives being read by someone with no memory of the incident, which
is exactly the reader you have. Every session.
## The trigger
Any time you catch yourself thinking "I already told you that" - that is not a
model failure. That is a missing file, and you just found out which one. Unlocks with the form above.
This is not a tutorial written to explain a tool. It is the memory system running a real acquisitions business, where the cost of the AI forgetting something is a lost deal rather than a lost afternoon.
Every rule in it exists because something broke first.
Seven files. Twenty minutes. It stops forgetting.