Markdown memory backend (#44 Phase A)#48
Merged
Conversation
Fills the Level-1/Level-2 gap in the memory backend lineup: a human-readable, git-committed memory store for single-agent setups where the developer curates the memory file by hand. Two modes selected by config: - Level 1 (`file: ./memory.md`) — one compound markdown document. Each memory is a `## <heading>` section. The Karpathy LLM Wiki pattern. - Level 2 (`dir: ./memories`) — one `.md` file per topic. Filename (without extension) is the memory id. Use when you have separate functional areas (standing instructions vs project memories) to curate. Memory IDs are section headings or filename stems so an LLM can both append new memories (`write`) and edit existing ones (`update`) using human-readable addresses rather than opaque UUIDs. `search(query="")` returns every section/file in stable file order, designed for cache-friendly injection: agents load the whole memory set once at session start and inject it as a stable prefix so token positions don't shift between turns. Non-empty queries do a case-insensitive substring filter without ranking — no index, no magic. If you need ranked retrieval, use the sqlite backend. `report_contradiction` is a log-only no-op; the human edits the file to resolve. Matches the backend's curated-by-hand ethos. Also documents the memory-backend decision tree and the prefix-cache pattern in `docs/architecture.md`. Makes the positioning of each backend explicit so new users can recognise themselves in exactly one row. Scope-discipline check: single-file module, no new runtime deps (pyyaml already present), pattern mirrors `memory_sqlite.py` / `memory_pgvector.py` siblings exactly. The `custom` backend remains the escape hatch for everything else. Follow-up filed as #47: first-class memory-prefix slot in BaseAgent so the cache-friendly injection pattern works automatically across all backends, not just markdown. Assisted-by: Claude Code (Opus 4.6)
rdwj
added a commit
that referenced
this pull request
Apr 16, 2026
Missed in #48. Keeps the in-repo decision-reference list in sync with the backends actually supported by the dispatcher. Assisted-by: Claude Code (Opus 4.6)
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #44 Phase A.
Fills the Level-1 / Level-2 gap in the memory backend lineup — a human-readable, git-committed memory store for agents whose memory a developer wants to eyeball and edit by hand.
Design summary
Two modes selected by config:
file: ./memory.md) — one compound markdown doc, each memory is a## <heading>section. The Karpathy LLM Wiki pattern.dir: ./memories) — one.mdfile per topic, filename (without extension) is the memory id. Use when you have multiple functional areas to curate separately (e.g. standing instructions vs project memories).Same backend, same code, the config picks which mode.
Memory IDs = section headings (Level 1) or filename stems (Level 2). The LLM can both append (
write) and edit (update) using human-readable addresses rather than opaque UUIDs.search(query="")returns every section/file in stable file order, intentionally designed for cache-friendly injection: agents load the whole memory set once at session start and inject it as a stable prefix so token positions don't shift between turns. Non-empty queries do a case-insensitive substring filter without ranking — no index, no magic. If you need ranked retrieval, jump to the sqlite backend.report_contradictionis a log-only no-op; the human edits the file to resolve.Positioning vs other backends
Added a decision tree to
docs/architecture.mdMemory Integration section:Each jump is a real jump, not a sliding scale of features. Users should recognise themselves in exactly one row.
What this PR deliberately does NOT build
Scope-discipline check
Single-file module, no new runtime deps (pyyaml already present), pattern mirrors
memory_sqlite.py/memory_pgvector.pyexactly. Thecustombackend remains the escape hatch.Test plan
test_memory_markdown.py— factory (both modes, missing/malformed/both-keys/neither-key configs, relative paths), Level 1 write/search/update, Level 2 write/search/update/unsafe-filename rejection, stable sort order, dispatcher integrationfipsagentssuite 429/429 green (393 previously + 36 new)Follow-ups