Seahorse
Provides persistent bi-temporal memory in an Obsidian-compatible vault, storing every memory episode as a readable and editable Markdown file with YAML frontmatter so humans can audit and maintain the same notes that agents query.
Seahorse
Persistent, bi-temporal memory for LLM agents — local-first, MCP-native, Obsidian-readable. This is what your agent's memory looks like — a markdown file you can read in Obsidian, diff in git, and edit by hand (abridged):
---
id: 019bb17c-12cb-7224-8ade-a3d0362d6d75
created_at: '2026-01-12T09:14:17.163477Z'
schema_version: 1.0.0
provenance:
agent_id: seahorse/claude-code
confidence: 0.97
extraction_mode: llm
model_used: claude-sonnet-5
source_type: agent
valid_at: '2026-01-12T00:00:00Z'
cognitive_type: social
source_type: agent
title: Alex Vega works as a data engineer
tags: []
---
# Alex Vega works as a data engineer
Alex Vega is a data engineer at [[Northwind Analytics]], working remotely.uv tool install seahorse-memory --with "seahorse-memory[embeddings,llm]"
seahorse setupThat second command is the whole onboarding — vault, database, capture hooks, observer, MCP registration, agent instructions, skills, LLM provider. It always exits 0: steps that cannot complete degrade to a WARN line with the exact fix. Full flags and uninstall in docs/setup.md.
Quickstart
uv tool install seahorse-memory --with "seahorse-memory[embeddings,llm]" # or: pip install "seahorse-memory[embeddings,llm]"
seahorse setup # everything configured; --vault ~/myvault to pick one
seahorse remember "Sergio lives in Madrid" --title home
seahorse recall "where does Sergio live?"Real output of that fresh install:
$ seahorse remember "Sergio lives in Madrid" --title home
✓ Remembered
fact_id: 4ea140588150773ce3aace786aeef7f4
ep_id: 01a08b81-5b47-7e22-8ec8-e9f321f85534
status: ACTIVE
collisions: 0
$ seahorse recall "where does Sergio live?"
Recall: 'where does Sergio live?' (1 results)
# ep_id subject stale pending
1 01a08b81-5b47-7e22-8ec8-e9f321f85534 home no no
Use `seahorse recall-timeline <ep_id>` for the chain.
Use `seahorse recall-full <ep_id> ...` to hydrate body.First run: the embedding model (mE5-small, ~235MB) downloads lazily on the first
remember/recall;setup --warm-embeddingspre-downloads it.
The full agentic loop ships since v1.0.0, end to end from that one command. What's next: ROADMAP.md.
Related MCP server: agentcairn
Why
LLM agents start every session from zero: the context window is a scratchpad that resets. The tools that try to fix this have their own problems:
They forget badly. Most accumulate facts forever and never resolve contradictions — an agent "remembers" Madrid and Barcelona at once, with no way to know which is current.
They are opaque. Memory lives in a proprietary database the human cannot read, edit, or audit — if the agent is wrong, there is no way to correct it.
They are expensive and locking. Every episode goes through an LLM (real money at scale), and adoption means adopting the vendor's runtime or provider.
Their benchmarks are not trustworthy. The field's own numbers are hard to reproduce: the LOCOMO benchmark has 6.4% wrong gold answers (Penfield Labs audit), Mem0's reproduction is broken (issue #2800), and MTEB embedding scores do not predict memory-retrieval performance (LMEB, arXiv 2603.12572).
Seahorse is a different approach: an open, portable, bi-temporal memory standard that an agent writes to and reads from, that a human can read and correct, and that does not lock you into any runtime or provider. Its F3.1 format is the only markdown-native interchange spec with bi-temporal timestamps and append-only supersession with a recorded reason that the landscape review found (docs/related-work.md).
Who it's for: developers building agents (Claude Code, Cursor, Codex, or your own), Obsidian power users who want their notes queryable, and teams that want memory they can migrate without replaying history.
How it works
graph LR
A[Claude Code / any MCP agent] -- stdio MCP io.seahorse.memory/v1 --> S[seahorse-mcp]
S --> E[Bi-temporal engine]
E --> DB[(sqlite3 + sqlite-vec + FTS5)]
E --> V[Obsidian vault: markdown + F3.1 frontmatter]
H[Human in Obsidian] --> VAn agent talks to seahorse-mcp over stdio MCP. The engine records every
episode in a single-file SQLite database (sqlite-vec for vector search, FTS5
for full-text) and seahorse materialize publishes distilled notes to
Memory/ as F3.1 markdown (--mode all: every episode) — the human edits
the same notes. Format spec: docs/f3.1-format.md.
And this is what the memory graph of a vault looks like — a fictional demo
vault (examples/demo-vault/, 205 F3.1 notes: 169
episodes, 18 ringed consolidate notes in Memory/, 18 human notes —
invented, nothing real). Red edges are supersedes chains: a correction
never overwrites, it appends. graph.html
is the same graph, interactive (zoom, pan, drag, tooltips — self-contained).
And the loop on screen — a 30-second scripted demo with real CLI output
against a disposable vault (the script is
examples/demo-clip/demo.tape, re-renderable
with scripts/render-demo.sh):

The loop
Capture. Hooks record every Claude Code session as episodes — skip-first, near-zero cost, redacted. The observer self-heals (the next hook refires it).
Recall. The SessionStart hook injects
seahorse contextinto the next session, so the agent starts with what it learned before.Write back. The agent reads and writes memory through the MCP tools, not by guessing; at design decisions it writes ADR-style notes in
Memory/.Distill. The
consolidateandsession-noteskills distill recurrent episodes and session takeaways into notes — no API key needed.Human in the loop. Notes are markdown files you edit in Obsidian — if the agent is wrong, you correct the note, not a database.
Connect your agent
seahorse setup registers the server in Claude Code automatically (user
scope); seahorse setup --harness codex,cursor,vscode,antigravity,gemini
registers it in the other MCP agents (per-harness details in
docs/connect.md; Codex additionally gets the same automatic
session capture as Claude Code). The vault resolves dynamically at each call —
the vault containing the working directory, else the per-user default.
Agent | Memory tools (MCP) | Automatic session capture | Instructions installed |
Claude Code | ✓ | ✓ hooks | ✓ |
Codex | ✓ | ✓ (approve hooks once) | ✓ |
Cursor | ✓ | — | user rule, by hand |
VS Code (Copilot) | ✓ | — | workspace instructions file |
Antigravity | ✓ | — | ✓ |
Gemini CLI | ✓ | — | ✓ |
Every MCP-speaking agent works with a two-line config (.mcp.json, below) —
the memory tools never need hooks. Capture is the piece that needs them, so it
ships only where hooks exist.
Manual alternatives, when you need them (claude mcp add seahorse-mcp -- seahorse-mcp for Claude's CLI):
// .mcp.json at the project root — shares the server via git (~ is not expanded here: use ${HOME})
{ "mcpServers": { "seahorse-mcp": { "type": "stdio", "command": "seahorse-mcp" } } }Once connected, the agent sees the 15 memory tools — see The agent surface. The observer is a separate piece: it captures Claude Code sessions into episodes; the MCP server is how the agent reads and writes memory.
The agent surface
Exposed over stdio MCP (io.seahorse.memory/v1, protocol pinned 2025-11-25)
and mirrored on the CLI — memory primitives, not generic CRUD: the agent calls
remember / recall / improve / forget the way a human talks about memory.
Primitive | What it does |
| Record an episode (body, source, optional title/subject). |
| INDEX level — the current-state listing, clamped to |
| TIMELINE level — the supersedes chain around an anchor episode. |
| FULL level — the hydrated episode with all provenance. |
| Supersede an episode with a corrected one (append-only). |
| Soft-delete an episode (append-only; history preserved). |
| Build a point-in-time projection (all-None → current state). |
Plus 8 procedural / read-only tools: skill_add / skill_show / skill_list
/ skill_search (deterministic skills with a trust gate), freshness_view
(age/stale snapshot), audit_log (write-path history),
follow_supersedes_chain (version history), and context (session bootstrap).
Three retrieval levels give progressive disclosure: a cheap listing first (INDEX), the chain on demand (TIMELINE), the full record only when needed (FULL).
Everyday commands
The CLI mirrors the agent surface for humans, scripts, and cron jobs:
seahorse remember "deployed the API behind auth" --title deploy
seahorse improve <ep_id> "deployed the API behind oauth" --reason correction
seahorse forget <ep_id> --reason done
seahorse recall "what did we decide about the API design?"
seahorse observe status # capture worker state
seahorse consolidate # batch-distill episodes into a note
seahorse materialize # backfill distilled notes into Memory/
seahorse import --mode commit # migrate claude-mem observations
seahorse doctor --fix # diagnose + repair what Seahorse owns
seahorse setup --uninstall # remove the surfaces, keep the vaultYour vault stays yours
Python ≥ 3.11 is the only requirement — the interpreter's sqlite3 must
support enable_load_extension (sqlite-vec needs it); seahorse doctor reports
a FAIL if not. Obsidian is optional: Seahorse runs on any directory of
markdown — seahorse init adds a .seahorse/ sidecar.
A vault of pre-existing Obsidian notes (no frontmatter, or legacy
tags/created) is migrated with seahorse frontmatter migrate:
seahorse frontmatter migrate --vault myvault --dry-run # preview, write nothing
seahorse frontmatter migrate --vault myvault # apply; exit 97 if notes need manual work
seahorse index rebuild --vault myvault # rebuild the sidecar index--resume skips unchanged notes; --batch-size sets the checkpoint cadence.
Compared to other memory tools
Verified facts, not a ranking — sources in docs/related-work.md and the claims cited below.
Seahorse | mem0 | Letta / MemGPT | Zep / Graphiti | claude-mem | LangMem | |
Portable open format | ✓ F3.1 spec | ✗ proprietary | ✗ runtime-bound | ✗ | ✗ own schema | ✗ |
Human-readable layer | ✓ Obsidian vault | ✗ | ✗ | ✗ | ✗ | ✗ |
Bi-temporal (point-in-time) | ✓ | ~ | ~ | ✓ Graphiti | ✗ | ✗ |
Local-first, zero-infra | ✓ | ~ | ~ | ✗ cloud-only | ✓ | ~ |
Reproducible benchmark | ✓ harness in-repo | ✗ #2800 | — | — | — | — |
License | Apache-2.0 | Apache-2.0 (open-core) | Apache-2.0 | Graphiti Apache-2.0 / Zep proprietary | AGPL | Apache-2.0 |
The two facts that matter most: mem0's headline benchmark numbers are produced by its managed platform and platform-only features, which the open-source library cannot exactly reproduce (its own eval suite shows ~91% open-source vs 94.4% platform on LongMemEval; memory-benchmarks README, issue #2800), and Zep discontinued its self-hostable Community Edition in April 2025 and now ships cloud-only (deprecation post, PR #390), keeping only the Graphiti engine open source. Seahorse is local-first, publishes its benchmark harness, and keeps the memory format portable — never locked in.
Benchmark
Seahorse ships a reproducible benchmark harness (LMEB-S, a subsample of the LongMemEval benchmark) and publishes its own numbers — with caveats. Not a leaderboard; an honest, reproducible measurement.
Metric | Value | Note |
recall@10 | 0.13 | knowledge-update slice: 0.44 |
ndcg@10 | 0.11 | |
mrr | 0.13 | knowledge-update slice: 0.47 |
precision@10 | 0.02 | |
token efficiency | 0.998 | 51.5M tokens full-context → 121K measured |
latency p95 (INDEX) | 42 ms | retrieval-only, no rerank |
Caveats: the run uses a subsample (n≈470–500 questions, not the full dataset); relevance is derived from the dataset's golden labels (no LLM judge in the scored path); and it measures retrieval only, not the agent's final answer. A cross-encoder rerank was tested and rejected — it degraded recall@10 to 0.11 with 1.2s latency at the summary representation (a body-rerank experiment later recovered 0.83, so the rejection is representation-specific). Full methodology in docs/benchmark.md.
These numbers measure retrieval ranking only on a subsample with golden-derived relevance labels — they are not comparable to the end-to-end accuracy scores other memory systems publish (e.g. Graphiti 63.8% with gpt-4o-mini, Mem0 94.8 at top_50, Hindsight 91.4%). See docs/benchmark.md for how not to compare.
Design principles
Local-first, zero-infra. A single SQLite file and a folder of markdown — no server, no cloud.
Append-only, bi-temporal.
valid_at+created_ateverywhere;improvesupersedes,forgetsoft-deletes — point-in-time recall reproduces any past state.Honest degrade. Without the
embeddingsextra,recallfalls back to the current-state listing and says so — nothing silently degrades.Deterministic default, LLM optional. The skip-path is the near-zero-cost default; LLM extraction (cost-capped) only where it pays.
Scriptable, honestly. Branchable exit codes, a structured error envelope, and exit
75instead of silent no-ops for unimplemented commands.Human edits win. A human body edit survives; supersession merges metadata instead of overwriting.
Measured. 2,800+ tests, coverage gate ≥80%, e2e scripts (CONTRIBUTING.md).
Additive evolution. MCP profile and F3.1 format frozen at 1.0; a breaking change is 2.0.
FAQ
What is an episode? One memory record: a markdown file with YAML frontmatter
carrying two time axes (valid_at — when it became true, created_at — when it
was recorded), provenance, and a cognitive type (docs/f3.1-format.md).
How is this different from claude-mem? claude-mem stores observations in its
own schema; Seahorse is an open, bi-temporal standard with a portable format and
a human-readable layer — seahorse import migrates its observations in.
Do I need an LLM? No. The deterministic skip-path is the default (near-zero
cost); LLM extraction is optional (seahorse-memory[llm]), and even distillation
uses the agent's own LLM.
Is it free? Yes — Apache-2.0, local-first, zero-infra. A managed SaaS tier is planned.
Contributing
Contributions are welcome — see CONTRIBUTING.md for the dev setup, test/lint commands, and the PR workflow. Release history: CHANGELOG.md.
License
Apache-2.0. See LICENSE.
mcp-name: io.github.ssanvi-builds/seahorse-memory
This server cannot be deployed
Maintenance
Related MCP Connectors
Token-efficient MCP memory for Markdown vaults. Tiered search, GraphRAG, AI memories.
Portable memory for AI agents: capture once, recall across Claude, Cursor, and any MCP client.
One memory, every AI. A shared, user-owned markdown memory your AI clients read and write over MCP.
Persistent memory and knowledge graphs for AI agents. Hybrid search, context checkpoints, and more.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceLocal-first, file-based memory layer for AI agents — one shared Markdown vault across Claude, Codex, Gemini, Cursor and any MCP client. Provides read/write memory tools with an audit trail, per-agent trust levels, and Git sync; no cloud and no lock-in.2MIT
- AlicenseBqualityAmaintenanceagentcairn is a local-first memory MCP server: your agent's memories live as Markdown in an Obsidian vault you own — the source of truth — with a rebuildable DuckDB index providing fast hybrid BM25 + vector + graph recall. It exposes tools to capture, recall, and manage those memories (non-lossy, with secret redaction) and works the same across Claude Code, Codex, Cursor, and any MCP host.552Apache 2.0
- AlicenseNot gradedqualityAmaintenanceLocal-first, source-grounded memory for AI agents, with citations, bitemporal history, review-gated corrections, and MCP tools for search and recall.3Apache 2.0
- AlicenseNot gradedqualityAmaintenanceDurable memory with sources, proof, history, and review for MCP-capable agents. It turns a Markdown/Obsidian vault into a local knowledge substrate, enabling agents to store, search, and retrieve governed knowledge.10AGPL 3.0