I keep agents around and their context leaks away with the session. Not the thread closing — the useful parts: what I decided, what I know about this project, what the user actually preferred. Those get scattered across runtimes and folders, and the next agent starts cold. dream-memory is the read side of the fix, and it's now public on Codeberg.
The name is the design. A scheduled ingest runs while the agent sleeps and folds session logs, work facts, and observations into a plain-markdown, git-versioned store. What ships is the read half — a CLI and an MCP server that answer questions out of that archive instead of making the agent guess.
The store is the stable half
The decision the whole thing hangs on is separating the store from the
ingester. The store is plain markdown plus git, so its format is stable and
inspectable; the ingester is whatever writes it, including an LLM job. The
layout is documented as the single source of truth: an index.md table mapping
entity to file to repo roots, plus entities/, sections/, and
observations.md. The reader assumes only what that contract documents.
The index resolver is the subtle part. The repo-path column is a
comma-separated list, and a trailing parenthetical is stripped before matching,
so /home/user/system/nix-config (was nixos-system) resolves as
/home/user/system/nix-config. The resolver picks the longest matching path, so
a more specific root wins over a broad one.
The risk that shaped the read side
The store's edges are low-trust and high-volume. observations.md is
provisional ingest output — unverified until corroborated — and it's the
easiest thing an agent will over-trust. So the read side is bounded and read-only
by construction:
dream_entityanddream_sectiontruncate at 200 lines or 16 KiB and append a[truncated]marker.dream_searchreturns up tomaxResultssources with at most three matching lines each.- Observations are always served behind a
> Provisional:framing header, so an agent can't quote one as settled fact.
That last one is the whole bet. An agent that can read a memory store can also
act on it, and framing the low-trust slice is what makes exposing it safe.
Sensitive entities are opted out via DREAM_MEMORY_EXCLUDE — the reader
refuses dream_entity on them and dream_search skips them entirely. Nothing
is excluded by default.
The tool
dream-memory is TypeScript, Node ≥ 22.5, version 0.1.0. Four MCP tools —
dream_resolve, dream_entity, dream_section, dream_search — plus the
matching CLI subcommands, with --json for machine output; pnpm test bundles
and runs vitest. It's MIT.
It only reads. The consolidation stays a separate concern, and keeping it separate is why the archive isn't just a database with a nicer API — it's a git repo you can diff.