Memory Spine
Local-first memory for AI agents

One memory. Every agent. Zero infrastructure.

Claude Code, Codex and any CLI agent on your machine share a single long-term memory: plain markdown in a local git repo, one disciplined write path, context injected automatically into every session — and a default-deny access gate born from a real incident.

Are you an AI agent? Read the whitepaper: memory.bridges.community/agents.md

7 weeksin daily production
497records and counting
≈3.5k tokinjected per session
0databases · servers · vendors
Works with Claude CodeCodexHermesCursorAiderany shell-capable agent
The problem

Why agent memory usually fails

  • Every tool hoards its own silo — ChatGPT memory, CLAUDE.md, Cursor rules — and none of them talk.
  • Pull-model amnesia: the agent must remember to ask its memory. It doesn't.
  • Context compaction strikes without warning — whatever wasn't written down is gone forever.
  • Everything on the machine is trusted by default. One rogue app can read it all.
The fix

Structure built around one canon

  • One brain for all agents — built-in memories demoted to session caches.
  • Push, not pull — a hook injects a distilled ≤14 KB packet + "what changed while you were away" into every session.
  • Checkpoint discipline — record at milestones, pins for env-facts, post-compaction recovery.
  • Default-deny access gate keyed on process ancestry, owner-only allowlist, full audit log.
A live system, not a concept

This is what agent memory looks like

The vault opens in Obsidian as a graph: every dot is one markdown record, every cluster a project scope around its hub, every edge a wikilink. Taken from the production system behind these numbers.

Obsidian graph of a live AgentMemory vault: hundreds of record dots clustered around scope hubs
facts decisions threads entities artifacts
The process

The memory cycle

01

Write at checkpoints

Agents record decisions and facts the moment they happen — through spine-new only: validation, secret scan, dedup gate.

02

One immutable canon

One record = one markdown file in ~/AgentMemory. Supersede, never edit. A daemon commits every 5 minutes; agents never touch git.

03

Distill honestly

Each scope compiles into a ≤14 KB packet: pins first, then decisions, facts, blockers. Every truncation carries an honest counter.

04

Inject automatically

A session-start hook delivers the packet plus a per-agent delta — through the access gate. The next session starts already knowing.

Battle scars included

Design decisions that survived production

Files in git, forever

Full history, audit and backup for free. Delete does not exist — knowledge is superseded, never erased.

Secrets are never values

Memory stores only "name + where it lives". A secret scanner runs on every write, in pre-commit, and across full history in CI.

A lifecycle for knowledge

Inbox for topics with no home, owner-only triage, weekly promotion for candidates, pins for environment truths.

Access gate from a real incident

A third-party app once read the packet through a global agent profile. Now: default-deny by process ancestry. An agent cannot grant itself access.

Injection-hardened

Packets are framed as data, not instructions. External content is tagged untrusted and never auto-injected.

Ops-grade reliability

Sync, backup, health and digest daemons; a dead-letter queue for alerts; a 13-test selftest; starvation alarms; atomic writes.

Honest comparison

Against the usual approaches

Instead ofMemory Spine
Per-tool memory silos with opaque retentionOne canon for every agent; built-in memories become session caches.
A vector DB or memory service holding your dataFiles + git, local. Embeddings rejected on evidence: keyword search with morphology hit 9/10 top-1 on real queries.
Hoping the agent remembers to askGuaranteed context before the first word of every session.
Notes dumped into the context windowTyped, size-bounded distillation with confidence levels and honest counters.
Trusting every process on the machineDefault-deny gate + complete access audit log.
497markdown records across 10 scopes
≈40sfrom a lost alert to Telegram delivery
13/13selftests green on every CI run
FAQ

Questions that come up first

Is this a database or a framework?

Neither. It is plain markdown files in a local git repo plus a set of bash/python CLI tools. Any agent that can read files and run shell commands participates — no SDK, no server, no account.

What stops a random app from reading my memory?

A default-deny access gate checks the process-ancestry chain of every caller against an owner-only allowlist, logs every access, and alerts on every refusal. It exists because a third-party desktop app actually did read the packet once. Honest caveat: the vault stays a plain folder, so "secrets never as values" remains the last line of defense.

Why not embeddings and vector search?

We measured instead of assuming: keyword search with morphology and synonyms hit 9/10 top-1 on real recall queries. Zero infrastructure beat a vector database on our workload — and stays fully transparent and debuggable.

Does it work outside macOS?

The core tools are portable bash + python3. macOS gets first-class treatment (launchd jobs, optional Keychain token cache); on Linux you run the same binaries from cron or systemd timers.

How does it survive context compaction?

By design: agents write at checkpoints (not session end), environment facts are pinned so they never fall out of the packet, every session gets a per-agent delta, and a post-compaction hook re-injects the packet with recovery instructions.

What about backups?

Three layers. The sync daemon pushes every commit to a local bare mirror (a second copy on the same machine). A nightly job snapshots the vault and, if you name an external volume in backup.conf, copies it there whenever the disk is mounted — soft-skipped with a note when it is not. And the health check nags you when the external copy grows stale, so a forgotten disk never fails silently.

Give your agents a memory that survives the night

https://github.com/AlexBridgesman/memory-spine

Verified on a second machine: fresh install from this repo, selftest 13/13 — and the access gate correctly denied the first unapproved caller.