Skip to content

About

A lightweight, file-based memory system for small software projects.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

project-memory

A lightweight, file-based memory system for small software projects. Just markdown files, a simple directory structure, and your existing source control. No third-party dependencies. Captures high-level project entities like the project's product description, the project's system architecture, and an index of all memory entries. A minimal frontmatter system in the memory files allows for extensibility and future iteration (e.g. db-based storage). This system is meant for smaller-scale projects.

What you get

After bootstrapping, your project will have these additions:

/.gitattributes              # Union merge for memory-index.md; appended to if it already exists
/AGENTS.md                   # Vendor-neutral entrypoint for any agent; updated if it already exists
/CLAUDE.md                   # One-line `@AGENTS.md` import for Claude Code
/docs/
  memory/
    memory-index.md          # Table of contents
    product.md               # What and why, implementation-independent
    architecture.md          # Current implementation overview
    log/
      yyyy-mm-dd-<slug>.md   # Dated events / decisions / incidents / etc.
  plans/
    current/
      README.md              # Plans whose work is not finished yet
    archive/
      README.md              # Plans whose work is done

Core files (product.md, architecture.md) plus a dated log/ subdir. Add more core files (e.g. codebase.md, conventions.md, etc.) only when an existing file exceeds ~50 lines, or starts evolving on a separate cadence.

Plan documents live in docs/plans/. A plan starts in current/ and moves to archive/ when its work is done.

Why this shape?

Two core files - product.md is the durable layer (which survives a code rewrite or systems migration), and architecture.md is the current implementation (which a rewrite would replace). That durability split is the essential distinction. Splitting further (codebase.md, conventions.md, etc.) is deferred until a file outgrows itself.

AGENTS.md as canonical - AGENTS.md is the open standard read by almost all coding agents. Claude Code only reads CLAUDE.md natively, so a one-line @AGENTS.md import is the Anthropic-recommended workaround. This keeps the project portable across agents.

Plans split by state - a plan's status is its location. current/ versus archive/ answers "what is still open" from a directory listing, with no field to parse and no file to open.

memory-index.md - An agent reads one cheap file to discover what's in memory, then fetches specific entries on demand. Without an index, agents either guess or blanket-load, both of which are expensive.

Union merge for the index - Every branch adds its log line at the top of memory-index.md, so two branches that each add one would conflict. docs/memory/memory-index.md merge=union in .gitattributes tells git to keep lines from both sides instead.

Frontmatter is schema-like - Every entry has the same fields. If memory ever migrates to a database (or a static-site search index, or anything queryable), the frontmatter fields become columns.

Monorepos

A monorepo is in scope. Run the bootstrap inside each subproject so each has its own docs/memory/, and optionally once more at the repo root for cross-cutting concerns. The root AGENTS.md should route agents to the relevant subproject memory when working inside one. See product.md for the rationale.


Getting started

Three ways to bootstrap, pick whichever you prefer:

Option A - Run the bootstrap script (recommended)

init/bootstrap.py and its init/templates/ directory are everything you need. Python 3.10+, stdlib-only - no install, no chmod, no $PATH setup. Clone this repo, then run from anywhere:

python3 /path/to/project-memory/init/bootstrap.py --project /path/to/your/project "<project name>" "<project description>"

Or cd into your target project first and omit --project (defaults to the current directory):

cd /path/to/your/project
python3 /path/to/project-memory/init/bootstrap.py "<project name>" "<project description>"

The script safely renders the templates into the target project, with metadata populated (project name, dates, author from git config user.name in the target repo) and <placeholder> strings left for you to fill in. If AGENTS.md or CLAUDE.md already exist, it offers to merge in the memory rules. It will not overwrite anything under docs/memory/. Safe to re-run after partial setup.

It also creates docs/plans/current/ and docs/plans/archive/, each holding a README.md. Plans start in current/ and move to archive/ when done, so current/ lists only open work. Existing READMEs there are left alone.

Finally it adds docs/memory/memory-index.md merge=union to .gitattributes, creating the file if needed and asking before appending to an existing one. It asks git which merge attribute already applies to the index: if it is already union nothing changes, and if the repo sets something else the script reports it and leaves the file alone.

After bootstrapping, fill in <placeholder> strings in docs/memory/product.md and docs/memory/architecture.md

Option B - Create the files manually

Open each file in init/templates/ (see Bootstrap files below for the mapping), copy their contents into the target project at the corresponding path, and substitute the ${var} placeholders by hand. Useful if you want to understand what the script does, or if Python isn't handy.

Option C - Hand it to an agent

Hand this repo to an LLM coding agent, with this prompt:

Bootstrap this project's memory system. The script is at <path/to/project-memory/init/bootstrap.py> (run with --project . from the target repo). Project name: <project-name>. Description: <project-description>. After the script completes, fill in <placeholder> strings in docs/memory/product.md and docs/memory/architecture.md from the existing codebase (manifests, README, etc.); leave any you can't infer for me to complete.

A capable agent should handle this end-to-end, and usually populate architecture.md partially from existing manifests.

Bootstrap files

The bootstrap script (Option A) renders these template files into the target project. To change what gets generated, edit the template source files directly - they're the single source of truth.

Bootstrap target Template source Substitutions
AGENTS.md init/templates/AGENTS.md ${name}, ${desc}, ${desc_sentence}
CLAUDE.md init/templates/CLAUDE.md none
docs/memory/memory-index.md init/templates/memory-index.md ${name}, ${today}
docs/memory/product.md init/templates/product.md ${desc}, ${desc_sentence}, ${author}, ${today}
docs/memory/architecture.md init/templates/architecture.md ${name}, ${author}, ${today}
docs/memory/log/<yyyy-mm-dd>-bootstrap.md init/templates/bootstrap-log.md ${author}, ${today}
docs/plans/current/README.md init/templates/plans-current-readme.md none
docs/plans/archive/README.md init/templates/plans-archive-readme.md none
.gitattributes none; the script adds the line docs/memory/memory-index.md merge=union none

The script substitutes ${var} placeholders using Python's string.Template. Other placeholder syntax (e.g. <...> markers) is left as-is for the user to fill in after bootstrap.

${desc_sentence} is the description with a trailing period added unless it already ends in ., ! or ?. Use it where prose follows the description.

If a template ever needs a literal $, escape it as $$ (a string.Template requirement).

Upgrading

To pick up changes to the memory rules in an already-bootstrapped project, re-run the same script with --upgrade:

python3 /path/to/project-memory/init/bootstrap.py --upgrade --project /path/to/your/project

The script locates the <!-- project-memory:start --> ... <!-- project-memory:end --> block in your AGENTS.md, diffs it against the current template, and prompts before replacing. Content outside the markers is preserved. If your block already matches, the script prints "already current."

Either way it then creates any missing docs/plans/ directories and adds the .gitattributes union rule, so a project bootstrapped before either existed picks them up. Declining the diff skips this and changes nothing.

If your marker block contains sections the template does not have - a heading you added inside the markers - the upgrade refuses to run and names them, because replacing the block would delete them. Move those sections below <!-- project-memory:end --> and re-run; content outside the markers is preserved. --force replaces the block anyway, and still prompts before writing.

python3 /path/to/project-memory/init/bootstrap.py --upgrade --force --project /path/to/your/project

Reworded template prose is not mistaken for your own content: the check compares section markers (headings and the bold label opening each rule), not lines. Content you add under an existing marker is still replaced.

The block between the markers is system-owned. Don't hand-edit it; add custom rules outside the markers instead.

Frontmatter schema

Every memory entry (core file or log file) starts with this frontmatter:

Field Type Purpose Example
title string Human-readable name Adopted VictoriaMetrics for observability
summary string ≤120ch Index hook - what an agent reads to decide if the entry is relevant VM stack (logs+metrics+traces) on <hosting service>; rejected <other stack> for lack of maturity
created YYYY-MM-DD Immutable date of record 2026-05-07
updated YYYY-MM-DD Optional. Add on the first meaningful edit; bump on subsequent edits. Absent means same as created. Drives staleness review 2026-05-08
author string Originator. Immutable - credit, not ownership (git blame covers ongoing edits) <git user.name>
tags array<string> Freeform, kebab-case. For grep/filter [log, decisions, observability]

Deliberately not included:

  • status (active/superseded/etc.) - if it's in memory it's true; if not, delete it and git remembers
  • type - filename pattern encodes core vs log (no date prefix vs log/yyyy-mm-dd-*.md)

Conventions for working with the system

  • Core files stay short (~50 lines) - Past that, split (e.g. codebase.md, conventions.md) and update memory-index.md.
  • Entries are concise - Bigger than a commit message, smaller than a design doc. A handful of bullets, short rationales per decision. If a bullet needs a paragraph, the entry is probably bundling.
  • One event per log file - Multiple events on the same day = multiple files (2026-05-08-layout-flatten.md, 2026-05-08-dep-bump.md). Don't append a second event onto an existing log file - keeps retrieval precise and titles meaningful.
  • Log slugs stay short (1-3 words) - The slug after the date is a topic distillation, not a sentence. If you need more, the entry is probably bundling decisions and should be split.
  • Log entries are append-only - If superseded, write a new log entry that links back; don't rewrite history. This shows the evolution of the discussion and decision-making process.

Anti-patterns

  • Long entries (>~50 lines) - usually a sign two topics got merged; split them.
  • Silent rewrites of log files - log entries are dated events; supersede with a new dated entry, don't edit the old one.
  • Adding fields to frontmatter for one entry - keep the schema uniform across all entries so future tooling can rely on it.

Prior art

This system is inspired by, but deviates from:

  • Cline's Memory Bank - established 6-file taxonomy in a memory-bank/ directory, loaded via .clinerules. This system adopts the pattern (markdown files in a memory directory as the agent's persistent context), but uses two core files instead of six, adds an index file, adds a log/ subdir for dated events, and adds frontmatter for queryability.
  • AGENTS.md - open standard for the agent-facing instruction file. Not yet natively read by Claude Code - see the Claude Code memory docs link below.
  • Anthropic Claude Code memory docs - documents the @AGENTS.md import workaround used in CLAUDE.md above. The native-AGENTS.md feature requests (#6235, #34235, #31005) remain open.

Also shaped by conversations with, and prior work by:

License

MIT © Eric Case

About

A lightweight, file-based memory system for small software projects.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages