A simple, git-friendly system for keeping project context across sessions, devices, and agents. No tooling required — just grep, tail, and echo.
Coding agents (Claude, Cursor, Windsurf, etc.) start each session with a blank context. Without a memory layer, you repeat yourself — re-explaining project quirks, rediscovering pitfalls, re-laying out the current state. This system stores durable context as plain files in your repo so any agent, on any device, can pick up where you left off.
docs/memory/
README.md ← This file. The workflow reference.
facts.md ← Curated durable truths (~50 lines max)
memory-log.jsonl ← Append-only chronological log
| File | Purpose | Format | Size limit |
|---|---|---|---|
facts.md |
Truths that cost time to rediscover. Tech stack quirks, hard-won pitfalls, project-wide conventions. | Markdown list | ~50 lines |
memory-log.jsonl |
A chronological record of what happened. Completions, decisions, pitfalls, session notes. Each line is one event. | JSONL (one JSON object per line) | Unlimited |
Both files are plain text in git — zero tooling overhead, zero merge conflicts (the JSONL is append-only).
Any of these triggers means something should be saved:
No special tooling: read with cat, search with grep, append with echo >>.
facts.md is a plain markdown list — one line per fact.
memory-log.jsonl is one JSON object per line, three fields:
{"date":"2026-07-04","type":"pitfall","summary":"Test runner --watch does not pick up new files without restart"}
type values and when to use them:
| Type | When |
|---|---|
completion |
A task, milestone, or phase finished |
decision |
A significant choice was made |
pitfall |
Something that wasted time — warn future sessions |
fact-archive |
A fact rotated out of facts.md to keep it short |
log |
A general session note that doesn’t fit above |
The summary is the search surface — grep -i "<term>" finds past context, grep '"pitfall"' filters by type.
Appending safely: if the file ever loses its trailing newline (some editors strip it), the next echo >> glues its JSON onto the previous line and silently corrupts the JSONL. If in doubt, repair first:
tail -c 1 docs/memory/memory-log.jsonl | read -r _ || echo >> docs/memory/memory-log.jsonl
Compacting facts: when facts.md approaches ~50 lines, move the oldest or least-relevant entries to the log as type: "fact-archive" entries, then delete them from facts.md.
Add this section to your project’s CLAUDE.md, AGENTS.md, .cursorrules, or equivalent:
## Memory
This repo keeps persistent context in `docs/memory/`.
- At the start of a task, read `docs/memory/facts.md` (kept under ~50 lines).
- When you complete a milestone, make a decision, or hit a pitfall, append to `docs/memory/memory-log.jsonl` — format and triggers in `docs/memory/README.md`.
- Search past context with `grep -i "<term>" docs/memory/memory-log.jsonl`.
- Project context belongs in `docs/memory/`, not in your built-in or local memory system. Reserve built-in memory for user preferences only.
Each line earns its place:
If your project uses Architecture Decision Records (ADRs) in docs/adr/, cross-reference them in the log:
echo '{"date":"2026-07-04","type":"decision","summary":"ADR-0003: Chose SQLite over Postgres for local dev. See docs/adr/0003-sqlite-for-dev.md"}' >> docs/memory/memory-log.jsonl
This way, grep decision in the log lists every decision ever made and where to find the details, without loading every ADR into context.
facts.md lean. Archive oldest entries to the log so the current facts are always relevant.type: "log" with what was accomplished, what’s next, and any active auths.facts.md when memory-log.jsonl is the right place. Durable truths only in facts. Events go in the log.facts.md grow past ~50 lines. Archive or prune. A bloated facts file defeats its purpose.memory-log.jsonl in place. It’s append-only. If something is wrong, append a correction entry rather than rewriting history.