architecture

Persistent Memory: Claude That Remembers

Memory tiers in Claude Code. CLAUDE.md, /memory directories, auto-memory hooks. How to make Claude remember without overflowing context.

10 min read·

The Problem

Cold Start Every Session

Every Claude session starts empty. No memory of what worked last week. No client context. No learned patterns. Session 100 is no smarter than session 1.

The cost of forgetting

  • 10-15 minutes re-explaining context at the start of every session
  • Repeated mistakes that were already solved and documented
  • No compound improvement: each session resets to zero

Without memory

Session 1→ forget →Session 2→ forget →Session 3

With persistent memory

Session 1→ learns →Session 2+→ learns →Smarter

Architecture

4 Memory Tiers

Persistent memory is not a single file. It is a layered system: each tier has a different speed, scope, and lifespan.

Vector Memory

Semantic similarity search across all stored knowledge. Finds concepts related to a topic, not just exact keyword matches.

Example: "What have we learned about Slack integrations?" returns every relevant session even if the word Slack never appeared.

Episodic Memory

Event sequences with temporal context. Remembers when things happened and in what order.

Example: "What happened during client onboarding week 1?" returns the full sequence of events in order.

Semantic Memory

Knowledge graphs of concepts and relationships. Builds a network: Client → Engineer → Tech Stack → Known Blockers.

Example: "Which engineer is best at n8n?" Graph traversal connects profiles to outcomes to technology tags.

Working Memory

Active context via attention mechanisms. Fast access to what is most relevant right now, like RAM vs. storage.

Example: During a session, working memory holds: client name, current project, recent blockers, last communication.

+---------------------------------------+ | Memory System Overview | +---------+------------+----------------+ | Vector | Episodic | Semantic | | Memory | Memory | Memory | |(similar)|(sequences) | (graphs) | +---------+------------+----------------+ | Working Memory (active RAM) | | Current session context | +---------------------------------------+ ^ writes v reads Claude Code Sessions

Foundation

CLAUDE.md Best Practices

CLAUDE.md is the simplest form of persistent memory. It is injected at the top of every context window, the one thing Claude always reads before anything else.

Keep it under 200 lines

Claude reads CLAUDE.md in full on every session. Long files waste context tokens and bury important instructions. Prune aggressively. If a rule is not enforced in 90% of sessions, remove it.

Use sections with clear headers

Organise by: Stack, Commands, Conventions, Architecture, DO NOT. Clear headers help Claude retrieve the right section quickly when it performs in-context search.

Put blocking rules in the DO NOT section

List hard constraints explicitly. "DO NOT use npm or yarn" is clearer than burying it in the stack section. Negatives get top-of-mind attention.

Reference, don't repeat

Use @filename.md to pull in project-specific files. Keep CLAUDE.md as the index, not the encyclopedia. Put the details in the referenced files.

Review and prune every 30 sessions

Rules decay. A constraint that was critical in month 1 may be solved by tooling in month 3. Dead rules add noise and reduce the signal-to-noise ratio for the model.

# CLAUDE.md - minimal structure

## Stack
- Next.js 15, TypeScript strict, Tailwind v4
- pnpm only

## Commands
- pnpm dev / pnpm build / pnpm test

## Conventions
- Server Components by default
- cn() from lib/utils.ts

## DO NOT
- Use npm or yarn
- Add `any` types
- Access DB from client components

File System

/memory/ Directory Structure

A /memory/ directory in your project root extends CLAUDE.md into a multi-file memory system. Each file is scoped, versioned, and retrievable.

project-root/
├── CLAUDE.md              # Global instructions (always loaded)
├── .claude/
│   └── settings.json      # Hook definitions
└── memory/
    ├── README.md           # Index - what lives where
    ├── stack.md            # Tech decisions + rationale
    ├── patterns.md         # Learned patterns from sessions
    ├── blockers-resolved.md # Solved problems, don't repeat
    ├── clients/
    │   ├── client-a.md    # Per-client context
    │   └── client-b.md
    └── sessions/
        └── YYYY-MM-DD.md  # Session logs (auto-written by hook)
patterns.md

Accumulates learned patterns from sessions

Format: Short bullet: problem → solution → why it works

Example: n8n webhook nodes require explicit 30s timeout in prod; default 10s drops on Vercel edge.

blockers-resolved.md

Documents every solved blocker so it never recurs

Format: Date · Symptom · Root cause · Fix · Prevention

Example: 2026-04 · Prisma type errors on deploy · prisma generate not in build script · add to pnpm build.

sessions/YYYY-MM-DD.md

Timestamped session log written by auto-memory hook

Format: Goal → Actions → Decisions → Learnings

Example: Auto-written on session end by the PostToolUse hook.

Automation

Auto-Memory Hooks

Manual memory is fragile. Hooks make memory automatic: learnings are captured without any deliberate action from you or Claude.

Stop hook: session logger

Fires when a Claude session ends. Writes a timestamped summary to memory/sessions/. Captures what was built, decisions made, and patterns observed.

// .claude/settings.json
{
  "hooks": {
    "Stop": [
      {
        "matcher": "",
        "hooks": [{
          "type": "command",
          "command": "node scripts/memory-logger.js"
        }]
      }
    ]
  }
}

PostToolUse hook: pattern extractor

Fires after every tool call. When Claude writes a file or runs a command, this hook checks for patterns worth persisting: new conventions, resolved errors, repeated solutions.

// .claude/settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Bash",
        "hooks": [{
          "type": "command",
          "command": "node scripts/pattern-extractor.js"
        }]
      }
    ]
  }
}

memory-logger.js: minimal implementation

// scripts/memory-logger.js
const fs = require("fs")
const path = require("path")

const date = new Date().toISOString().split("T")[0]
const dir = path.join(process.cwd(), "memory", "sessions")
fs.mkdirSync(dir, { recursive: true })

const entry = [
  `# Session - ${date}`,
  `## Timestamp`,
  new Date().toISOString(),
  `## Learnings`,
  process.env.CLAUDE_LEARNINGS ?? "(none captured)",
  "",
].join("\n")

fs.appendFileSync(path.join(dir, `${date}.md`), entry)

Retrieval

Retrieval at Session Start

Writing memory is only half the system. Claude must also read the right memory at the right time, without loading everything into context at once.

1

Pre-session briefing via hook

A PreSession hook (or a prompt prefix) runs memory/README.md through a small script that identifies the most recent session log and any open patterns. The output is prepended to the context as a briefing block.

2

Targeted retrieval with /read

For specific topics, instruct Claude to read the relevant memory file directly. "Read memory/clients/client-a.md before we continue" loads exactly what is needed without touching everything else.

3

Semantic search via SAFLA or similar

For large memory stores (100+ session logs), a vector memory layer lets Claude query by concept rather than filename. Ask "what do we know about n8n timeouts" and get ranked results back in seconds.

4

Working memory injection

At session start, keep the active working memory slim: current project state, last 3 decisions, and top 5 open patterns. Everything else stays on disk until needed.

Maintenance

Pruning Strategies

Memory that is never pruned becomes noise. Stale patterns and obsolete rules waste context and mislead the model. Prune on a schedule.

CadenceWhat to pruneMethod
Every sessionWorking memory: clear active context on stopStop hook resets working-memory.md to empty template
WeeklySession logs older than 7 days: archive or compressCron script moves logs to memory/archive/YYYY-MM/
Monthlypatterns.md: remove patterns solved by tooling or configManual review + git diff to confirm removal
QuarterlyCLAUDE.md rules: remove dead constraintsReview each rule: is it enforced? Does tooling now handle it?
On demandContradicting patterns: two entries with opposite adviceSearch for keyword overlap, resolve in patterns.md, delete stale entry

The pruning rule of thumb

If a memory entry has not influenced a session decision in 30 days, archive it. If it has not been referenced in 90 days, delete it. Memory quality beats memory quantity: a 50-line CLAUDE.md that is always relevant outperforms a 500-line file that is 80% stale.

Impact

Before vs. After

ScenarioWithout memoryWith persistent memory
Session startRe-explain project from scratch (~15 min)Auto-briefing from memory/ loads in seconds
Repeated bugDebug again, same root cause as last monthblockers-resolved.md surfaces the fix immediately
Client contextDig through notes and Slack history manuallymemory/clients/ has full context, preferences, history
Session 50 vs. session 1Identical capability, no compounding50 sessions of learned patterns, far faster execution

Want this running in your stack?

AY Automate builds agent systems, RAG pipelines, and Claude Code setups for production teams.