dream-memory: an agent's memory, consolidated while it sleeps

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_entity and dream_section truncate at 200 lines or 16 KiB and append a [truncated] marker.
  • dream_search returns up to maxResults sources 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.

codeberg.org/maxronner/dream-memory