One local setup. Pick your agent memory backend.
personal-memory wires up indexing and compose for the memory API you pick. Agents use that provider’s plugin or MCP; this repo is plumbing, not a replacement memory product. Supported: Cognee, Hindsight, mem0.
Sources
- Git repositories
- Obsidian vaults
- Notes · papers · bookmarks
- Feed cache (RSS / OpenAlex)
Shared indexer
- Tree-sitter code outlines
- Poll repos · watch folders
- Sink → active provider API
Memory provider
- CogneeSupported
- HindsightSupported
- mem0Supported
- GraphitiPlanned
- LettaPlanned
- ZepPlanned
MCP & plugins (host)
- personal-memory MCP (memory_*)
- Session hooks (all providers)
- Provider MCP (mem0/Cognee, optional)
- NotebookLM MCP (optional)
Coding agents
- Claude Code
- Codex
- OpenCode
memory_* MCP and session hooks on the host; optional provider-native MCP and NotebookLM MCP. LiteLLM is optional on Hindsight stacks (not shown). Optional upstream Hindsight plugin (@vectorize-io/hindsight-coding-agents) via --hindsight-plugin.Architecture.What it does
Indexer, wizard, smoke tests, and MCP registration. Models and memory semantics stay with the provider you chose.
Pluggable providers
Hindsight, mem0, Cognee, or the next manifest entry. One wizard and indexer; `npx personal-memory switch` rewires compose and MCP. Data stays on each backend until you export/import yourself.
Setup wizard
Preflight, ports, index sources, compose up, health check, smoke retain/recall. Provider hooks in `providers/*/wizard.mjs` add only backend-specific steps.
Compose on loopback
Hindsight publishes API and control on 127.0.0.1. LiteLLM stays on the Docker network as Hindsight’s model proxy.
Multi-source indexer
Git repos (poll), Obsidian vaults, notes/papers/bookmarks folders, and RSS/OpenAlex feed cache (inotify). Tree-sitter outlines for code. One sink for the active provider.
Indexer secret masking
Home is mounted read-only; generated compose overrides hide common credential paths. Writable storage is a named volume.
Smoke test
Temporary bank retain/recall/delete after health passes. Idempotent reruns report changed=0 when nothing moved.
config.toml
`~/.config/personal-memory/config.toml` for provider and ports. Day-2: up, down, doctor, install-mcp, switch.
Unified MCP
`install-mcp` registers `personal-memory` with stable `memory_*` tools against the active API. Provider-native MCP (`--provider-only`) and NotebookLM MCP are separate servers.
Manifest-driven site
Provider status badges and copy on this site are generated from `providers/*/manifest.json` at build time.
NotebookLM (opt-in)Opt-in
Compose profile syncs into the active provider; optional MCP for list/search. Off until you enable sync.
How a run goes
Pick a provider
Run the wizard and choose a stack action and a memory provider. Defaults come from your config file.
Configure
The wizard checks Docker and ports, writes env files with mode 600 outside the repository, and wires the provider.
Start the stack
It builds the indexer only when its inputs changed, starts Compose, and waits for the health check.
Index
The indexer reads index.yml, finds repositories and vaults, and writes them to the active provider.
Smoke test
A retain and recall round trip in a temporary bank confirms the provider answers before you rely on it.
Providers
Status and ports come from providers/*/manifest.json at build time. Supported means the manifest says production-ready.
| Provider | Id | Status | Self-host | Native docs |
|---|---|---|---|---|
| Cognee | cognee | Supported | Docker Compose services: cognee, indexer. Default host port 8766 (COGNEE_PORT).Self-hosted graph/RAG memory run as a pinned cognee/cognee image (single container, SQLite + LanceDB + Ladybug) on a loopback port in single-user mode (no authentication). Ingestion is asynchronous: the indexer adds documents, then requests cognify once per changed dataset, so a document is searchable only after the graph is built (OpenAI-compatible LLM_API_KEY, or LLM_PROVIDER=ollama with matching ollama embeddings). No coding-agent plugin — agents use the REST API on the loopback port (/docs). | docs.cognee.ai |
| Hindsight | hindsight | Supported | Docker Compose services: litellm, hindsight, indexer. Default host port 8888 (HINDSIGHT_PORT). | github.com |
| mem0 | mem0 | Supported | Docker Compose services: indexer. Default host port 18888 (MEM0_PORT).URL-only v1: the operator runs a mem0 REST server and this stack points the shared indexer at it; no mem0 container yet (docker mode is a follow-up). Operator runbook: providers/mem0/OPERATOR.md. Not api.mem0.ai. The API key lives in ~/.config/personal-memory/mem0.env (mode 600), never the stack .env. The wizard.* HTTP fields below are informational: the wizard's smoke hook replaces the generic HTTP smoke (it needs an X-API-Key header), and deletePath is admin-only upstream, so the hook deletes by memory id instead. | none listed |
| Graphiti | graphiti | Planned | Not wired yet: no compose services declared.Placeholder for Zep Graphiti temporal knowledge graph backend. | help.getzep.com |
| Letta | letta | Planned | Not wired yet: no compose services declared.Placeholder manifest. Letta (formerly MemGPT) server integration is not wired; track via issues before changing status. | docs.letta.com |
| Zep | zep | Planned | Not wired yet: no compose services declared.Placeholder manifest. Zep Cloud/self-hosted API integration is not wired; track via issues before changing status. | docs.getzep.com |
Works today. Up next.
Shipped features and manifest-driven gaps. No dates.
Works today
- Interactive and non-interactive wizard: configure, start, stop, --yes, --dry-run
- Provider manifests drive this site: supported today: Cognee, Hindsight, mem0
- Hindsight stack through Docker Compose, with a LiteLLM proxy in front of lemond, Ollama, or a custom endpoint
- mem0 (URL-only) and Cognee (pinned Docker image) compose profiles with provider wizard hooks and indexer sinks
- Indexer for git repositories and Obsidian vaults, with tree-sitter outlines and secret-path masking
- Smoke retain and recall, and an idempotent rerun that reports changed=N
- Declarative config.toml and npx personal-memory tasks: up, down, doctor, install-mcp, switch
- Unified personal-memory MCP (memory_add/search/recall/forget, PMM export/import) via install-mcp
- Opt-in NotebookLM sync; install-mcp also registers the NotebookLM MCP when enabled
- Provider-native MCP (mem0/Cognee) still available with install-mcp --provider-only
Up next
- PMM import: mem0 duplicate detection; richer Cognee export (full document text)
- Graphiti: manifest status is planned
- Letta: manifest status is planned
- Zep: manifest status is planned
- Live end-to-end runs against real mem0 and Cognee servers (required before supported)
- Further npm releases
Install
You need Docker with Compose v2, Node.js 20.12 or newer, and a model server for the provider you pick (for Hindsight: lemond, Ollama, or an OpenAI-compatible endpoint).
With npxPublished
Day-0 and day-2 commands. install-mcp registers the unified memory_* MCP; Hindsight session memory still uses the coding-agent plugin.
npx personal-memory
npx personal-memory up
npx personal-memory install-mcp --yes
npx personal-memory switch mem0 --yesFrom sourceWorks today
Clone and use npx . for the same CLI. Add --dry-run first to see what setup would do without writing anything.
git clone https://github.com/bcmyguest/personal-memory.git
cd personal-memory
npm install && npx . setupSecurity notes
Loopback binds
The Hindsight API (127.0.0.1:8888) and control plane (127.0.0.1:9999) publish on loopback only. The LiteLLM proxy is on the internal Docker network and is not published.
Secret masking in the indexer
The indexer sees your home directory read-only. A generated compose.override.yaml masks secret paths such as ~/.ssh and ~/.gnupg. Only paths that exist when it is generated are masked, so rerun the generator after adding a secret directory.
Secrets stay out of the repository
Env files live under ~/.config/hindsight with mode 600. LiteLLM routes read keys from environment variables, so route YAML holds no secrets.
Nothing leaves the machine unless a provider says so
Indexed text goes to the provider and the model server you configured. A hosted model route or the NotebookLM sync sends data to those services; a local route does not.
This site
Static pages with self-hosted fonts: no analytics and no third-party requests. The build fails if the output contains home paths, private IPs, host aliases, or secret-style assignments.