persistent-memory

Memory — repo-local persistent context

A simple, git-friendly system for keeping project context across sessions, devices, and agents. No tooling required — just grep, tail, and echo.

Why

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.

File structure

docs/memory/
  README.md         ← This file. The workflow reference.
  facts.md          ← Curated durable truths (~50 lines max)
  memory-log.jsonl  ← Append-only chronological log

What goes where

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).

When to write

Any of these triggers means something should be saved:

Format

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.

Integration with your agent config file

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:

With ADRs (optional)

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.

Do’s

Don’ts