A simple technique to stop Claude Code Agents from rediscovering your codebase every conversation. One JSON file, a few lines in CLAUDE.md and a few in MEMORY.md, and your Explore agents become a persistent knowledge layer.
Claude Code's Explore agents are powerful: they search, read, and synthesize information about your codebase. But they start from zero every conversation. Ask about your auth system on Monday, then again on Thursday, and you'll burn the same tokens tracing the same files twice.
There's no built-in memory for agent results. So I built one. Say AMEN.
Conversation 1 Conversation 2
┌──────────────────────┐ ┌─────────────────────┐
│ "How does auth work?"│ │"Add OAuth support" │
│ │ │ │
│ Launch Explore agent │ │ Check cache → HIT │
│ Agent reads 12 files │ │ Skip agent entirely │
│ Returns findings │ │ Use cached summary │
│ │ │ + file list directly│
│ Distill → cache │ │ │
└────────┬─────────────┘ └─────────────────────┘
│ ▲
▼ │
.agent-cache.json ────────────────────────────┘
- Before launching an Explore agent, Claude checks the cache file for a matching entry
- If the entry exists and is fresh, the agent is skipped entirely
- If the entry is missing or stale, the agent runs normally, then its findings are distilled and saved
- Reusable implementation patterns are saved separately with no expiry
Here's what AMEN actually saves.
An Explore subagent typically runs 5–8 turns, each accumulating context: file contents, search results, reasoning. Because context grows with every turn, total token consumption across all turns sums to roughly:
- Input tokens: ~50,000–100,000 (context accumulates across turns)
- Output tokens: ~5,000–10,000 (summaries, reasoning, tool calls)
One Read call to .agent-cache.json, pulling only the relevant key:
- Total tokens: ~200–500
That's a ~99% reduction per cache hit.
Not too mention the speed aspect.
Create .agent-cache.json in your project root:
{
"_meta": { "maxAgeDays": 7 },
"topics": {},
"patterns": {}
}# .gitignore
.agent-cache.json
The cache is local and machine-specific. It should never be committed.
Paste the contents of CLAUDE.md into your project's CLAUDE.md (the file Claude Code reads at the start of every conversation). Place it near the top, after any project-level conventions:
Paste the contents of MEMORY.md into your project's memory file
{
"_meta": { "maxAgeDays": 7 },
"topics": {
"topic-slug": {
"ts": "2026-02-08T14:30:00Z",
"summary": "Plain text summary of what the agent found. 2-4 sentences, under 300 chars.",
"files": ["src/auth.ts", "src/middleware/session.ts"]
}
},
"patterns": {
"pattern-slug": "One-liner describing a recurring implementation pattern."
}
}| Field | Type | Description |
|---|---|---|
_meta.maxAgeDays |
number | Topic entries older than this are treated as stale. Default 7. |
topics.<key>.ts |
string | ISO 8601 timestamp of when the entry was written. |
topics.<key>.summary |
string | Distilled agent findings. Plain text, no code fences, under 300 chars. |
topics.<key>.files |
string[] | Key file paths the agent identified as relevant. |
patterns.<key> |
string | Reusable implementation pattern as a one-liner. No TTL — updated only when the pattern changes. |
{
"_meta": { "maxAgeDays": 7 },
"topics": {
"auth-system": {
"ts": "2026-02-08T14:30:00Z",
"summary": "JWT auth in src/auth.ts using jose library. Login/register routes in src/routes/auth.ts. Session stored as httpOnly cookie named 'token'. Middleware in src/middleware/auth.ts extracts and verifies JWT on every request.",
"files": ["src/auth.ts", "src/routes/auth.ts", "src/middleware/auth.ts"]
},
"database-schema": {
"ts": "2026-02-07T09:15:00Z",
"summary": "PostgreSQL with Drizzle ORM. Schema defined in src/db/schema.ts. Migrations in migrations/ dir managed by drizzle-kit. Key tables: users, posts, comments, tags. Relations defined inline with Drizzle's relations() helper.",
"files": ["src/db/schema.ts", "src/db/index.ts", "drizzle.config.ts"]
}
},
"patterns": {
"new-api-route": "Create handler in src/routes/<name>.ts, add to router in src/routes/index.ts, add validation schema in src/validation/<name>.ts.",
"db-migration": "Run 'npx drizzle-kit generate' after schema change, then 'npx drizzle-kit migrate' to apply."
}
}The default maxAgeDays: 7 works well for active projects. Adjust based on how fast your codebase changes:
| Pace | Suggested maxAgeDays |
|---|---|
| Rapid iteration (multiple changes/day) | 3 |
| Normal development | 7 |
| Stable/maintenance mode | 14–30 |
Topic keys should map to the kind of question you'd ask an Explore agent:
auth-system— "How does authentication work?"api-routes— "Where are the API endpoints defined?"database-schema— "What's the database structure?"deployment-pipeline— "How is the app deployed?"
Bad keys: bug-fix-123 (too specific), code (too broad), refactoring-plan (not a codebase fact).
Patterns capture the recipe for recurring implementation tasks:
- Good:
"Add route in src/routes/<name>.ts, register in src/routes/index.ts, add middleware in src/middleware/<name>.ts." - Bad:
"The routes are in the routes folder."(too vague — that's a topic summary, not a pattern)
The difference: a topic describes what exists, a pattern describes how to add something new.
First conversation about a topic — no cache entry exists. Claude launches the Explore agent normally, then saves the results. You see no difference except the cache file gets populated.
Subsequent conversations — Claude finds the cache entry, checks the timestamp, and skips the agent. The response is faster and cheaper. You'll often see Claude reference the cached files directly without any exploration step.
After the entry expires — Claude re-runs the agent and overwrites the entry. This keeps the cache accurate as your codebase evolves.
Stale entries (>7 days) — automatically pruned whenever any write to the cache occurs.
- Claude must follow instructions. This technique relies on Claude Code reading and obeying the
CLAUDE.mdinstructions. In practice it works reliably, but it's a convention, not an enforcement mechanism. - No cross-machine sync. The cache is local. If you work on multiple machines, each builds its own cache independently.
- Summaries can drift. If you make major structural changes between cache writes, the summary may be outdated until it expires. We try to preempt that by the reinforcements in both files to update agent results. Lower
maxAgeDaysif this bothers you, or manually delete the stale key. - Not a replacement for CLAUDE.md. The cache handles dynamic, exploratory knowledge. Static facts about your project (conventions, tech stack, directory structure) still belong in
CLAUDE.md.
This technique is for the public domain. Use it however you like. Send me a message if you liked it or want to improve on it (also jobs if you're hiring).