dokoro is a persistent brain for your LLM agent — five memory layers, each answering a different question, so the agent recalls the right kind of memory instead of the most textually similar one.
Working · episodic · semantic · procedural · affective — with bi-temporal facts and a track record of which tools to trust.
SQLite + LanceDB built on the MCP TypeScript SDK MIT byPawel/dokoro
On npm as dokoro. One command — no clone, no build. Each project gets its own isolated memory in ./dokoro, so sessions, entities and tool-trust never leak between repos.
# add dokoro to the current project (Claude Code, or any MCP client) claude mcp add dokoro -- npx -y dokoro # CLI subcommands npx dokoro init # scaffold the .dokoro workspace npx dokoro migrate # run DB migrations npx dokoro browse # interactive memory browser (TUI) # lean install — skip the ~100MB native vector deps (lazy-loaded) npm install --omit=optional
Most memory plugins dump everything into one vector store and retrieve by fuzzy similarity. dokoro follows the CoALA taxonomy used by Letta, Zep and Mem0: each layer owns a different question, a storage home, and its own tools — so the agent fetches the right kind of memory, not the most textually similar one. Each layer is also retained for a different span — from a single task to all-time.
Agent memory has moved through four generations — from no memory at all, to one big similarity bucket, to tiered OS-like memory, to temporal graphs. dokoro sits at the current edge: function-separated layers, bi-temporal facts, and an affective layer that learns which tools to trust.
An agent's only memory was its prompt — wiped at the end of every session. It re-learned the codebase, re-discovered decisions, and repeated tools that had already failed. Nothing persisted.
"Memory" became a single embedding index: dump everything in, pull back the most textually similar chunks. Useful, but undifferentiated — a stale plan, a one-off fact and a failed-tool note all compete in the same fuzzy ranking.
Borrowing from virtual memory: a small in-context "core" plus a large archival store the agent pages in and self-edits. Structure arrives — but the tiers are about size and recency, not about what kind of thing is being remembered.
Facts became first-class and time-aware: entities and relations with validity windows, so you can ask what the graph believed at a past moment instead of overwriting history. Memory gains a timeline.
dokoro keeps the temporal graph (bi-temporal relations) and adds two moves no popular OSS lib makes together: memory split into five purpose-built layers (CoALA), and an affective layer that records every tool outcome and turns it into a routing policy — so the agent learns which tools and models to trust, not just what it once saw.
The server stores and serves; the agent reads and writes. A Claude Code session forms a loop across the layers — resume informed, act, reflect, and persist what was learned for next time.
Every tool outcome is recorded; the agent asks dokoro_feedback_route for a ranked track record and biases itself accordingly. No other popular OSS memory library — Mem0, Letta, Zep, Cognee, LangMem — does this natively.
# MCP tools/call — ranked routing for this agent { "name": "dokoro_feedback_route", "arguments": { "agent_id": "claude-code", "half_life_days": 14 } } dokoro_session_recall n=89 decayed_rate=1.000 wilson_lower=0.9583 confident=true dokoro_entity_extract_deep n=142 success=125 timeout=15 wilson_lower=0.8213 confident=true
Ranking uses a Wilson lower bound on the success rate — a single lucky success can't outrank a long, proven record. The agent prefers the higher wilson_lower.
Stale failures fade via half_life_days — an outcome from three months ago counts for less than one from yesterday.
A confident flag flips true only once a tool clears the minimum sample size. Raw aggregates stay in dokoro_feedback_query.
Every entity_relations row carries valid_from / valid_to (Zep / Graphiti-style). Facts are never destructively overwritten — a superseded fact has its window closed and a new slice opens. Drag as_of to query the graph at any point in time.
Window-closing on supersession is active for single-valued relations; genuinely many-valued relations like depends_on accumulate concurrent open facts instead of evicting each other. History is never deleted — it only stops surfacing in the default "now" view.
Structured data in SQLite, vectors in LanceDB, human-readable state on the filesystem. Hybrid search fuses FTS5 + vectors by Reciprocal Rank Fusion; an optional local LLM (Ollama) adds embeddings and deep extraction — the server runs fine without it.
tachibot-mcp does the thinking; dokoro remembers it. Three opt-in bridge tools (DOKORO_ENABLE_TACHIBOT_BRIDGE=true) land each model's stateless output in the right layer — and feed it back into the next decision. Want the pair wired together out of the box? tachi-agent is the local-first orchestrator that fuses dokoro memory with the tachibot council.
npx dokoro browse is a terminal dashboard over the whole memory folder — ten categories, from the live workspace and plans to file claims, agent presence, open questions and the affective feedback ledger. File watchers and pollers keep every list live, changed preview lines flash, / fuzzy-filters, s runs hybrid FTS5+vector search, and ? overlays every keybinding.
dokoro › File claims ────────────────────────────────────────── ▸ src/auth/session.ts alice · live · 4m left src/cli/browse-ui.tsx bob · stale · expired ────────────────────────────────────────── ↑/↓ move · enter open · r release · ? help · 1/2 ⚑ holder is live — not releasing
Read everywhere, write only where gated. A multi-model council rejected command palettes, multi-select and inline editing — a coordination dashboard must never race the agents it watches.
r releases a stuck file claim only when the holder's heartbeat is stale past the 900s TTL or the lease expired. A live holder is refused — no force flag exists.
p advances a plan one legal step (draft→active→completed). The plan is re-read before writing; if its status drifted since you confirmed, the write aborts.
Filter the toolset by the memory layer it reads or writes. Core tools ship on core-server.js; analytics and bridge tools register on their own servers.
Four capabilities set dokoro apart — bi-temporal facts, per-agent affective feedback, workspace lock coordination, and WAL concurrency — all queryable as plain MCP tool calls or visible directly in the SQLite schema.
| Project | Architecture | Native temporal | Native affective | Native multi-agent | Concurrent access |
|---|---|---|---|---|---|
| dokoro | SQLite + LanceDB + entity graph | ✓ bi-temporal | ✓ agent_feedback | ✓ shared editable blocks + handoff + advisory file claims | ✓ WAL + busy_timeout=5000 |
| Mem0 | Vector + optional graph | — | — | — | — |
| Letta (MemGPT) | Tiered, OS-like, self-editing | ◐ via metadata | ◐ via metadata | ◐ shared blocks | — |
| Zep / Graphiti | Temporal knowledge graph | ✓ bi-temporal | — | — | — |
| Cognee | Graph + vector poly-store | ◐ partial | — | — | — |
| LangMem | Modular over LangGraph | — | — | — | — |
Layer-driven, gracefully degrading, and built on the MCP TypeScript SDK.
Five layers along the CoALA taxonomy — the agent retrieves the right kind of memory, not the most similar text.
Supersession closes a fact's valid_to window and opens a new slice. as_of replays the graph at any moment.
Wilson lower bound + recency decay turn per-tool records into a routing signal the agent can trust.
SQLite for structure, LanceDB for vectors, files for human-readable state — fused by Reciprocal Rank Fusion.
No local LLM? Regex extraction takes over and recall falls back to recency. Nothing hard-fails.
Three opt-in tools wire tachibot's multi-model output into memory. Disabled by default.
Advisory per-file leases (dokoro_file_claim, default 300s) so agents sharing a worktree see who is editing what. Conflicts warn — they never block — and expired or dead-holder claims are taken over.
A live terminal dashboard over all ten memory categories — questions and feedback included — with ? help, fuzzy filter, hybrid search, and gated actions: release a stale claim, advance a plan. Falls back to a static summary when not a TTY.
Isolation is a ruled invariant, not a default: one memory per project, cross-project writes forbidden, no registry, no --all. Sandboxes and CI get an explicit path — memory never leaks between repos.