Local-first memory, planning, knowledge graphs, and secure integrations for AI agents.
OpenMemory 0.2.0 combines persistent memory with project tasks, decision history, reusable workflows, registered resources, codebase graphs, design documents, cost forecasts, and credential-safe network tools. Data stays in your local services unless you explicitly configure an outbound workflow, LLM provider, HTTP request, or SSH action.
Current release: v0.2.1 · Release notes · License
| Capability | What it provides |
|---|---|
| Persistent memory | BM25 search, importance/recency ranking, tags, summaries, and explicit memory relationships |
| Temporal knowledge graph | Episodes, entities, time-valid facts, entity history, and graph-assisted retrieval |
| Environment parameters | AES-GCM encrypted settings and secrets with server-side credential use |
| Resource catalog | Discoverable local paths, URLs, tags, and linked account configuration |
| Projects and tasks | Roadmaps, subtasks, scheduling, routines, lessons, notes, and decision checkpoints |
| Project code graphs | Tree-sitter indexing, graph queries, node details, paths, hubs, and rebuilds |
| Reusable workflows | Stored HTTP and agent-assisted processes with resumable execution |
| Design workspace | Text, Mermaid, draw.io, React Flow, and OpenPencil documents with budget forecasts |
| Asset library | Searchable image, video, and live-code candidates, optionally scoped to projects |
| Session recording | Passive history for Claude Code, Gemini CLI, Codex CLI, and configurable AI-agent roots |
| Web dashboard | Memory, agents, projects, files, source control, designs, lessons, workflows, and settings |
- Docker with Compose v2
- Rust toolchain (to build the MCP and watcher binaries)
curlandjqfor thememCLI- Node.js and pnpm only for non-Docker web development
The API server and MCP process refuse to start without OPENMEMORY_SECRET_KEY. Keep the same value for both processes or encrypted environment values will be unreadable.
umask 077
OPENMEMORY_SECRET_KEY_VALUE=$(openssl rand -base64 48)
OPENMEMORY_API_TOKEN_VALUE=$(openssl rand -hex 32)
printf 'OPENMEMORY_SECRET_KEY=%s\nOPENMEMORY_API_TOKEN=%s\n' \
"$OPENMEMORY_SECRET_KEY_VALUE" "$OPENMEMORY_API_TOKEN_VALUE" > .env
unset OPENMEMORY_SECRET_KEY_VALUE OPENMEMORY_API_TOKEN_VALUEDo not commit .env.
docker compose up -d
docker compose psThis starts PostgreSQL, OpenSearch, Redis, and FalkorDB.
Start only the backend and its dependencies:
docker compose --profile api up -d openmemory-server
curl -s http://localhost:18080/healthExpected response:
{"status":"ok"}The API listens on 127.0.0.1:18080 by default. The CLI uses the same default.
export PATH="$PWD/scripts:$PATH"
set -a
source .env
set +a
mem save "The service uses Rust and PostgreSQL" \
--importance 0.7 --tags openmemory,architecture
mem search "service architecture" --limit 5
mem list --limit 20mem resolves its bearer token from OPENMEMORY_API_TOKEN, then ~/.openmemory/api_token. Override the server with OPENMEMORY_URL.
cargo build --release --bin openmemory-mcpConfigure an MCP-compatible client to run the binary with the same encryption secret as the API. This generic configuration loads the repository .env without copying the secret into the client configuration:
{
"mcpServers": {
"openmemory": {
"command": "/bin/bash",
"args": [
"-lc",
"set -a; source /absolute/path/to/openmemory/.env; exec /absolute/path/to/openmemory/target/release/openmemory-mcp"
],
"env": {
"DATABASE_URL": "postgres://openmemory:openmemory@localhost:5432/openmemory",
"OPENSEARCH_URL": "http://localhost:9201",
"FALKORDB_URL": "redis://localhost:6380"
}
}
}
}Replace both absolute paths. Restart the client session after rebuilding; an existing stdio MCP process cannot hot-reload new tools.
The complete API profile serves:
- dashboard: http://localhost:13000
- API: http://localhost:18080
- local draw.io editor/viewer: http://localhost:18081
- local OpenPencil embed: http://localhost:18082
The full profile expects compatible sibling checkouts by default:
parent/
├── openmemory/
├── drawio/
└── open-pencil/
Override their locations when necessary:
export DRAWIO_WEBAPP_PATH=/absolute/path/to/drawio/src/main/webapp
export OPEN_PENCIL_PATH=/absolute/path/to/open-pencil
export OPENMEMORY_ROOT="$PWD"
docker compose --profile api up -d --buildNEXT_PUBLIC_DRAWIO_EDITOR_URL, NEXT_PUBLIC_DRAWIO_VIEWER_URL, and NEXT_PUBLIC_OPEN_PENCIL_URL are compiled into the web bundle; rebuild the web image after changing them.
Store only durable facts, preferences, decisions, and constraints. Do not manually save conversation transcripts; the watcher handles them.
mem save "Use rustls in deployment images because OpenSSL is unavailable" \
--importance 0.8 --tags rust,deployment,decision \
--summary "TLS dependency decision"
mem search "deployment TLS" --limit 5
mem get <uuid>
mem delete <uuid>Use mem save ... --auto to fill only omitted importance, tags, or summary fields using the LLM configured under LLM Settings. Preview suggestions with:
mem autofill memory "<content>"
mem autofill task "<content>"
mem autofill resource "<content>"Autofill is optional and never overrides explicitly supplied fields.
Projects can be planning-only containers or linked to a local repository. MCP tools manage tasks, subtasks, dates, labels, status, and priority. Task notes are append-only and support human/agent decision checkpoints:
- decisions may be open questions or contain up to six choices;
- selection mode may be
singleormultiple; - answers may select options, include a custom reply, or both;
- re-answering preserves earlier answer history.
Use project_list to resolve a project ID, then project_task_list, project_task_create, project_task_update, and the project_task_note_* tools.
Routines materialize recurring work as dated tasks. The API server checks due routines in the background every five minutes by default; routine_check also supports an explicit or dry-run check.
Lessons store per-project corrections and conventions. Reusing a normalized title increments its occurrence count rather than adding a duplicate. Archive superseded lessons instead of deleting them.
mem lessons --project <uuid> --query "authentication" --limit 20Lesson writes use the MCP tools or authenticated REST routes; the CLI command is read-only.
Resources register source material: local paths, websites, tags, and the environment keys needed for an account. Search before adding to prevent duplicate catalog entries.
mem resource-list --query "design" --tags ui,reference
mem resource-tags
mem resource-get <id-or-name>
mem resource-add docs --kind path --location /absolute/path/to/docs \
--description "Project documentation" --tags project,docsThe asset library is for already-created image, video, or self-contained HTML/CSS/JS candidates. It catalogs and previews content; it does not generate or validate it.
Registering a project path indexes Rust, TypeScript, JavaScript, and Python with tree-sitter and records recognized files. MCP clients can:
- search a code graph with IDF-weighted, multi-hop traversal;
- inspect a node and its direct edges;
- find shortest paths and highly connected hubs;
- rebuild after code changes;
- delete the registered graph without deleting source files.
Workflows are ordered HTTP and agent-assisted processes configured in Settings → Workflows.
- Call
workflow_listto discover an existing process. - Call
workflow_getfor its input schema. - Call
workflow_runwith the workflow name/ID and input. - If the result is
action_required, perform the host-agent action and callworkflow_continuewith its structured result. - Repeat until
completed; execution stops on failure.
Inputs support text, JSON, image, PDF, generic file, and unrestricted values. HTTP nodes run server-side, so referenced credentials remain inside OpenMemory.
Projects linked to Git repositories can export database-backed project data to a .openmemory/ bundle:
.openmemory/
├── manifest.json
├── docs/
├── tasks/
├── routines/
└── lessons/
The bundle includes document metadata/content, tasks and decision history, routines, lessons, and design budgets. Import merges by stable ID and does not delete records absent from the bundle.
TOKEN="${OPENMEMORY_API_TOKEN:-$(tr -d '[:space:]' < ~/.openmemory/api_token)}"
BASE="${OPENMEMORY_URL:-http://localhost:18080}"
curl -s -X POST "$BASE/projects/<uuid>/sync" \
-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"action":"export"}' | jq .
curl -s -X POST "$BASE/projects/<uuid>/sync" \
-H "Authorization: Bearer $TOKEN" -H 'content-type: application/json' \
-d '{"action":"import"}' | jq .Inspect exported changes before committing. The web UI can create AI-assisted commit messages and commit/push selected files separately.
Forecast profiles capture application type, user count, budget, stress tolerance, usage shape, engagement, planning horizon, and growth. Design budgets attach auditable service line items, conditions, confidence, and pricing basis to a project document. Monthly totals are derived from costs stored in cents.
The design workspace supports:
- Markdown/text with Mermaid preview;
- Mermaid source;
- draw.io XML through a self-hosted editor;
- native React Flow architecture diagrams with AWS icons;
- OpenPencil documents through the local embed;
- AI diagram and budget suggestions when an LLM is configured.
OpenMemory 0.2.0 exposes 86 MCP tools:
| Group | Tools |
|---|---|
| Memory | memory_save, memory_search, memory_graph_neighbors, memory_graph_relate |
| Temporal graph | graph_add_episode, graph_add_entity, graph_add_fact, graph_query_facts, graph_query_at, graph_get_entity_history, graph_get_entity |
| Environment and secure actions | env_set, env_get, env_rename, env_list, env_delete, env_http_request, env_http_download, env_sign_jwt, env_http_request_jwt, env_set_file, env_google_service_account_request, env_ssh_execute |
| Resources | resource_list, resource_tags, resource_get, resource_add, resource_update, resource_delete |
| Asset library | library_add, library_list, library_get, library_delete |
| Project code graphs | project_graph_list, project_graph_create, project_graph_query, project_graph_node_detail, project_graph_shortest_path, project_graph_god_nodes, project_graph_delete, project_graph_rebuild |
| Workflows | workflow_list, workflow_get, workflow_run, workflow_continue |
| Forecasts | forecast_list, forecast_create, forecast_update, forecast_delete |
| Design budgets | design_budget_list, design_budget_create, design_budget_update, design_budget_delete |
| Projects and tasks | project_list, project_create, project_task_list, project_task_create, project_task_note_list, project_task_note_create, project_task_note_decide, project_task_update, project_task_delete |
| Lessons | lesson_create, lesson_list, lesson_update, lesson_delete |
| Routines | routine_check, routine_list, routine_create |
| QA | qa_event_create, qa_event_list, qa_event_update, qa_event_delete, qa_run_create, qa_run_update, qa_run_list, qa_run_delete, qa_evidence_add, qa_evidence_update, qa_evidence_delete |
| QA plans | qa_plan_create, qa_plan_list, qa_plan_update, qa_plan_delete — store test-script templates; OpenMemory never executes them |
| QA test history | qa_results_import, qa_case_history — record per-case results a test runner produced elsewhere, and trace one case across runs. OpenMemory never executes tests. |
See the bundled OpenMemory skill for agent operating guidance and safety rules, and the QA run skill for the workflow that records a QA pass and its evidence.
mem save <content> [--importance N] [--tags a,b] [--summary TEXT] [--auto]
mem search <query> [--limit N]
mem list [--limit N]
mem get <uuid>
mem delete <uuid>
mem autofill memory|task|resource <content>
mem env-set <key> <value> [--secret] [--description TEXT]
mem env-rename <old-key> <new-key> [--value VALUE] [--secret|--normal]
mem env-get <key>
mem env-list
mem env-delete <key>
mem resource-list [--kind path|url] [--query TEXT] [--tags a,b]
mem resource-tags
mem resource-get <id-or-name>
mem resource-add <name> --kind path|url --location <location> [...]
mem resource-update <uuid> [...]
mem resource-delete <uuid>
mem lessons [--project <uuid>] [--query TEXT] [--limit N]
mem sessions [--limit N]
mem sessions <uuid>
mem sessions messages <uuid> [--limit N] [--after N]
Run ./scripts/mem --help for every option.
Start passive recording separately or with the API profile:
docker compose --profile watcher up -d
docker compose --profile api --profile watcher up -dThe watcher mounts supported log directories read-only. Set WATCHER_POLL_INTERVAL_SEC=30 when filesystem events do not propagate through Docker bind mounts (common on Docker Desktop, macOS, and WSL).
mem sessions --limit 20
mem sessions messages <uuid> --limit 200
docker compose logs openmemory-watcherscripts/stack brings up OpenMemory alongside a sibling qa-automation checkout with one command:
./scripts/stack up # start both
./scripts/stack ps # containers for both
./scripts/stack down # stop both (volumes are never removed)The checkout stays an independent repository at its own path — nothing is vendored in. Override the location with QA_AUTOMATION_PATH (default ../qa-automation), the same convention DRAWIO_WEBAPP_PATH and OPEN_PENCIL_PATH use. SKIP_QA=1 operates on OpenMemory only, and a missing checkout is skipped with a warning rather than an error. COMPOSE_PROFILES selects the OpenMemory profiles (default api,watcher); it is not passed to the companion stack.
The two remain separate Compose projects deliberately. Do not merge them with include: or -f a.yml -f b.yml: both files define top-level postgres and redis, and Compose merges same-named services silently instead of erroring, yielding one container with OpenMemory's image and qa-automation's credentials. Merging also re-prefixes every volume to the combined project name, orphaning the existing qa-platform_{postgres,redis,minio}_data volumes. Separate projects also keep the blast radius apart — down on one cannot touch the other.
See docs/design/primitives.md for a conceptual reference on every agent-facing primitive (memory, temporal graph, env params, resources, tasks, lessons, workflows, and more) — what each one is and when to use it over its neighbors.
flowchart LR
Agent[MCP client] --> MCP[openmemory-mcp]
CLI[mem CLI] --> API[openmemory-server]
Web[Next.js dashboard] --> API
Watcher[session watcher] --> PG[(PostgreSQL)]
MCP --> PG
API --> PG
MCP --> OS[(OpenSearch)]
API --> OS
MCP --> FG[(FalkorDB)]
API --> FG
API --> Redis[(Redis cache)]
API --> Blobs[(design/library volumes)]
| Store | Purpose |
|---|---|
| PostgreSQL 17 | metadata, environment parameters, sessions, projects, planning records, workflows |
| OpenSearch 2.18 | full memory content and BM25 search |
| Redis 7 | optional search-result cache |
| FalkorDB | temporal entities/facts and memory relationships |
| Docker volumes | design, QA evidence, and uploaded library blobs |
The API container publishes only to 127.0.0.1 by default. The backing PostgreSQL, OpenSearch, Redis, and FalkorDB mappings use development credentials and currently publish on all interfaces. On a shared or network-exposed machine, prefix those mappings with 127.0.0.1: or put them behind equivalent network controls.
Authentication is applied per handler, not as global middleware. The health endpoint, legacy /mcp memory operations, and session-history reads are not bearer-gated. Project, workflow, library, design, agent-management, and other sensitive handlers enforce the API token individually; authenticated secret reads require it as well. Keep the API local and do not treat the bearer token as a substitute for network isolation.
Environment values are encrypted at rest with AES-256-GCM using a key derived from OPENMEMORY_SECRET_KEY. Secret values cannot be returned through MCP env_get; use their key names with server-side operations instead.
Use env_set_file for private keys, certificates, or service-account JSON so bytes never enter an agent tool call. Prefer:
env_http_requestfor authenticated text/JSON responses;env_http_downloadfor binary responses written to an absolute local path;env_http_request_jwtinstead of returning a live token fromenv_sign_jwt;env_google_service_account_requestfor Google OAuth service accounts.
Set OPENMEMORY_HTTP_ALLOWED_HOSTS to constrain credential-bearing outbound HTTP requests.
env_ssh_execute is fail-closed unless OPENMEMORY_SSH_ALLOWED_HOSTS permits the target. Pin each server with <ssh_key_key>.host_key_fingerprint; optionally bind a key further with <ssh_key_key>.allowed_hosts. SSH execution has no PTY, forwarding, agent forwarding, or password authentication.
OPENMEMORY_SSH_ALLOW_UNKNOWN_HOST_KEY=1 is an emergency development bypass, not a production setting.
Back up PostgreSQL first. Preview and then perform a transactional rotation:
OPENMEMORY_OLD_SECRET_KEY='<old>' \
OPENMEMORY_NEW_SECRET_KEY='<new>' \
DATABASE_URL='postgres://openmemory:openmemory@localhost:5432/openmemory' \
cargo run --release --bin openmemory-server -- rotate-secret-key --dry-run
OPENMEMORY_OLD_SECRET_KEY='<old>' \
OPENMEMORY_NEW_SECRET_KEY='<new>' \
DATABASE_URL='postgres://openmemory:openmemory@localhost:5432/openmemory' \
cargo run --release --bin openmemory-server -- rotate-secret-keyUpdate both the API and MCP configuration to the new key after rotation.
# Rust checks
cargo fmt --check
cargo test --workspace
cargo build --release
# Web checks
pnpm install
pnpm --filter web build
# Run the web workspace in development mode
pnpm devRepository layout:
openmemory/
├── apps/server/ Rust API, MCP server, and watcher
├── apps/web/ Next.js dashboard
├── skills/openmemory/ bundled agent skill
├── skills/qa-run/ QA run + evidence recording skill
├── scripts/mem command-line client
├── docker/ local editor/embed support
├── docs/ architecture, design, and implementation notes
│ └── version/ release summaries
├── vendor/ patched third-party crates (see vendor/README.md)
└── docker-compose.yml local service stack
Back up the Docker volumes for PostgreSQL, OpenSearch, FalkorDB, design blobs, QA evidence blobs, and library blobs. Redis is a cache and is not required for recovery. Preserve OPENMEMORY_SECRET_KEY; losing it makes encrypted environment values unrecoverable.
Project .openmemory/ exports are useful Git-friendly mirrors of planning/design data, but they are not a complete database backup.
docker compose --profile api ps
docker compose logs openmemory-server
curl -s http://localhost:18080/healthConfirm .env contains a non-empty OPENMEMORY_SECRET_KEY.
- use absolute paths in client configuration;
- verify
cargo build --release --bin openmemory-mcpsucceeded; - ensure MCP and API use the same
OPENMEMORY_SECRET_KEY; - verify PostgreSQL and OpenSearch are healthy;
- restart the MCP client session after rebuilding.
docker compose ps postgres opensearch
curl -s http://localhost:9201
docker compose logs opensearch- confirm the relevant host log directory exists;
- inspect
docker compose logs openmemory-watcher; - set
WATCHER_POLL_INTERVAL_SEC=30when bind-mount notifications are unreliable; - check container read permissions for the mounted directories.