Architecture
personal-memory’s job is not to be the memory — it is to let you run whichever memory system you choose on one machine with shared indexing and setup. A shared indexer writes into the active provider; coding agents reach that API through unified memory_* MCP, in-repo session hooks, and optional native paths (Hindsight plugin, mem0/Cognee MCP). Only one provider is active at a time; npx personal-memory switch rewires the stack without pretending to migrate your data. Setup (npx personal-memory) is install plumbing only — not part of the runtime data path.
Runtime data flow
Section titled “Runtime data flow”Two paths share one active provider API (Hindsight, mem0, or Cognee — never more than one). Setup (npx personal-memory) is not on this diagram; see How personal-memory interfaces with providers.
| Path | What moves |
|---|---|
| Indexing | Git, Obsidian, markdown trees, feed cache → indexer → provider HTTP sink (MEMORY_SINK from manifest) |
| Agents | Cursor/Claude/Codex → session hooks and/or MCP → same provider API |
| Unified MCP | install-mcp registers personal-memory on the host; tools delegate to the active provider |
| LiteLLM | Optional sidecar on Hindsight stacks; also used for cross-provider reflect synthesis when PM_LLM_URL / stack LiteLLM is reachable (memory_reflect on mem0/Cognee) |
| NotebookLM sync | Opt-in, any active provider. Background sync writes into notebooklm::* via the same indexer sinks (Hindsight / mem0 / Cognee); not the same as the NotebookLM MCP |
| Provider MCP | Native mem0 or Cognee tool names (install-mcp --provider-only); same API as unified MCP, different stdio server |
| NotebookLM MCP | Read-only list/search over synced notebooks; separate entry in mcp.json, not a memory provider |
Only one provider is active at a time (MEMORY_PROVIDER). The indexer uses that provider’s HTTP sink (MEMORY_SINK / manifest).
How personal-memory interfaces with providers
Section titled “How personal-memory interfaces with providers”personal-memory is a meta layer: it does not replace provider APIs. It wires the same plumbing (indexer, compose, wizard, MCP) to different backends through manifests and thin adapters.
Integration layers
Section titled “Integration layers”| Layer | What it is | Repo location |
|---|---|---|
| Manifest | Status, compose services, ports, indexer sink id, smoke HTTP templates | providers/<id>/manifest.json |
| Wizard hooks | Provider-specific env, keys, smoke, coding-agent notes | providers/<id>/wizard.mjs |
| Indexer sink | Poll/vault → retain/update/delete on the provider API | indexer/ (driver id in manifest, e.g. hindsight-rest-v1, mem0-rest) |
| Unified MCP | Stable memory_* tools → provider HTTP |
cli/mcp/memory-facade.mjs, cli/personal-memory-mcp.mjs |
| Native agent paths | Session hooks + optional plugin/MCP | cli/coding-agent/hook-runner.mjs; optional Hindsight plugin; cli/mem0-mcp.mjs, cli/cognee-mcp.mjs, NotebookLM |
Adding a provider means a new manifest + hooks + sink driver; agents can keep using memory_* once the facade implements that backend.
Runtime wiring (env and config)
Section titled “Runtime wiring (env and config)”| Input | Resolves |
|---|---|
MEMORY_PROVIDER |
Active backend (wizard.conf, optional config.toml) |
Stack .env |
API URLs, ports, MEMORY_SINK, indexer → provider URL |
| Provider secret files | e.g. ~/.config/personal-memory/mem0.env (never committed; not written to mcp.json) |
~/.config/hindsight/index.yml |
What the indexer watches |
npx personal-memory switch <id> updates provider selection and restarts compose; it does not migrate memories (export/import is for that).
Example: unified MCP on mem0
Section titled “Example: unified MCP on mem0”npx personal-memory switch mem0 --yes— compose and env point the indexer and unified MCP atMEM0_API_URL.npx personal-memory install-mcp --yes— merges thepersonal-memoryserver into~/.cursor/mcp.json(NotebookLM MCP only if you enabled sync or pass--notebooklm).- The agent calls
memory_addwith{ content: "…", bank: "my-project" }. The facade sendsPOST /memorieswithuser_id=my-projectandinfer: false.
install-mcp --provider-only is a different stdio server: same mem0 API, but upstream mem0 tool names from @yeyuan98/mem0-mcp. NotebookLM MCP is different again — search over notebooks synced into Hindsight, not a substitute for mem0/Cognee/Hindsight memory.
Unified MCP → provider HTTP
Section titled “Unified MCP → provider HTTP”The personal-memory MCP server delegates each tool to the active provider:
| Unified tool | Hindsight (HINDSIGHT_URL) |
mem0 (MEM0_API_URL + key file) |
Cognee (COGNEE_API_URL) |
|---|---|---|---|
memory_add |
POST /v1/default/banks/{bank}/memories |
POST /memories (infer: false, user_id from bank arg) |
POST /api/v1/add |
memory_search / memory_recall |
POST /v1/default/banks/{bank}/memories/recall |
POST /search with filters.user_id |
POST /api/v1/search |
memory_reflect |
Same recall path | Search + optional LiteLLM synthesis | Search + optional LiteLLM synthesis |
memory_consolidate |
LiteLLM / Hindsight consolidate routes | Skipped (no equivalent) | POST /api/v1/cognify |
memory_forget |
DELETE /v1/default/banks/{bank} (bank scope) |
DELETE /memories/{id} |
Not exposed yet |
memory_provider_status |
Returns provider id + loopback URL | Same | Same |
memory_export / memory_import |
PMM envelope; mem0 list/add — see Memory portability |
Default scope key for MCP-created rows: bank / user_id personal-memory-mcp unless the tool passes bank.
Native agent paths (optional, alongside unified MCP)
Section titled “Native agent paths (optional, alongside unified MCP)”| Provider | Session / tools | Install |
|---|---|---|
| All providers | In-repo session hooks → unified memory_* |
install-coding-agent --yes |
| Hindsight (optional) | @vectorize-io/hindsight-coding-agents plugin |
install-coding-agent --hindsight-plugin |
| mem0 | @yeyuan98/mem0-mcp tools |
install-mcp --provider-only |
| Cognee | cognee_health, cognee_search |
install-mcp --provider-only |
| NotebookLM | notebooklm_list_banks, notebooklm_search |
install-mcp when sync enabled or --notebooklm |
install-mcp merges the unified personal-memory server by default (--no-unified-mcp to skip).
How file changes become memory
Section titled “How file changes become memory”The indexer does not watch your editor — it watches configured sources on disk (poll, inotify, or periodic re-list).
| Source | Detection | What gets sent to the provider |
|---|---|---|
| Git repo | Poll every poll_seconds (default 60): HEAD + tracked-file status |
Tree-sitter outlines + text for changed files → retain on the active sink |
| Obsidian vault | inotify; re-index after vault_quiet_seconds (default 30) without edits |
Vault documents → provider-specific banks |
| Notes / papers / bookmarks | notes.paths, papers.paths, bookmarks.paths; inotify on .md (bookmarks also .html, .txt) |
Markdown (and bookmark exports) → notes::, papers::, bookmarks:: banks |
| Feed cache | feeds.out_dir after npx personal-memory feed-sync (RSS / OpenAlex) |
Generated markdown → feed:: banks |
| New sources under scan roots | Re-list every relist_seconds (default 600) |
Picked up without restarting the stack |
Configuration: ~/.config/hindsight/index.yml (wizard writes this on first setup). Full source list and examples: index-sources.md · sources-feeds.md · sources-zotero.md · sources-readwise.md. Filters such as optInPaths in ~/.hindsight/coding-agent.json can limit which discovered sources are indexed.
Bank prefixes include coding-agent::, obsidian::, notes::, papers::, bookmarks::, feed::, and optional notebooklm::*. mem0 uses user_id / agent_id / run_id; Cognee uses datasets mapped from indexer banks.
Industry context
Section titled “Industry context”There is no cross-vendor standard for agent memory APIs. MCP standardizes tool transport, not memory semantics — each product exposes different tool names and shapes. personal-memory’s answer is a stable facade on your chosen backend so agents keep the same verbs when you switch providers.
Unified personal-memory MCP (beta)
Section titled “Unified personal-memory MCP (beta)”cli/personal-memory-mcp.mjs registers as the personal-memory server in ~/.cursor/mcp.json when you run install-mcp (unless --no-unified-mcp). It delegates to the active provider:
| Tool | Purpose |
|---|---|
memory_add |
Store text (Hindsight bank, mem0 user scope, Cognee dataset add) |
memory_search / memory_recall |
Query memories on the active backend |
memory_reflect |
Session-style context (recall or search + optional LiteLLM) |
memory_consolidate |
Cognee cognify; Hindsight notes; mem0 skip |
memory_forget |
Delete by id (mem0) or drop a Hindsight bank |
memory_provider_status |
Active provider and loopback URL (no secrets) |
memory_export / memory_import |
PMM portable format — Memory portability (mem0 beta) |
Session hooks (all providers) call the unified MCP via cli/coding-agent/hook-runner.mjs. Optional @vectorize-io/hindsight-coding-agents with --hindsight-plugin adds a second hook set on Hindsight stacks.
Other MCP integrations
Section titled “Other MCP integrations”| Integration | Tools / path | Role |
|---|---|---|
| Session hooks | SessionStart / prompt / Stop → memory_* |
Default in-IDE session memory (all providers) |
| Hindsight plugin (optional) | Upstream retain / recall / reflect | --hindsight-plugin only |
notebooklm (install-mcp) |
notebooklm_list_banks, notebooklm_search |
Opt-in synced notebooks |
mem0 (--provider-only) |
mem0 REST tools via @yeyuan98/mem0-mcp |
Native mem0 tool names |
cognee (--provider-only) |
cognee_health, cognee_search |
Native Cognee read-only MCP |
Related
Section titled “Related”- Memory portability — PMM export/import
- Provider status — manifest status and ports
- mem0 operator guide — URL-only mem0 setup
- Cognee operator guide — loopback container + LLM env
- Configuration file —
config.tomlfor provider and stack defaults
Developer docs (wizard phases, hooks, manual compose, indexer sinks, MCP install modes) live in the git repository under docs/ and are not published on this site. See also Pluggable memory providers.
This page is generated from docs/architecture.md in the repository.