Memory + identity + judgment for AI agents. One SQLite file. Zero API cost.
Runs two ways:
npm install && npm start.node server.mjs exposes an HTTP
API with optional bearer-token auth on writes, shared DB across MCP
clients, agent-to-agent mail, capability registry, runtime identity
switching for operator sessions.One codebase, two deployment patterns. Library-mode users can ignore the
service-mode tools entirely (the mail_*, capability_*, agent_* MCP
surface).
claude plugins marketplace add github.com/andrkelemen/wmem
claude plugins install wmem@wmem
The plugin registers the MCP server on first run via a Setup hook, wires the SessionStart / SessionEnd / PreCompact hooks, ships two skills (using-wmem, wmem-compact-protocol) that auto-load, and exposes slash commands (/recall, /chunks, /projects, /wmem-doctor). Then run the one-time setup to import + index + create a personality:
git clone https://github.com/andrkelemen/wmem.git ~/wmem
cd ~/wmem
node scripts/setup.mjs --agent myname
git clone https://github.com/andrkelemen/wmem.git
cd wmem
node scripts/setup.mjs --agent myname
Same setup script does everything: npm install, import your CLAUDE.md, index your sessions, create a personality, register the MCP server via claude mcp add, register the hooks via ~/.claude/settings.json.
Preview first with --dry-run:
node scripts/setup.mjs --agent myname --dry-run
AI agents forget. Every compaction, every restart — knowledge is lost. wmem fixes this with a layered memory system, hybrid search, and three features nobody else has:
node scripts/setup.mjs --agent myname
Detects OS, installs deps, imports existing files, indexes sessions, creates personality, registers MCP server. Linux, macOS, Windows.
Multi-stage retrieval in one SQLite file. memory_search auto-routes based on what's in the DB — hybrid when vectors exist, tag-boosted FTS5 otherwise.
^0.1.9 — fine for personal-scale; flag before broader deployment)scripts/benchmark-experimental.mjs for offline runs; off in the interactive MCP pathBenchmark scripts are in scripts/ for anyone who wants to measure on their own workloads.
Switch who the agent IS. Each personality has its own memories, voice, capabilities, and decision thresholds.
node scripts/personality.mjs create dev --template coder
node scripts/personality.mjs create planner --template architect
node scripts/personality.mjs use dev # instant switch
node scripts/personality.mjs update dev --voice "Terse. No hedging." # tweak in place
node scripts/personality.mjs create dawn --interactive # guided Q&A
Built-in templates: coder, architect, reviewer, writer, researcher, confidant.
Eleven commands cover the full lifecycle: list, use, create (with --template and/or --interactive), update, show, active, delete, templates, import, export. See docs/personalities.md for the full reference, the JSON export schema, and how personality files / decision config layer on top.
Export/import as JSON. Share personalities between machines.
Deterministic silence decisions. Asking an LLM whether to speak makes the model the judge of its own output — the decision and the output get coupled. Move the decision into a state machine with auditable thresholds instead. Don't ask the model. Build a state machine.
Four output modes:
Each personality defines its own thresholds:
{
"decision": {
"actionThreshold": 0.6,
"cooldownMinutes": 15,
"quietHours": [1, 7],
"salienceModifiers": { "error": 1.3, "task_failed": 1.5 },
"responseStyle": { "maxWords": 10, "register": "technical" }
}
}
Same event, different personality, different behavior. Coder stays silent during focus. Researcher proactively shares findings. Writer barely speaks at all.
Relationships emerge from co-occurrence. No graph database.
# "What relates to authentication?"
graph_related → direct tag matches + co-occurring chunks from same sessions
# "What topics appear alongside auth?"
graph_topics → deployment (63 sessions), config (68), api (64)
# "How does auth relate to deployment?"
graph_path → strong (10 shared sessions), connecting chunks shown
Four node types: topic, directory, project, agent. Unified kg_relations table with typed edges. Directories auto-detect project from git remote. Related directories discovered by shared project, tag overlap (3+), or time proximity (24h).
Pure SQLite queries over existing tags + sessions tables. <50ms.
Cross-personality shared memory with privacy controls.
_shared — all personalities see it (projects, decisions, facts)private — only this personality (conversations, session history)personal — locked, cannot be shared. Ever.memory_share copies to shared. memory_personal locks permanently.
Import whatever you already have. No reformatting.
# Dry run — preview sections + classifications
node scripts/setup.mjs --agent myname --dry-run
# Handles: markdown (.md), plain text (.txt), CLAUDE.md section splitting
# Classifies: personality vs memory vs config (with confidence scores)
# Low confidence → flagged for review, not guessed
# Atomic: whole file imports or none (SQLite transaction)
# Source tracing: file + section + line number in metadata
25 topic + action patterns, generated on insert. No manual organization.
Tags: auth, debugging, deployment, decision, fix, shipped, api, database, performance, security, frontend, testing, config, networking, automation, observability, and more.
Auto-generated context loaded on every session start. Zero API cost.
TEMPORAL ANCHOR: Today, agent age
PERSONALITY: System prompt + voice + always-load files
CAPABILITIES: Manually maintained list
RECENT SESSIONS: Time-windowed compression (2h/6h/18h)
CROSS-FOLDER PICK-UP: "you were also working on X in another folder" (v1.3)
PROJECTS: Active/shipped/blocked state
~1,200 tokens. >95% of context window stays free.
The CROSS-FOLDER PICK-UP section is fed by session_bookmarks (written
on SessionEnd by scripts/session-end-bookmark.mjs) and surfaces
parallel work from other directories — same project, shared topics, or
recent time overlap.
Named documents per personality (identity notes, preferences, style guides). Stored in DB, travel with personality on export.
Mark as always_load: true → injected into L1 every session.
Run one canonical master + N read-only mirrors without forking the dataset.
master / mirror / unknown at first boot (default master for single-user; override WMEM_ROLE=mirror on follower boxes). Non-master writes get 403 wmem_role_not_master./api/wmem/role — clients check before writing; surfaces hostname + set-by metadata.POST /api/write dispatcher — single endpoint covering 22 admin ops (projects, sessions, personality core/traits, memory share). One server-side allowlist, one gate, no per-op route sprawl.wmem-outbox daemon — local proxy at :18421. MCP/scripts post writes to it instead of straight upstream. Forwards while master reachable, buffers to local SQLite when not, drains on reconnect with exponential backoff + dead-letter. Survives upstream outages without losing writes.Library-mode users see no change — master is auto-stamped, writes work as before. Multi-instance topologies opt in by setting WMEM_ROLE=mirror on followers and running modules/wmem-outbox/install/install.sh on each.
See modules/wmem-outbox/README.md and migrations/0010_wmem_role.sql.
| What | Default | Set via |
|---|---|---|
HTTP server (node server.mjs) | 18420 | PORT= env, or port in wmem.config.json |
| Outbox daemon listen | 18421 | WMEM_OUTBOX_PORT= env, or outboxPort in wmem.config.json |
| Outbox → upstream | 127.0.0.1:18420 | WMEM_UPSTREAM_HOST= + WMEM_UPSTREAM_PORT= env, or upstreamHost + upstreamPort in config |
Defaults sit at 18420/18421 to avoid collision with Angular CLI (4200), Vite (5173), and other common dev ports.
Interactive port picker — probes candidates, prompts if taken, writes wmem.config.json:
node scripts/configure-ports.mjs # interactive: probe + prompt
node scripts/configure-ports.mjs --port 19420 # non-interactive
node scripts/configure-ports.mjs --print # show resolved config
wmem.config.json is gitignored (per-machine). wmem.config.example.json ships as the template. Env vars always win over the file, which always wins over the default.
| Var | Purpose | Default |
|---|---|---|
MEMORY_DB | SQLite DB path | ./data/memory.db |
WMEM_TOKEN_FILE | Bearer-auth token file path | ./.wmem-token (auth disabled if file missing) |
WMEM_ROLE | Force role master/mirror/unknown at boot | auto-detect → master for single-user |
WMEM_OUTBOX_* | Outbox tuning (tick, batch, backoff, dead-letter) | see modules/wmem-outbox/README.md |
wmem/
├── core/
│ ├── db.mjs ← SQLite + FTS5 + sqlite-vec + tags + sessions + aliases + privacy + kg_relations
│ ├── indexer.mjs ← incremental JSONL indexer + auto-agent detection
│ ├── importer.mjs ← universal file importer (markdown, text, CLAUDE.md)
│ ├── context.mjs ← L-tier classification + validation + compression
│ ├── embeddings.mjs ← local embeddings (transformers.js, all-MiniLM-L6-v2)
│ ├── autotag.mjs ← pattern-based auto-tagging (40+ categories)
│ ├── personality.mjs ← personality CRUD, files, activation, L1 integration
│ ├── decision.mjs ← proactive behavior engine (salience + thresholds)
│ ├── graph.mjs ← knowledge graph (topic/directory/project/agent nodes)
│ ├── expander.mjs ← query expansion (200+ synonym mappings, zero LLM)
│ ├── facts.mjs ← regex-based fact extraction (25+ patterns)
│ ├── temporal.mjs ← date resolver (yesterday, last tuesday, N days ago)
│ ├── subquery.mjs ← sub-query splitting for multi-event temporal
│ └── doctor.mjs ← integrity checks, recovery, purge, checkpoints
├── scripts/
│ ├── setup.mjs ← one-command setup (9 steps, cross-platform)
│ ├── index-sessions.mjs ← CLI: indexing + --auto-agent + --merge aliases
│ ├── generate-l1.mjs ← CLI: generate L1 hot memory block
│ ├── personality.mjs ← CLI: create, use, list, show, export, import
│ ├── doctor.mjs ← CLI: status, health check, fix, dedup, purge, recover
│ ├── import.mjs ← CLI: import external files with tier placement
│ ├── session-start-hook.sh ← Claude Code hook: index + L1 + personality
│ └── session-end-hook.sh ← Claude Code hook: index new content
│ ├── benchmark-ingest.mjs ← ingest LongMemEval into wmem DB
│ └── benchmark-retrieval.mjs ← benchmark retrieval (keyword/expanded/hybrid/full)
├── mcp-server.mjs <- MCP server (69 stdio tools)
├── server.mjs <- HTTP service (read endpoints + 22-op /api/write dispatcher, v1.2)
├── modules/wmem-outbox/ <- local proxy daemon for multi-instance topologies (v1.2)
├── server.mjs ← HTTP API server (Express, optional)
├── capabilities.md ← what the agent can do (manually maintained)
├── LICENSE ← MIT
└── data/ ← SQLite DB (gitignored)
wmem exposes 69 stdio MCP tools (library mode) and an additional HTTP surface
when running server.mjs (service mode, v1.2+):
/api/search, /api/recent, /api/stats, /api/mail/*, /api/wmem/role, /health/api/ingest, /api/amend, /api/import, /api/reimport, /api/preferences/write, /api/facts/write, /api/capabilities/*, /api/mail/send/api/write (22 ops, v1.2) — memory.{amend,share,personal}, project.{upsert,ship,scope.*}, session.file.touch, personality.{upsert,delete,enable,sfw,activate,file.set}, personality.core.{add,update,delete}, personality.trait.{add,update,enable,disable,delete,promote}modules/wmem-outbox/) — /health, /role, /admin/{drain,outbox,outbox/dead-letter}All write endpoints are gated by the role middleware (refuses 403 on non-master instances). See docs/mcp-tools.md for the full HTTP surface.
| Tool | Description |
|---|---|
| Memory | |
memory_search | FTS5 keyword search (scope: default/private/shared/all, snippet previews) |
memory_ingest | Store content manually |
memory_l1 | Generate L1 hot memory block |
memory_capabilities | Return capabilities list |
memory_recent | Recent chunks by agent |
memory_stats | Index statistics |
memory_share | Share a chunk across all personalities |
memory_personal | Lock a chunk to this personality (cannot be shared) |
memory_import | Import a file or raw text (section splitting, auto-tags, source tracing) |
memory_delete | Delete a chunk (preview first, confirm to execute) |
memory_last_session | Where did we leave off? Current dir + parallel work across directories |
memory_sessions | List recent session bookmarks by project/agent |
| Projects | |
project_update | Create/update project state |
project_ship | Mark project as shipped |
project_list | List projects by status |
| Personality | |
personality_use | Switch active personality (atomic, with checkpoint) |
personality_list | List all personalities |
personality_create | Create new (with templates + decision config) |
personality_show | Show personality details |
personality_file_set | Create/update personality file |
personality_file_list | List personality files |
| Knowledge Graph | |
graph_related | Find chunks related to a topic |
graph_topics | Find co-occurring topics |
graph_path | Relationship between two topics |
graph_map | Full topic graph (nodes + edges) |
| System | |
wmem_status | Full status report (chunks, sessions, agents, DB size) |
wmem_doctor | Integrity checks (orphans, duplicates, stale sessions) |
wmem_dedup | Remove duplicate chunks |
node scripts/setup.mjs --agent myname)claude mcp add>>>markers<<<)scripts/import.mjs)--merge false positives, retroactive re-tag)wmem_status, wmem_doctor, wmem_dedup)wmem_role table + role gate (writes refused on non-master)GET /api/wmem/role endpoint for client probesPOST /api/write generic dispatcher (22 ops, server-side allowlist)wmem-outbox daemon — local proxy with offline buffering + drain on reconnectscripts/configure-ports.mjs) — probe + prompt + write wmem.config.jsonaggregatePreferences in core/db.mjs)core/doctor.mjs)reimport; hook wiring pending)materializeTopicRelations exists; hook wiring pending)wmem personality generate — interactive personality builderpersonality update CLI command (create/delete/use exist; update missing)--secrets flag) — core/secret-patterns.mjs exists and is wired into memory_amend previews; wiring into wmem_doctor pendingwrittenBy / about on ingest path; schema exists in 0004_messages_and_written_by.sql)wmem-eval benchmark and publish retrieval scores in READMEprepublishOnly, .npmignore, automated version tagging)examples/multi-instance-walkthrough.mjs — runnable demo of master + mirror + outbox topologynpm test on push + PR)examples/preference-loop-walkthrough.mjs — runnable demo of the zero-LLM preference consolidation loop (tier 1 signals → tier 2 preferences → tier 3 facts). Observable output at each stage. Run against a scratch DB:
MEMORY_DB=/tmp/wmem-pref-demo.db node examples/preference-loop-walkthrough.mjs
wmem is not a password manager. By deliberate scope.
Encrypted-at-rest key-value storage (API tokens, credentials, private material) belongs in a specialized tool with a mature threat model. We recommend:
pass — GPG-backed, the UNIX-idiomatic answerage / sops — file-level encryptionWhat wmem does provide:
Secret pattern scanning + redaction. core/secret-patterns.mjs recognizes common shapes (OpenAI / Anthropic / GitHub / AWS / GCP keys, JWTs, bearer tokens, PEM blocks, password assignments). Used in two places:
memory_amend or memory_delete on a chunk that contains a secret, the preview response redacts the secret before returning — so the secret never traverses an API response on its way to your review.wmem_doctor --secrets surfaces chunks where secrets were accidentally indexed so you can amend or delete them.memory_amend tool. If you find a leaked credential in memory, amend replaces the content in place (regenerates tags, drops the vector, FTS re-syncs). The original content is NOT preserved — this is redaction, not revision history. See docs/mcp-tools.md.
The design discipline: wmem ingests a lot. Sometimes it ingests something it shouldn't have. Our job is to help you find and remove those, not to become a storage backend for the thing that got ingested.
The public repository starts at the point where the code was scrubbed for public release. Earlier development history is not published. Source of truth from the fork point forward is this repository.
15 commits
JavaScript
95.6%
Python
2.9%
Shell
1.4%
Memory + identity + judgment for AI agents. One SQLite file. Zero API cost.
Runs two ways:
npm install && npm start.node server.mjs exposes an HTTP
API with optional bearer-token auth on writes, shared DB across MCP
clients, agent-to-agent mail, capability registry, runtime identity
switching for operator sessions.One codebase, two deployment patterns. Library-mode users can ignore the
service-mode tools entirely (the mail_*, capability_*, agent_* MCP
surface).
claude plugins marketplace add github.com/andrkelemen/wmem
claude plugins install wmem@wmem
The plugin registers the MCP server on first run via a Setup hook, wires the SessionStart / SessionEnd / PreCompact hooks, ships two skills (using-wmem, wmem-compact-protocol) that auto-load, and exposes slash commands (/recall, /chunks, /projects, /wmem-doctor). Then run the one-time setup to import + index + create a personality:
git clone https://github.com/andrkelemen/wmem.git ~/wmem
cd ~/wmem
node scripts/setup.mjs --agent myname
git clone https://github.com/andrkelemen/wmem.git
cd wmem
node scripts/setup.mjs --agent myname
Same setup script does everything: npm install, import your CLAUDE.md, index your sessions, create a personality, register the MCP server via claude mcp add, register the hooks via ~/.claude/settings.json.
Preview first with --dry-run:
node scripts/setup.mjs --agent myname --dry-run
AI agents forget. Every compaction, every restart — knowledge is lost. wmem fixes this with a layered memory system, hybrid search, and three features nobody else has:
node scripts/setup.mjs --agent myname
Detects OS, installs deps, imports existing files, indexes sessions, creates personality, registers MCP server. Linux, macOS, Windows.
Multi-stage retrieval in one SQLite file. memory_search auto-routes based on what's in the DB — hybrid when vectors exist, tag-boosted FTS5 otherwise.
^0.1.9 — fine for personal-scale; flag before broader deployment)scripts/benchmark-experimental.mjs for offline runs; off in the interactive MCP pathBenchmark scripts are in scripts/ for anyone who wants to measure on their own workloads.
Switch who the agent IS. Each personality has its own memories, voice, capabilities, and decision thresholds.
node scripts/personality.mjs create dev --template coder
node scripts/personality.mjs create planner --template architect
node scripts/personality.mjs use dev # instant switch
node scripts/personality.mjs update dev --voice "Terse. No hedging." # tweak in place
node scripts/personality.mjs create dawn --interactive # guided Q&A
Built-in templates: coder, architect, reviewer, writer, researcher, confidant.
Eleven commands cover the full lifecycle: list, use, create (with --template and/or --interactive), update, show, active, delete, templates, import, export. See docs/personalities.md for the full reference, the JSON export schema, and how personality files / decision config layer on top.
Export/import as JSON. Share personalities between machines.
Deterministic silence decisions. Asking an LLM whether to speak makes the model the judge of its own output — the decision and the output get coupled. Move the decision into a state machine with auditable thresholds instead. Don't ask the model. Build a state machine.
Four output modes:
Each personality defines its own thresholds:
{
"decision": {
"actionThreshold": 0.6,
"cooldownMinutes": 15,
"quietHours": [1, 7],
"salienceModifiers": { "error": 1.3, "task_failed": 1.5 },
"responseStyle": { "maxWords": 10, "register": "technical" }
}
}
Same event, different personality, different behavior. Coder stays silent during focus. Researcher proactively shares findings. Writer barely speaks at all.
Relationships emerge from co-occurrence. No graph database.
# "What relates to authentication?"
graph_related → direct tag matches + co-occurring chunks from same sessions
# "What topics appear alongside auth?"
graph_topics → deployment (63 sessions), config (68), api (64)
# "How does auth relate to deployment?"
graph_path → strong (10 shared sessions), connecting chunks shown
Four node types: topic, directory, project, agent. Unified kg_relations table with typed edges. Directories auto-detect project from git remote. Related directories discovered by shared project, tag overlap (3+), or time proximity (24h).
Pure SQLite queries over existing tags + sessions tables. <50ms.
Cross-personality shared memory with privacy controls.
_shared — all personalities see it (projects, decisions, facts)private — only this personality (conversations, session history)personal — locked, cannot be shared. Ever.memory_share copies to shared. memory_personal locks permanently.
Import whatever you already have. No reformatting.
# Dry run — preview sections + classifications
node scripts/setup.mjs --agent myname --dry-run
# Handles: markdown (.md), plain text (.txt), CLAUDE.md section splitting
# Classifies: personality vs memory vs config (with confidence scores)
# Low confidence → flagged for review, not guessed
# Atomic: whole file imports or none (SQLite transaction)
# Source tracing: file + section + line number in metadata
25 topic + action patterns, generated on insert. No manual organization.
Tags: auth, debugging, deployment, decision, fix, shipped, api, database, performance, security, frontend, testing, config, networking, automation, observability, and more.
Auto-generated context loaded on every session start. Zero API cost.
TEMPORAL ANCHOR: Today, agent age
PERSONALITY: System prompt + voice + always-load files
CAPABILITIES: Manually maintained list
RECENT SESSIONS: Time-windowed compression (2h/6h/18h)
CROSS-FOLDER PICK-UP: "you were also working on X in another folder" (v1.3)
PROJECTS: Active/shipped/blocked state
~1,200 tokens. >95% of context window stays free.
The CROSS-FOLDER PICK-UP section is fed by session_bookmarks (written
on SessionEnd by scripts/session-end-bookmark.mjs) and surfaces
parallel work from other directories — same project, shared topics, or
recent time overlap.
Named documents per personality (identity notes, preferences, style guides). Stored in DB, travel with personality on export.
Mark as always_load: true → injected into L1 every session.
Run one canonical master + N read-only mirrors without forking the dataset.
master / mirror / unknown at first boot (default master for single-user; override WMEM_ROLE=mirror on follower boxes). Non-master writes get 403 wmem_role_not_master./api/wmem/role — clients check before writing; surfaces hostname + set-by metadata.POST /api/write dispatcher — single endpoint covering 22 admin ops (projects, sessions, personality core/traits, memory share). One server-side allowlist, one gate, no per-op route sprawl.wmem-outbox daemon — local proxy at :18421. MCP/scripts post writes to it instead of straight upstream. Forwards while master reachable, buffers to local SQLite when not, drains on reconnect with exponential backoff + dead-letter. Survives upstream outages without losing writes.Library-mode users see no change — master is auto-stamped, writes work as before. Multi-instance topologies opt in by setting WMEM_ROLE=mirror on followers and running modules/wmem-outbox/install/install.sh on each.
See modules/wmem-outbox/README.md and migrations/0010_wmem_role.sql.
| What | Default | Set via |
|---|---|---|
HTTP server (node server.mjs) | 18420 | PORT= env, or port in wmem.config.json |
| Outbox daemon listen | 18421 | WMEM_OUTBOX_PORT= env, or outboxPort in wmem.config.json |
| Outbox → upstream | 127.0.0.1:18420 | WMEM_UPSTREAM_HOST= + WMEM_UPSTREAM_PORT= env, or upstreamHost + upstreamPort in config |
Defaults sit at 18420/18421 to avoid collision with Angular CLI (4200), Vite (5173), and other common dev ports.
Interactive port picker — probes candidates, prompts if taken, writes wmem.config.json:
node scripts/configure-ports.mjs # interactive: probe + prompt
node scripts/configure-ports.mjs --port 19420 # non-interactive
node scripts/configure-ports.mjs --print # show resolved config
wmem.config.json is gitignored (per-machine). wmem.config.example.json ships as the template. Env vars always win over the file, which always wins over the default.
| Var | Purpose | Default |
|---|---|---|
MEMORY_DB | SQLite DB path | ./data/memory.db |
WMEM_TOKEN_FILE | Bearer-auth token file path | ./.wmem-token (auth disabled if file missing) |
WMEM_ROLE | Force role master/mirror/unknown at boot | auto-detect → master for single-user |
WMEM_OUTBOX_* | Outbox tuning (tick, batch, backoff, dead-letter) | see modules/wmem-outbox/README.md |
wmem/
├── core/
│ ├── db.mjs ← SQLite + FTS5 + sqlite-vec + tags + sessions + aliases + privacy + kg_relations
│ ├── indexer.mjs ← incremental JSONL indexer + auto-agent detection
│ ├── importer.mjs ← universal file importer (markdown, text, CLAUDE.md)
│ ├── context.mjs ← L-tier classification + validation + compression
│ ├── embeddings.mjs ← local embeddings (transformers.js, all-MiniLM-L6-v2)
│ ├── autotag.mjs ← pattern-based auto-tagging (40+ categories)
│ ├── personality.mjs ← personality CRUD, files, activation, L1 integration
│ ├── decision.mjs ← proactive behavior engine (salience + thresholds)
│ ├── graph.mjs ← knowledge graph (topic/directory/project/agent nodes)
│ ├── expander.mjs ← query expansion (200+ synonym mappings, zero LLM)
│ ├── facts.mjs ← regex-based fact extraction (25+ patterns)
│ ├── temporal.mjs ← date resolver (yesterday, last tuesday, N days ago)
│ ├── subquery.mjs ← sub-query splitting for multi-event temporal
│ └── doctor.mjs ← integrity checks, recovery, purge, checkpoints
├── scripts/
│ ├── setup.mjs ← one-command setup (9 steps, cross-platform)
│ ├── index-sessions.mjs ← CLI: indexing + --auto-agent + --merge aliases
│ ├── generate-l1.mjs ← CLI: generate L1 hot memory block
│ ├── personality.mjs ← CLI: create, use, list, show, export, import
│ ├── doctor.mjs ← CLI: status, health check, fix, dedup, purge, recover
│ ├── import.mjs ← CLI: import external files with tier placement
│ ├── session-start-hook.sh ← Claude Code hook: index + L1 + personality
│ └── session-end-hook.sh ← Claude Code hook: index new content
│ ├── benchmark-ingest.mjs ← ingest LongMemEval into wmem DB
│ └── benchmark-retrieval.mjs ← benchmark retrieval (keyword/expanded/hybrid/full)
├── mcp-server.mjs <- MCP server (69 stdio tools)
├── server.mjs <- HTTP service (read endpoints + 22-op /api/write dispatcher, v1.2)
├── modules/wmem-outbox/ <- local proxy daemon for multi-instance topologies (v1.2)
├── server.mjs ← HTTP API server (Express, optional)
├── capabilities.md ← what the agent can do (manually maintained)
├── LICENSE ← MIT
└── data/ ← SQLite DB (gitignored)
wmem exposes 69 stdio MCP tools (library mode) and an additional HTTP surface
when running server.mjs (service mode, v1.2+):
/api/search, /api/recent, /api/stats, /api/mail/*, /api/wmem/role, /health/api/ingest, /api/amend, /api/import, /api/reimport, /api/preferences/write, /api/facts/write, /api/capabilities/*, /api/mail/send/api/write (22 ops, v1.2) — memory.{amend,share,personal}, project.{upsert,ship,scope.*}, session.file.touch, personality.{upsert,delete,enable,sfw,activate,file.set}, personality.core.{add,update,delete}, personality.trait.{add,update,enable,disable,delete,promote}modules/wmem-outbox/) — /health, /role, /admin/{drain,outbox,outbox/dead-letter}All write endpoints are gated by the role middleware (refuses 403 on non-master instances). See docs/mcp-tools.md for the full HTTP surface.
| Tool | Description |
|---|---|
| Memory | |
memory_search | FTS5 keyword search (scope: default/private/shared/all, snippet previews) |
memory_ingest | Store content manually |
memory_l1 | Generate L1 hot memory block |
memory_capabilities | Return capabilities list |
memory_recent | Recent chunks by agent |
memory_stats | Index statistics |
memory_share | Share a chunk across all personalities |
memory_personal | Lock a chunk to this personality (cannot be shared) |
memory_import | Import a file or raw text (section splitting, auto-tags, source tracing) |
memory_delete | Delete a chunk (preview first, confirm to execute) |
memory_last_session | Where did we leave off? Current dir + parallel work across directories |
memory_sessions | List recent session bookmarks by project/agent |
| Projects | |
project_update | Create/update project state |
project_ship | Mark project as shipped |
project_list | List projects by status |
| Personality | |
personality_use | Switch active personality (atomic, with checkpoint) |
personality_list | List all personalities |
personality_create | Create new (with templates + decision config) |
personality_show | Show personality details |
personality_file_set | Create/update personality file |
personality_file_list | List personality files |
| Knowledge Graph | |
graph_related | Find chunks related to a topic |
graph_topics | Find co-occurring topics |
graph_path | Relationship between two topics |
graph_map | Full topic graph (nodes + edges) |
| System | |
wmem_status | Full status report (chunks, sessions, agents, DB size) |
wmem_doctor | Integrity checks (orphans, duplicates, stale sessions) |
wmem_dedup | Remove duplicate chunks |
node scripts/setup.mjs --agent myname)claude mcp add>>>markers<<<)scripts/import.mjs)--merge false positives, retroactive re-tag)wmem_status, wmem_doctor, wmem_dedup)wmem_role table + role gate (writes refused on non-master)GET /api/wmem/role endpoint for client probesPOST /api/write generic dispatcher (22 ops, server-side allowlist)wmem-outbox daemon — local proxy with offline buffering + drain on reconnectscripts/configure-ports.mjs) — probe + prompt + write wmem.config.jsonaggregatePreferences in core/db.mjs)core/doctor.mjs)reimport; hook wiring pending)materializeTopicRelations exists; hook wiring pending)wmem personality generate — interactive personality builderpersonality update CLI command (create/delete/use exist; update missing)--secrets flag) — core/secret-patterns.mjs exists and is wired into memory_amend previews; wiring into wmem_doctor pendingwrittenBy / about on ingest path; schema exists in 0004_messages_and_written_by.sql)wmem-eval benchmark and publish retrieval scores in READMEprepublishOnly, .npmignore, automated version tagging)examples/multi-instance-walkthrough.mjs — runnable demo of master + mirror + outbox topologynpm test on push + PR)examples/preference-loop-walkthrough.mjs — runnable demo of the zero-LLM preference consolidation loop (tier 1 signals → tier 2 preferences → tier 3 facts). Observable output at each stage. Run against a scratch DB:
MEMORY_DB=/tmp/wmem-pref-demo.db node examples/preference-loop-walkthrough.mjs
wmem is not a password manager. By deliberate scope.
Encrypted-at-rest key-value storage (API tokens, credentials, private material) belongs in a specialized tool with a mature threat model. We recommend:
pass — GPG-backed, the UNIX-idiomatic answerage / sops — file-level encryptionWhat wmem does provide:
Secret pattern scanning + redaction. core/secret-patterns.mjs recognizes common shapes (OpenAI / Anthropic / GitHub / AWS / GCP keys, JWTs, bearer tokens, PEM blocks, password assignments). Used in two places:
memory_amend or memory_delete on a chunk that contains a secret, the preview response redacts the secret before returning — so the secret never traverses an API response on its way to your review.wmem_doctor --secrets surfaces chunks where secrets were accidentally indexed so you can amend or delete them.memory_amend tool. If you find a leaked credential in memory, amend replaces the content in place (regenerates tags, drops the vector, FTS re-syncs). The original content is NOT preserved — this is redaction, not revision history. See docs/mcp-tools.md.
The design discipline: wmem ingests a lot. Sometimes it ingests something it shouldn't have. Our job is to help you find and remove those, not to become a storage backend for the thing that got ingested.
The public repository starts at the point where the code was scrubbed for public release. Earlier development history is not published. Source of truth from the fork point forward is this repository.
15 commits
JavaScript
95.6%
Python
2.9%
Shell
1.4%