Guides

Give your AI agent a memory

5 min read

Every agent session starts from zero. So you either re-explain the project every time, or you let the agent re-derive it from the code, slowly and sometimes differently than it did the last time. The worst is when it quietly reworks something you settled on yesterday.

The fix isn't a vector database or a memory plugin. It's files. Markdown is the one format the agent reads and writes fluently, you can audit it yourself, and it versions with the rest of the project. Straight from the source, it's how Anthropic tells people to build agents: notes written to files outside the context window, pulled in only when a task needs them. Here's the exact setup my projects run on.

The shape

Five parts, one folder. Call it memory/, put it wherever your project keeps its non-code files.

1. Small notes, one topic each. One decision, one subsystem, one hard-won lesson per file. Each opens with a one-line description of what's inside:

---
name: preview-surface
description: how the app preview works, what renders it, and the navigation gotcha
---

2. An index the agent always reads. A single MEMORY.md, one line per note:

# Project Memory — Index
Start every session here: read this index + active-context, then open
only the notes the task needs.

- [Active Context](active-context.md) — current focus, in-flight work, open questions
- [Decision Log](decision-log.md) — what was decided and why, dated
- [Preview Surface](preview-surface.md) — how the preview renders; the navigation gotcha
- [Payments](payments.md) — why Stripe over IAP, the entitlement model

This split is the part that makes everything work. The index is always in the agent's context, and it stays cheap because it's one line per topic. The notes load only when a task needs them. Without the split you get one giant NOTES.md that grows until the agent starts skimming it, and skimmed memory is worse than no memory because you think it's working.

3. active-context.md, capped at about a page. What's happening right now: the current focus, work that's in flight with its next step, open questions ranked. This is the handoff between sessions. A new session reads it and picks up where the last one stopped. When something ships, it moves out of this file and into the decision log. The cap matters: if this page grows, it's just a second diary.

4. A decision log, with the why. Dated entries, newest first:

## 2026-07-09 — Native rendering replaces the streamed preview
Decided: render previews natively on the phone instead of streaming
pixels from the Mac.
Why: streaming was 400ms behind on every tap and broke text selection.
The tunnel we'd need for native rendering also carries every future
feature, so the work pays twice.

The why is the part you'll actually need. Write down a decision without its reasoning and you'll argue about it again in three months, with the agent or with yourself.

5. An archive. When the decision log or a note grows heavy, move the old tail to archive/decision-log-2026-06.md and leave a pointer. Nothing gets deleted, and the day-to-day set stays small.

Wiring it into the agent

The folder does nothing on its own. The agent has to know when to read it and when to write to it, and that goes in whatever standing-rules file your tool supports (CLAUDE.md, AGENTS.md, or custom instructions):

## Project memory
On start: read memory/MEMORY.md and memory/active-context.md. Open
further notes only when the index says they're relevant. Do NOT read
everything.

Update the memory when:
- you finish a feature or change how something works (update the topic note)
- a decision is made or reversed (add a decision-log entry with the why)
- you learn something a future session would otherwise re-discover

Keep active-context.md to one page. Move shipped work to the decision
log. When a note grows heavy, archive the tail and leave a pointer.

The write triggers matter as much as the read instructions. Without them, memory either never gets written or rots into a diary of everything the agent did, and a diary is the giant-file problem all over again.

The habits that keep it working

Index lines decide what gets read. The one-line description is what the agent uses to decide whether a note is worth opening. A vague line ("misc notes on the backend") means the note effectively doesn't exist. Write index lines like you're selling the click.

Let the agent do the writing. You review diffs, you don't hand-maintain notes. If a note is wrong, say so and the agent fixes it, same as the code.

Tidy on a signal, not a schedule. Every month or two, or when the folder starts feeling heavy, have the agent do a tidy pass: merge duplicates, archive dead weight, re-rank the open questions. It takes the agent ten minutes and clears out the junk.

Ask before you close. The end of a session is when memory gets written. Before I end one, I ask, "did you update the memory?" Half the time the answer is yes. All of this memory system helps, but in the end, it still needs some handholding.

It all comes down to one rule. Keep the memory smaller than what the agent will actually read. Every piece above exists to protect that, and when it holds, each new session starts already caught up instead of starting from zero.


I build Koda, a Mac app where the agent keeps a memory like this for every project by default. But nothing above needs it. It's markdown in a folder, and any agent tool can run it today.