Skip to main content
Glama

open-memex

Persistent memory for your AI coding agents — on your machine, in plain Markdown, shared by every tool you code with.

npm version License open-memex MCP server – quality and maintenance score on Glama

中文文档

Every AI coding session starts from zero: you re-explain the project, the agent rediscovers the same gotchas, and yesterday's decisions vanish when the chat ends. open-memex gives your agents a memory that survives the session. Say "remember: we deploy on Fridays" once, and next week Copilot, Cursor, opencode, or Claude Code already knows — because they all read and write the same local memory on your machine.

  • Free and open source (Apache-2.0). No account, no cloud, no telemetry — everything lives on your machine, in files you can open and edit.

  • Local-first: memories are plain Markdown files (the source of truth) with a rebuildable SQLite keyword index. Nothing leaves your machine unless you explicitly share it.

  • One memory, every agent: wire up several editors with one command; they share the same memory instead of keeping separate silos.

Terminal demo: two memories saved on Monday, recalled by search in a fresh session on Friday

New here? This README takes you from install to a working memory in about a minute. The concept guide explains the mental model in depth once you're up and running.

Contents

Related MCP server: agent-memory

Quick start

You need Node.js ≥ 22.14 (check with node -v). Then:

npm install -g open-memex
open-memex init

init detects the editors you have installed (VS Code, Cursor, opencode, and Visual Studio when your project has a solution file) and connects each one to open-memex. Restart your editor afterwards.

See it work (30 seconds):

open-memex add "This project deploys on Fridays"

Now open a new chat in your editor and ask your agent: "When does this project deploy?" It already knows — no re-explaining. That round trip, capture once and recall forever, is the whole product. Everything below is detail.

Optional but recommended — check everything is wired up:

open-memex doctor

Core concepts

Three ideas explain almost everything open-memex does.

open-memex architecture: your editors share one local memory — Markdown files as the source of truth, an SQLite FTS5 index for search, personal scope that never leaves the machine, and project scope shared through git PRs

1. Two scopes: project and personal. Every memory belongs to one of two places:

  • project — knowledge about one codebase (decisions, constraints, lessons). Scoped to the current repo automatically; you never set this up by hand.

  • personal — knowledge about you (preferences, habits) that applies in every project. It lives only on this machine and can never be shared into a repo.

Facts about you ("I prefer concise diffs") go to personal; everything else defaults to the current project.

2. Capture → recall. Memories are saved as small Markdown files, one fact each. On the first turn of every new session, open-memex hands your agent the most relevant ones automatically, so it starts the session already knowing them. The agent can also search the full memory on demand. You never have to "load" anything yourself.

3. Your files, your rules. The Markdown files are the source of truth — open them, edit them, delete them, grep them. The SQLite index next to them is just a search accelerator and rebuilds from the files at any time (open-memex reindex). Team sharing, when you want it, goes through the same review flow as code: nothing is shared automatically (see Team workflow).

Which editors, which features

open-memex talks to editors two ways: a native opencode plugin, and a standard MCP server that any MCP-capable editor can use. (MCP — Model Context Protocol — is the open standard editors use to give agents extra tools; open-memex appears in your editor as a set of memory_* tools.) What you get depends on which path an editor uses:

Editor

Setup

Tools

Session-start recall

Keyword auto-capture

opencode (native plugin, recommended)

open-memex init --client opencode --global

5 core tools

Built in — first turn of every session

Yes — remember …, 记住…

VS Code (Copilot)

open-memex init --client vscode

All 11 via MCP

Via MCP guidance*

No — the agent saves when you ask

Cursor

open-memex init --client cursor

All 11 via MCP

Via MCP guidance*

No — the agent saves when you ask

Claude Code

claude mcp add open-memex -- open-memex mcp

All 11 via MCP

Via MCP guidance*

No — the agent saves when you ask

Visual Studio 2022 17.14+ / 2026

open-memex init --client visualstudio

All 11 via MCP

Via MCP guidance*

No — the agent saves when you ask

Codex and other MCP clients

open-memex mcp --print-config

All 11 via MCP

Via MCP guidance*

No — the agent saves when you ask

* MCP has no hard session-start hook, so open-memex sends the agent guidance in the MCP handshake (including how many drafts are waiting) and init writes the fuller version into the editor's instruction files. In practice agents follow it; the opencode plugin is the only path with true built-in first-turn injection. The Tools section lists the 5 core tools and the 6 extra workflow tools, so the "5 vs 11" split is explicit.

All editors on the same machine read and write the same memory — a constraint captured in VS Code is respected in opencode; a lesson learned in Cursor shows up in Claude Code. (Different machines do not sync automatically; see the FAQ.)

init also installs an Agent Skill (a short instruction file that teaches skill-aware agents to use the CLI) for VS Code and Cursor, and for opencode in per-project MCP mode. With the opencode native plugin wired, no skill is installed there — the plugin already provides the memory tools, and a second instruction set only made agents chatty.

How it compares

open-memex

Instruction files (CLAUDE.md, AGENTS.md, …)

Cloud memory services

Chat history

Where it lives

Your machine + your repos

In the repo

Vendor servers

Gone when the chat ends

Who maintains it

Captured as you work; you review

You write and update by hand

The service

—

Works across AI tools

Yes — any MCP client (same machine)

One file per tool convention

Per-integration

No

Review before sharing

Yes — outbox + pull request

Yes — it's just files

Varies

No

Human-readable

Plain Markdown files

Yes

Dashboard / API

No

Instruction files are great for a handful of standing rules — keep using them (open-memex can even draft one from your memories; see distill-agents below). open-memex covers the growing pile of decisions, lessons, and preferences that no one remembers to write down.

Installation

Requirements

  • Node.js ≥ 22.14 (open-memex doctor verifies this for you). The floor is the SQLite driver's: better-sqlite3 13 is built against Node-API 10, which Node gained in 22.14.0 — older Node segfaults on the first database open.

Install the CLI

npm install -g open-memex

That's the stable release. Installing the package may print a reminder to run open-memex init — the editor wiring is a separate step (see Setting up your editor), so don't worry if you don't see the reminder; just run init next.

Two alternatives:

  • No install — run via npx: npx -y open-memex <command> runs any command without installing (e.g. npx -y open-memex init --client vscode). Slower to start, nothing to uninstall.

  • Alpha builds (newest features, rougher edges, for testers): npm install -g open-memex@alpha. Check what's published with npm view open-memex version (stable) and npm view open-memex@alpha version (alpha).

If open-memex isn't found after installing, your PATH needs attention — see Troubleshooting.

From source (for contributors)

git clone -b main https://github.com/stoneskin/open-memex.git
cd open-memex
npm install
node --experimental-strip-types src/cli.ts <command>

Setting up your editor

Run init from your project root (the top folder of the repo you're working in) so the project scope resolves to that repo:

open-memex init --yes
# …or without installing the package first:
npx -y open-memex init --yes

--yes accepts the recommended defaults for everything init asks about (editors to wire, auto-capture, first-turn recall). Leave it off if you want to answer each question. With no --client, init detects your installed editors and wires them all — one init covers every project. Prefer a single editor? Pass --client:

VS Code (Copilot):

open-memex init --client vscode

Writes the MCP server entry; reload the window afterwards and confirm the open-memex server is started in Copilot Chat's MCP panel. By default this writes a project-level .vscode/mcp.json (an interactive run asks which level you want); add --global for VS Code's user-level config instead — one setup that works in every project.

Cursor:

open-memex init --client cursor

Same shape as VS Code: project-level .cursor/mcp.json by default, user-level MCP config with --global, plus Copilot-style instructions.

opencode (native plugin — recommended):

open-memex init --client opencode --global --yes

Merges the native plugin into your user-level ~/.config/opencode/opencode.json (or opencode.jsonc if that's the file you already have) — one-time, every project picks it up, no per-project init. You get the 5 core tools, keyword auto-capture, and first-turn context injection. (A config file with comments is left untouched — init prints the line to add by hand.)

Both opencode generations are supported from the same install: init writes the opencode 1 spelling ("plugin") and the opencode 2 spelling ("plugins") — each host reads its own key. Opencode 1 needs version 1.18.29 or newer for this. open-memex doctor tells you if the wiring and the installed host version don't match.

opencode (as a plain MCP consumer):

open-memex init --client opencode

Writes a project-level opencode.jsonc with the MCP server. Only needed if you prefer plain MCP over the native plugin — you give up keyword capture and built-in injection.

Claude Code (from your project root):

claude mcp add open-memex -- open-memex mcp
# …or print the config snippet: open-memex mcp --print-config claude

Visual Studio (from your solution directory):

open-memex init --client visualstudio

Writes solution-level .mcp.json. Requires Visual Studio 2022 17.14+ or Visual Studio 2026 (Windows-only). Visual Studio also auto-discovers .vscode/mcp.json and .cursor/mcp.json, so the VS Code setup above works too.

Codex: no init client yet — add the server manually via open-memex mcp --print-config as a starting point ([mcp_servers] in config.toml, or codex mcp add).

One-time setup for all projects (VS Code / Cursor)

open-memex init --client vscode --global --yes

Two different "globals" — don't mix them up.

  • npm install -g open-memex installs the package globally: it puts the open-memex command on your PATH.

  • init --global writes the editor config at user level instead of the project: init once, the wiring works in every project. It works the same whether the package was installed globally or run via npx.

The --global form writes the server entry to the editor's user-level MCP config (%APPDATA%\Code\User\mcp.json on Windows, ~/Library/Application Support/Code/User/mcp.json on macOS, ~/.config/Code/User/mcp.json on Linux; ~/.cursor/mcp.json for Cursor) instead of the project — init once, the server starts in every project. A per-project .vscode/mcp.json still wins if a project defines its own. If the user-level file has comments in it (editors accept JSONC), init leaves the file untouched and prints the exact snippet to paste in by hand.

init behavior notes

  • Existing config files are merged, never overwritten — re-running init is safe. --force rewrites our entries.

  • With no durable open-memex on PATH (e.g. one-shot npx), init writes an npx -y open-memex mcp server command into the config so the setup keeps working. npm i -g open-memex + open-memex init --force switches to the faster direct command later.

  • On an interactive terminal, init shows the detected editors and asks you to confirm; scripts and CI never prompt and wire every detected editor.

  • If you run bare open-memex on a machine where init never completed, it offers to run it for you (interactive terminals only).

Remove the wiring

open-memex uninstall --yes

Reverses init — removes the MCP server entry, the opencode plugin line, the Agent Skill, and the open-memex section of the editor instructions. With no --client it cleans up every detected editor; --global limits the cleanup to user-level wiring. Your memories are never touched.

What init changes on your machine

Everything init writes, in one place:

  • Memory data (created on first use, not by init itself): %APPDATA%\open-memex\ on Windows, ~/.local/share/open-memex/ on macOS/Linux — your memory files and the search index. Nothing here is ever modified by uninstall.

  • Editor wiring (removed by open-memex uninstall):

    • opencode: a "plugin" entry (opencode 1) and a "plugins" entry (opencode 2) merged into ~/.config/opencode/opencode.json (or .jsonc). Stale my-o-memory entries from before the rename are removed at the same time.

    • VS Code / Cursor: an open-memex server entry in the user-level or project-level MCP config, plus an open-memex section in the Copilot instructions (user-level ~/.copilot/copilot-instructions.md by default; --instructions project writes .github/copilot-instructions.md in the repo instead, for teams where everyone uses open-memex).

    • Visual Studio: .mcp.json next to your solution.

    • Agent Skill: a skills/open-memex/ folder for VS Code (~/.copilot/skills/), Cursor (~/.cursor/skills/), or opencode in per-project MCP mode (~/.config/opencode/skills/).

  • Your repo: nothing. Files only appear in a repo when you explicitly run submit (see Team workflow) — a local commit, never an automatic push.

Files with comments (JSONC) are never rewritten: init prints the exact snippet to paste instead.

Capture: how memories get saved

Three ways memories get in:

  • Keyword triggers (opencode native plugin only): say remember …, note that …, don't forget: …, TIL …, save this … — or in Chinese 记住… / 记一下… / 记录一下… / 别忘了:… — and the sentence is captured without any tool call. Captures land in the current project by default; phrases that signal "this is about me" — remember for me …, help me remember: …, 记住我…, 替我记…, 帮我记…, 我觉得…, 我喜欢… — go to personal instead, and team-context phrases (我们决定…, 帮我们记住…) stay in project. Two rules keep the noise down (D67): a trigger must be a statement to the store, so the narration forms 记得… / remind me to… / 别忘了带伞 / don't forget the wifi password never fire (add a separator — 别忘了:…, don't forget: … — or that to make it an instruction); and a captured body under 3 characters is rejected as a fragment rather than saved — capture --dry-run says so instead of dropping it silently. A trigger also owns its own sentence: the plugin tells the agent what it just stored, and a memory_add that re-saves the same words within the next few minutes is refused with the stored id (D73) — one thing you said is one memory, not three copies of it.

  • The agent saves it: in any editor, ask your agent to remember something (or it saves on its own when you state a fact worth keeping) — it calls memory_add. The routing above is a heuristic; you can always say "save this to my personal memory" or use the CLI with --scope to be explicit.

  • Checkpoint proposals: when a task wraps up, the agent proposes 1–3 short candidate memories distilled from the session — decisions and their reasons, conventions, gotchas, approaches tried and abandoned — and saves only the ones you approve. Nothing is written silently: no draft is created behind your back.

  • The CLI: open-memex add "…" with optional --scope / --tag / --type / --aliases.

Aliases. Each saved memory can carry up to 4 alternate phrasings (synonyms, another language's equivalent) that are indexed with it, so a question worded differently still finds the memory — "vacation days" finds the holiday policy. init asks once whether to enable this (default on); turn it off any time with open-memex config set captureAliases false.

Redaction. Wrap anything sensitive in <private>…</private> and it is stripped before saving. Recognized secrets (API keys, tokens, high-entropy credentials) are masked in place — the first 4 characters are kept so you can tell which key it was, the rest is replaced — and the memory is still saved. Preview exactly what a message would capture, safely, any time:

open-memex capture --dry-run "…"

If a secret slips through anyway, open-memex forget <id> deletes the memory.

Tools the agent gets

The MCP server exposes eleven tools; the opencode native plugin exposes the five core ones (marked ●). The other six are the team-review workflow tools — they only matter once you share memories through Git.

Tool

What it does

● memory_add

Save a fact, preference, decision, note

● memory_search

Keyword search (BM25) across project + personal memories

● memory_list

List memories in a scope (project, personal, or both) as a numbered inventory; include=all is the audit view

● memory_supersede

Replace a memory with a newer version (keeps a supersede chain)

● memory_forget

Delete a memory by id (soft=true hides it instead — retracted, one-way)

memory_status

Show the sync queue: outbox drafts, repo review states, uncommitted files

memory_submit

Move named drafts into the repo memory dir (local branch + commit)

memory_propose

Copy personal memories into the project scope as review candidates

memory_promote

Advance proposed → approved → published (or reject / resubmit)

memory_resolve

List conflicted memory files / 3-way-merge one of them

memory_pr_status

Map the branch PR's GitHub state onto each memory's review state

So an MCP-connected editor always has the full set; opencode's plugin covers capture and recall, and anything workflow-shaped goes through the CLI or an MCP-connected editor.

Memory types

Every memory has a type (what it is) and tags (what it's about). Eleven types are built in:

Type

Captures

fact

A stable true statement about the project or world

preference

How someone likes things done

decision

A choice that was made — the why and the trade-off

constraint

A rule that must not be violated

todo

A commitment to do something later

knowledge

Durable domain or architecture knowledge

howto

A procedure that worked

gotcha

A trap to avoid

lesson

What an incident or mistake taught us

observation

Something noticed, not yet a conclusion

reference

A pointer to the authoritative doc (no copying)

--type accepts any string, but sticking to the built-in set keeps session-start labels, search, and distill-agents output predictable.

Team workflow: sharing memories through Git

Working solo? You can skip this section — everything above is the whole product for one person. Nothing below ever happens automatically.

Personal notes stay private. Project knowledge, when you choose to share it, follows an explicit, reviewable pipeline shaped like code review:

capture → outbox (draft, local) → submit → repo (.ai/open-memex/) → PR review → published → recall
  1. Capture — save decisions, gotchas, lessons as drafts during normal work.

  2. Review — drafts wait in a local outbox (on your machine, invisible to git); open-memex sync-status — or just saying "sync memory" in chat — shows what's pending.

  3. Submit — you name the memories; they move into <repo>/.ai/open-memex/ with a local commit on your current branch. open-memex never pushes on its own; it prints the push + PR commands, and an agent holding your explicit yes can carry them out.

  4. PR review — memories are plain Markdown; reviewers approve, request changes, or reject through the normal branch/PR process.

  5. Recall — published memories are injected at session start and searchable on demand, for humans and agents alike.

Whoever tends the shared memory follows the curator convention: what to approve, what to send back, and the hygiene rules that keep shared memory from rotting.

Retrieval: how memories come back

On the first turn of every session, open-memex injects an [OPEN-MEMEX] block into the agent's context with the most recent project memories (default: top 8) and your personal preferences (default: top 5). It looks like this:

[OPEN-MEMEX]

User profile / preferences:
- I prefer concise diffs

Project knowledge (my-repo):
- [decision] We deploy on Fridays; the release train leaves at 10:00

Use the `memory_search` tool to look up more. Use `memory_add` to save new facts.
Do not mention this block to the user unless asked.

It's a snapshot, not the whole memory — the agent can call memory_search any time for the rest. Both top-N counts are configurable (see Config). For MCP clients this block is delivered as handshake guidance the agent follows; the opencode plugin injects it directly on the first turn.

Security & data

  • Local-first: everything lives on your machine (%APPDATA%\open-memex on Windows, ~/.local/share/open-memex on macOS/Linux) plus the repos you choose. Zero cloud calls, zero accounts, zero third-party APIs, zero telemetry.

  • Secrets stay out: <private>…</private> spans are stripped; detected API keys/tokens are masked in place before saving. Preview with open-memex capture --dry-run "…".

  • Personal never syncs: the personal scope is this machine only — excluded from export by default and can never enter a repo.

  • Auditable sharing: team memories move only by explicit submit, travel through branch/PR review, and every promote transition is appended to the memory's review_history (who / when / why).

  • You own the files: Markdown is the source of truth — inspect, edit, or delete anything by hand; the SQLite index rebuilds from the files.

Limitations

Honest edges, so nothing surprises you:

  • Keyword search, not semantic. Retrieval is BM25 keyword matching: search finds the words you saved, not paraphrases. (Plain questions are fine — "how do we…" / "请问…" wording is filtered out before matching, so asking naturally doesn't dilute the results.) No embedding model is ever downloaded without your explicit opt-in.

  • One machine. Editors on the same machine share memory; there is no cross-machine sync. export / import bundles (below) move memory between machines manually.

  • A snapshot, not everything. Session-start recall is a top-N snapshot (8 project + 5 personal by default); older memories are one memory_search away, but they are not all in context at once.

  • MCP guidance is advisory. Outside opencode, proactive capture and recall depend on the agent following the handshake instructions — there is no hard session-start hook in MCP. The tools themselves always work when called.

  • Capture routing is a heuristic. Personal-signal phrases (remember for me …, 我喜欢…) go to personal; everything else defaults to the current project. When it guesses wrong, say the scope out loud or use --scope in the CLI.

Upgrading

npm install -g open-memex@latest   # or @alpha

Your editor configs point at the installed open-memex command, so upgrades need no re-wiring. After a major upgrade, run open-memex init --force once to refresh the installed Agent Skill and instruction files with the latest wording. If you installed from source or moved the package, --force also re-points the opencode plugin path.

What changed in each version: see the CHANGELOG.

Storage layout

%APPDATA%\open-memex\               (Windows)
~/.local/share/open-memex/          (macOS/Linux; $XDG_DATA_HOME if set)
├── index.db                         # SQLite FTS5 index (rebuildable)
└── memories/
    ├── personal/
    │   └── <id>.md
    └── project__<name>__<hash12>/
        └── <id>.md

Each .md file is one memory: YAML frontmatter (id, scope, type, tags, created_at, schema_version, …) followed by the content. You can edit them by hand — the index re-syncs from the files, and Markdown is always the source of truth (open-memex reindex rebuilds the index from scratch).

Once you submit, project memories also live as Markdown files under <repo>/.ai/open-memex/ (configurable via memoryDir), where they travel with branches and PRs like any other file.

Config

Settings live in ~/.config/opencode/open-memex.jsonc — the opencode in the path is historical; this one file is shared by every client. Override the config path with OPEN_MEMEX_CONFIG and the storage root with OPEN_MEMEX_HOME (the pre-rename MY_O_MEMORY_CONFIG / MY_O_MEMORY_HOME names are still honored as fallbacks).

Defaults:

{
  "maxProjectMemories": 8,    // top-N project memories injected on first turn
  "maxProfileItems": 5,       // top-N personal items injected on first turn
  "injectOnFirstTurn": true,  // [OPEN-MEMEX] system-prompt block
  "keywordCaptureEnabled": true,
  "logLevel": "info",          // info | debug
  "memoryDir": ".ai/open-memex" // in-repo project-memory dir, relative to repo root
}

open-memex config prints the effective config (defaults + file). Change a setting after install:

open-memex config set keywordCaptureEnabled false
open-memex config set maxProjectMemories 12
open-memex config set sync.autoPull true   # best-effort pull at MCP session start

Settable keys: maxProjectMemories, maxProfileItems, injectOnFirstTurn, keywordCaptureEnabled, captureAliases, logLevel, memoryDir, and sync.autoPull (a dotted key that writes into the nested sync object). Full design: docs/V2-DESIGN.md.

CLI reference

Setup & health:

open-memex init [--client vscode|cursor|opencode|visualstudio]
              [--instructions personal|project] [--global] [--force] [--yes]
open-memex uninstall [--client vscode|cursor|opencode|visualstudio] [--global] [--yes]
open-memex config                                  # print effective config
open-memex config set <key> <value>                # change a setting
open-memex doctor                                  # environment health check (incl. plugin entry)
open-memex audit                                   # memory health check (duplicates, stale, broken chains)
open-memex capture --dry-run "记住我喜欢简洁的回答"  # preview keyword capture
open-memex mcp --print-config vscode|cursor|claude|opencode|visualstudio
open-memex --help      # this reference
open-memex <command> --help  # help for one command
open-memex --version   # installed version

Memory operations:

open-memex add "This repo uses better-sqlite3" --type fact
open-memex search "auth flow"
open-memex search "auth flow" --explain   # show FTS expression, scores, lifecycle-hidden counts
open-memex list --scope project
open-memex list --scope both       # each scope's newest under its own header
open-memex list --include all      # audit view: superseded versions, retracted, archived
open-memex supersede <id> "Updated content"
open-memex status <id> deprecated
open-memex forget <id>
open-memex forget <id> --soft      # hide instead of delete (retracted; one-way)

open-memex inventory                        # everything remembered, as readable text
open-memex inventory --format json          # the same data, for agents
open-memex inventory --format html          # the same data as a local page (writes <data dir>/inventory.html)
# Personal + current project, outbox drafts in their own section, hidden
# history counted. Refuses to write a personal-bearing report inside a
# git working tree unless you pass --allow-personal.
# `list` numbers every entry in one listing and says how many it left out.

Team review workflow (two homes, one per stage):

Project drafts live in the appdata outbox (git-invisible, branch-independent); only drafts you approve move into <repo>/.ai/open-memex/, where they follow branches and PRs. Nothing moves without you naming it. In an AI chat with the MCP server connected, just say "sync memory" (or "同步记忆") — the agent runs the status check, summarizes the outbox drafts, and asks which ones to sync. The server also tells the agent on its own: at session start the handshake reports how many drafts are waiting, and every memory-changing tool result carries the current count when it is non-zero.

open-memex sync-status
# show when the index was last synced (and what triggered it), the outbox
# (pending sync), the repo review states
# (draft / proposed / approved / published / rejected),
# and any uncommitted repo memory files.

open-memex submit <id...> [--branch <name>] [--base <branch>]
# move your named drafts into .ai/open-memex/ as "proposed":
# copies, flips review_state, local git commit ON THE CURRENT BRANCH.
# Never creates a branch on its own — branch creation is your call
# (or the agent's, only with your explicit approval for the full chain).
# All-or-nothing; conflicts (same id, different content) abort cleanly.
# Prints the push + gh pr commands; an agent holding your Yes carries
# through push/PR itself. --branch <name> creates the branch first
# (agent full-chain path). Default PR base is the current branch (memory
# PRs stack onto your working branch); --base redirects it to main or
# wherever you review.

open-memex pr-status [--apply]
# read the branch's GitHub PR and map its state onto each in-repo memory:
# merged PR → published, PR approval → approved (approved_by = reviewer),
# changes-requested → suggestion only. Report by default; --apply performs
# the mapped transitions locally (no push).

open-memex pull
# pull shared memories from the git remote: fetch + fast-forward ONLY.
# A diverged branch fails with a clear message — open-memex never
# force-merges; resolve it by hand, then pull again. On success the
# local index re-syncs. Pulls are explicit by default; set
# `open-memex config set sync.autoPull true` for a best-effort pull
# at MCP session start (a failed pull never blocks the session).

open-memex push
# push the current branch (with its submitted memories) to the git remote.
# Explicit only — open-memex never pushes on its own.

open-memex export [--scope project|personal|both] [--type T] [--tag t] [--all] [-o <file>]
# bundle memories into a portable .tar.gz (markdown + manifest.json) for
# moving to another machine or another app. Excludes visibility:private
# memories by default; --all / -a includes everything (full migration).

open-memex import <bundle.tar.gz> [--dry-run]
# restore a bundle: personal memories go to the personal dir; project
# memories are re-keyed to the current project and land in the outbox as
# drafts. Identical ids are skipped; conflicting ids are reported,
# never overwritten.

open-memex distill-agents [--scope project|personal] [--type t1,t2] [--limit N] [-o <file>]
# propose an AGENTS.md snippet distilled from project memories
# (decisions, constraints, lessons, gotchas, howtos). Prints markdown;
# -o writes it to a file. You review and merge by hand — open-memex
# never rewrites your AGENTS.md on its own. The snippet ends with a
# "memory hygiene" section so agents reading AGENTS.md learn to propose
# distilled captures when a task ends.

open-memex propose <id...> --to project [--local-approve]
# propose one or several personal memories at once (one branch, one PR);
# each is copied with its own new id. All-or-nothing: a bad id aborts the
# whole batch, never a half-proposed one.
# copy a personal memory into the project scope as a review candidate
# (never moves — the personal original stays). Result lands in the outbox;
# run sync-status / submit when you're ready to put it in the repo.
open-memex promote <id> [--reject] [--resubmit] [--note "..."] [--by NAME]
# advance one step: proposed → approved → published (or reject with a note).
# Every transition is appended to the memory's review_history (who/when/why).
# A rejection never deletes the file — your call: accept it (close the PR,
# delete the branch), revise + --resubmit for another round, or keep it as
# a [rejected] record.
open-memex resolve [id-or-path]
# list conflicted memory files, or field-level 3-way merge one of them.
# Semantic conflicts are reported, never auto-resolved.

Whoever tends the shared memory follows the curator convention — docs/CURATOR.md: what to approve, what to send back, and the hygiene rules that keep shared memory from rotting.

Maintenance:

open-memex where        # show storage + config paths
open-memex scopes       # list project scopes with memory counts
open-memex reindex      # rebuild the SQLite index from markdown
open-memex audit        # memory health: duplicate pairs, stale memories, broken chains
open-memex migrate --to-v2 [--dry-run]   # v1 data → v2 (renames user scope to personal)

The CLI runs under Node 22. From a source checkout it uses the built-in experimental TypeScript loader (no build step); the published npm package ships pre-compiled JS (npm run build at publish time). From a source checkout, prefix every command with node --experimental-strip-types src/cli.ts (or npm run cli -- <command> for simple cases — npm swallows unknown --flag args, so prefer direct node).

MCP server

The same memory tools over the Model Context Protocol, via a stdio server — no host-specific plugin needed. Any MCP client can use open-memex.

open-memex mcp               # after a global install
npx -y open-memex mcp        # no install needed

The project scope is resolved from the process working directory, so configure the server with cwd set to your project root (init handles this for you).

Note: MCP is request/response — it gives the agent tools, not the opencode plugin's automatic keyword capture or first-turn injection. Proactive memory use depends on the agent's instructions: the server sends session-start guidance in the MCP handshake instructions (including the live outbox draft count at session start, plus the pending count appended to memory-changing tool results when non-zero), and init writes the fuller version into the editor's instruction files. Both are advisory — no MCP consumer offers a hard session-start hook.

Scopes, in detail

  • project — scoped to the current repo, keyed off the git origin URL hash (so clones of the same repo share a scope), or off the cwd path if there is no remote. Default for new memories.

  • personal — global across all your projects, this machine only, never synced. Use for personal preferences. (v1 called this user; migrate --to-v2 renames it.)

See docs/SCOPES.md for the full scope model: key derivation, migration, visibility, reserved names. The concept guide walks through the mental model end to end.

Troubleshooting

Every command dies with no output, or the process crashes (exit 139, 0xC0000005, "Segmentation fault"). Your Node is older than 22.14 and the bundled SQLite driver cannot load on it. better-sqlite3 13 is compiled against Node-API 10, which Node only gained in 22.14.0; on anything older require() succeeds and then the first database open segfaults the process with no diagnostic. open-memex now refuses to load the driver and says so, but anything already crashing was almost certainly this. Check with node -v, then either upgrade Node (nvm install 22.14 && nvm use 22.14, or any current 22.x/24.x) or pin the driver down with npm install better-sqlite3@^12.11.1. open-memex doctor reports both the Node floor and a live driver probe. Known upstream: WiseLibs/better-sqlite3#1514.

open-memex is not recognized / command not found. A global npm install -g puts the open-memex launcher in npm's global bin folder. If your terminal can't find it, that folder isn't on your PATH:

  1. Find the folder: npm config get prefix

    • Windows: the launcher (open-memex.cmd) sits directly in that folder, e.g. C:\Users\<you>\AppData\Roaming\npm

    • macOS / Linux: it's in <prefix>/bin, e.g. /usr/local/bin or ~/.nvm/versions/node/v22.x.x/bin

  2. Add it to PATH:

    • Windows: Settings → System → About → Advanced system settings → Environment Variables → add the folder to the User Path → restart the terminal. Verify with where open-memex.

    • macOS / Linux: add export PATH="$(npm prefix -g)/bin:$PATH" to ~/.zshrc (or ~/.bashrc), restart the shell, verify with command -v open-memex.

  3. No admin rights / don't want to touch PATH? Use the npx form — npx -y open-memex <command> resolves the package itself and needs no PATH changes.

EBUSY / EPERM on better_sqlite3.node (Windows). On Windows a loaded DLL is locked: if the open-memex MCP server is running (VS Code MCP panel, Cursor, etc.), npm install -g open-memex cannot replace better_sqlite3.node and fails with EBUSY / EPERM. Stop the MCP server first (or quit the editor), then re-run the install. If it still fails, delete node_modules/open-memex and any node_modules/.open-memex-* temp folders under your global npm root and install again.

init says it left a config file untouched. Your editor config has comments (JSONC) or invalid JSON, and open-memex never rewrites files it can't parse safely. init printed the exact snippet to add by hand — paste it in, and you're done. The same applies to the opencode config: if it has comments, add the "plugin" line manually.

Something's off — run open-memex doctor. Checks the Node version, config source, scope resolution for the current directory, and storage writability; verifies VS Code hasn't disabled MCP; then boots a real MCP server and runs initialize + tools/list against it — all eleven tools must show up. It also reports pre-rename my-o-memory leftovers if any editor config still references the old package name.

FAQ

Do I need git? No. Capture and recall work in any folder — without a git repo the project scope simply keys off the folder path. Git is only needed for the team workflow (submit / PR review), which is optional.

I use several editors. Do they really share one memory? Yes — on the same machine. Every wired editor reads and writes the same local memory; see the capability matrix for what each editor gets. A decision captured in VS Code is respected in opencode.

I work on two computers (office + home). Does memory sync? Not automatically — memory is per-machine by design, and your personal scope never leaves the machine it was created on. To move memory manually, use open-memex export on one machine and open-memex import on the other. Project memories shared through Git (Team workflow) travel with the repo, so cloning the repo on the second machine brings the published project memories along — your personal ones stay behind, on purpose.

Is it really free? Do I need an account? Free and open source (Apache-2.0). No account, no sign-up, no telemetry, no cloud calls. If it can't phone home, there's nothing to phone home to: the only network open-memex ever touches is your own git remote, when you explicitly push.

I accidentally pasted a secret into a memory. What now? open-memex search "<part of it>" to find the memory, then open-memex forget <id> to delete it. To prevent it next time, wrap sensitive text in <private>…</private> (stripped before saving) — recognized API keys and tokens are also masked automatically. Preview any message safely with open-memex capture --dry-run "…".

Do I need to run init for every project? No. The data layer needs nothing — the project scope is derived automatically from your cwd's git remote or path, so memories are namespaced per project with zero setup. The editor wiring is one open-memex init per machine (user-level wherever the editor supports it). Run it again only after upgrading (--force) or if you switch editors.

Does opencode need init? Two paths. Recommended: open-memex init --client opencode --global — it merges the native open-memex plugin into ~/.config/opencode/opencode.json for you. One-time setup, applies to all projects, and additionally enables keyword auto-capture and first-turn memory injection. Prefer to do it by hand? Add "plugin": ["file:///absolute/path/to/open-memex/src/index.ts"] (the installed package's path) to that file instead. As a plain MCP consumer: open-memex init --client opencode writes a project-level opencode.jsonc (no hooks). If your user-level config has comments, init leaves it untouched and prints the manual step.

VS Code — run init once, or per project? Once. Plain open-memex init auto-detects VS Code and writes the MCP server entry to VS Code's user-level mcp.json (%APPDATA%/Code/User/mcp.json on Windows, ~/Library/Application Support/Code/User/mcp.json on macOS, ~/.config/Code/User/mcp.json on Linux), so the server starts in every project. A per-project .vscode/mcp.json still wins when present, and the entry keeps cwd=${workspaceFolder} so project-scope resolution keeps working per window. If your user-level mcp.json has comments (VS Code accepts JSONC), init leaves it alone and prints the exact snippet to add by hand. An empty file is treated as blank and written to directly.

How do I remove the editor wiring? open-memex uninstall reverses init: it removes the MCP server entry, the opencode plugin line, the Agent Skill directory, and the open-memex section of the Copilot instructions. With no --client it cleans up every detected editor; --global limits the cleanup to user-level wiring. Your memories are never touched.

I upgraded Node, or switched versions with nvm. Do I need to reinstall? The package itself doesn't care: its SQLite driver is a Node-API prebuild, so it loads on any supported Node (≥ 22.14) with no recompiling, and your memories live outside the install. But version managers (nvm and friends) keep a separate global package folder per Node version, so after a switch open-memex may simply be "not found". Run npm install -g open-memex once under the new Node, then open-memex doctor to confirm the driver loads.

Project status

open-memex is stable and in daily use; the current stable line is published on npm as latest, with alpha builds for testers. Release history lives in GitHub Releases; design decisions are recorded in the append-only log at docs/V2-DESIGN.md.

On the horizon (no version promises): native agent plugins for more editors as enhancements over the same MCP tools; local embeddings as an opt-in experiment (no model is ever downloaded without asking); an org layer only if real multi-repo sharing, ACL, or compliance needs demand it.

License

Apache-2.0

Available Tools

11 tools
memory_addA

Save a fact, preference, decision, or note to persistent local memory. Call this PROACTIVELY whenever the user shares something worth remembering across sessions — project conventions, tool choices, personal preferences, decisions made, error fixes and their causes. Worth saving: decisions and their reasons, preferences, conventions, gotchas, approaches tried and abandoned. Not worth saving: one-off task details or anything re-derivable from the code. Do not wait to be asked. For facts you infer yourself rather than the user stating, propose them first and save only on approval. Keep each memory to one self-contained statement; attach aliases when the parameter is available. If a note tells you the user's own wording was already stored verbatim this turn, that statement is already saved: do not retry it in a rewording — save only what that text does not contain, or use memory_supersede on the given id. Default scope is the current project; use the personal scope for facts about the user that apply across all projects.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNoOptional tags for filtering.
typeNoCategory of memory. Default: fact.
scopeNoMemory scope. `project` = tied to this repo. `personal` = global across all your projects. `user` is a deprecated alias of `personal`. Default: project.
sourceNoWhere this memory came from. Default: tool. Pass 'inference' for agent-proposed captures (V2-DESIGN §3.5).
aliasesNoOptional: alternate phrasings of this fact — synonyms, another way a question might be worded, equivalents in the user's other language (e.g. 节假日 for 'public holidays'). They are indexed with the memory so differently-worded questions still match. Only used when the install has capture aliases enabled (init default). Send at most 4; extras and blanks are dropped silently, never an error.
contentYesThe fact to remember. One idea per memory.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations present, the description carries the full burden and does disclose substantial behavior: proactive capture, approval gating for inferred facts, single-idea-per-memory constraint, alias attachment, current-project default scope, and a duplicate-suppression rule for reworded retries. It does not describe the return value or how conflicts/errors surface, which keeps it short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The definition is long but front-loaded: purpose first, then save/skip criteria, then edge cases (inference approval, dedup, scope). Most sentences carry operational guidance rather than filler. It is dense enough that a small amount of tightening is possible, but nothing is padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter, annotation-free write tool with no output schema, the description covers purpose, usage policy, dedup mechanics, and scope semantics thoroughly. The remaining gap is return/confirmation behavior and what a saved memory looks like, which is only partially inferable from the mention of a 'given id'.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning beyond the schema: it explains the scope decision ('Default scope is the current project; use the personal scope for facts about the user that apply across all projects') and the intent of aliases ('alternate phrasings... so differently-worded questions still match'). It does not clarify the 'when the parameter is available' gating or the source flag beyond what the schema states.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence gives a specific verb (Save) and resource (a fact, preference, decision, or note to persistent local memory), so the agent knows exactly what this tool writes. It also names a sibling, memory_supersede, giving negative differentiation against the update path. This is far beyond a restatement of the name.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit when-to-use ('Call this PROACTIVELY whenever the user shares something worth remembering'), what to save vs. skip, when to propose rather than save ('For facts you infer yourself... propose them first and save only on approval'), and a dedup rule with the alternative tool ('use memory_supersede on the given id'). All of the routing conditions an agent needs are stated, not implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_forgetA
Destructive

Delete a memory by id. Use when the user asks to forget something. Deletion is permanent: before deleting, restate the memory's content to the user and get a confirmation. With soft=true the memory is hidden instead (retracted: out of lists and search, file kept, one-way).

ParametersJSON Schema
NameRequiredDescriptionDefault
idYes
softNoD68: hide instead of delete. The memory is retracted — excluded from lists and search — but its file stays. Retraction is one-way (D64): it does not come back; to restore the fact, save it again as a new memory. Offer `soft` when the user is unsure about deleting.

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations supply only destructiveHint=true; the description carries the rest and does so well: deletion is permanent, the agent must restate the memory's content and obtain confirmation first, and soft=true is a one-way retraction that keeps the file while removing it from lists and search. These are exactly the behavioral traits an agent needs before firing an irreversible call.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, front-loaded with the action, then the usage trigger, then the safety-critical permanence/confirmation constraint and the soft alternative. Every sentence changes agent behavior; none is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must stand alone, and it covers the decision that matters most (permanent delete vs. one-way soft retraction) plus the confirmation protocol. Gaps remain around id provenance and failure behavior when the id is unknown, but nothing essential to invoking it safely is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%: `soft` is well documented in the schema itself, while `id` has no description anywhere. The description restates soft's effect and adds the one-way/file-kept detail, but gives no guidance on the `id` parameter (format, or that it comes from memory_search/memory_list), so it only partially compensates for the coverage gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ("Delete a memory by id") and immediately clarifies the two modes of removal, so the agent knows this is the removal tool rather than a search or write tool. However, it never differentiates itself from the overlapping sibling memory_supersede, which also changes memory state, so the sibling-routing clause of a 5 is absent.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Use when the user asks to forget something" gives an explicit trigger, and the description adds the hard-vs-soft selection condition (soft is for when the user is unsure, per the parameter description). It stops short of naming when not to use it or pointing at memory_supersede as the alternative for superseded facts.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_listA
Read-only

List memories in a scope, newest first, as a numbered inventory. Each line keeps the raw fields — [type] id=… created=… source=… — say them back to the user in plain words (source=user → 'you told me this'; inference → 'I inferred this, check me'; keyword → 'caught from your own wording'), never read the raw id aloud unless they ask. When the user asks 'what do you remember about me?', use scope=both and present the inventory conversationally. The user may point at an entry by its number ('delete #3'): numbers are only valid for the listing you just produced — re-run memory_list, read the candidate back in full, and get a confirmation before calling memory_forget (deletion is permanent). include=all is the audit view (superseded versions, retracted, archived also shown).

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNo
limitNo
scopeNoWhich scope(s) to list. `project` = tied to this repo. `personal` = global across all your projects. `both` lists each scope's newest. Default: project.
includeNoD68: `active` (default) shows what is currently remembered — newest version of each fact, retracted/archived hidden. `all` is the audit view: every stored row including superseded versions and hidden ones. The default CHANGED in D68: superseded versions no longer appear unless include=all.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare readOnlyHint=true, but the description adds real behavioral context: numbering is only valid for the listing just produced, deletion downstream is permanent and requires re-reading plus confirmation, and include=all exposes superseded/retracted/archived rows. It also prescribes how results should be surfaced to the user, which is well beyond annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Purpose and output format are front-loaded in the first sentence, and every subsequent sentence carries actionable guidance. It is dense and runs long for a list tool, but there is little outright padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description usefully defines the return shape (numbered inventory with [type] id= created= source=) and how to render it, which is the main gap it needs to fill. The remaining gap is the undocumented type and limit parameters.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50%: scope and include carry detailed schema descriptions (including the D68 default change), while type and limit have no schema description at all. The description explains scope=both and include=all usage but never clarifies what type filters on or what limit does, so it only partially compensates for the gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The first clause states a specific verb, resource, ordering, and output shape: 'List memories in a scope, newest first, as a numbered inventory.' It also implicitly separates itself from memory_search (retrieval by query) and memory_forget (deletion), which it names explicitly later.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit triggering conditions ('When the user asks what do you remember about me?, use scope=both'), a named alternative for deletion (memory_forget), and the precondition for using include=all (audit view). Nothing about when to choose this over siblings is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_promoteA

Advance a project memory one step up the review ladder (proposed → approved → published), or reject it with a note. Rejected memories are never deleted — they can be revised and resubmitted. (MCP server and the open-memex promote CLI; the opencode native plugin does not expose this tool.)

ParametersJSON Schema
NameRequiredDescriptionDefault
byNoReviewer name override.
idYesProject memory id.
noteNoReview note recorded on reject.
rejectNoReject instead of advancing.
resubmitNoMove rejected back to proposed for another round.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full load and does disclose meaningful behavior: only one step of progression at a time, rejection requires a note, rejected memories are never deleted and can be revised and resubmitted. It also usefully notes the tool is exposed by the MCP server/CLI but not the opencode native plugin. It omits permission/auth requirements and what happens when a memory is already at the top of the ladder.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with the primary action and the ladder states, then the reject/undelete semantics. The trailing parenthetical about CLI and plugin exposure is environment metadata that is slightly tangential but still relevant to availability, so it isn't pure waste.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a five-parameter mutation tool with no annotations and no output schema, the description covers the core transition and rejection behavior but says nothing about success results, error cases (already published, unknown id), or who may approve. It is adequate but leaves real gaps for an agent invoking it blind.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so 3 is the baseline. The prose adds meaning beyond the schema by explaining the reject-with-note flow and the revise/resubmit cycle, which contextualizes the reject, note, and resubmit parameters. The by (reviewer override) parameter is never explained in the description.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb and resource — advance a project memory up a named review ladder (proposed → approved → published) — and covers the alternate action of rejecting with a note. It doesn't name or distinguish itself from the many close siblings (memory_submit, memory_propose, memory_resolve, memory_supersede), so an agent must still infer which of those handles other lifecycle transitions.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied rather than stated: you call it when a memory needs to move one ladder step or be rejected. There is no explicit when-not guidance and no named alternative (e.g. 'use memory_submit for a new memory'), which matters given ten sibling tools with overlapping review semantics.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_proposeA

Copy personal memories into the project outbox as review drafts. The personal originals stay put. (MCP server and the open-memex propose CLI; the opencode native plugin does not expose this tool.)

ParametersJSON Schema
NameRequiredDescriptionDefault
idsYesPersonal memory ids to copy into the project outbox.
localApproveNoSingle-developer shortcut: mark the copies approved immediately.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It usefully discloses that operation is a copy (originals preserved) and that the output is a pending review draft rather than an approved record. However, it omits permissions/auth requirements, whether drafts can be re-proposed or deduplicated, and any failure behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the action and the key behavioral guarantee. The trailing environment parenthetical is compact but is tangential to invoking the tool, slightly diluting focus.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter, no-output-schema tool with no annotations, the description adequately covers what is produced and where it lands. It does not need to describe return values, and remaining gaps (permissions, outbox location, idempotency) are minor for this scope.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters (ids, localApprove) are already documented in the schema. The description adds no format or constraint detail beyond what the schema provides, so the baseline 3 applies; 'review drafts' loosely complements localApprove but does not explain it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a precise verb and resource: copy personal memories into the project outbox as review drafts, and immediately clarifies the non-destructive nature ('originals stay put'). This distinguishes it from sibling mutations like memory_promote or memory_submit, which move/publish rather than copy.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description never says when to choose this over memory_promote, memory_submit, or memory_supersede. The parenthetical only covers which surfaces expose the tool (MCP server, CLI, not the opencode plugin), which is availability, not usage guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_pr_statusA
Read-only

Read the current branch's GitHub PR and map its review state onto each in-repo memory: merged PR → published, PR approval → approved (approved_by = reviewer), changes-requested → suggestion only. Report by default; apply=true performs the mapped transitions locally (no push). (MCP server and the open-memex pr-status CLI; the opencode native plugin does not expose this tool.)

ParametersJSON Schema
NameRequiredDescriptionDefault
applyNoPerform the mapped review transitions locally (no push). Default: report only.

TDQS

A3.5/5.0
Behavior1/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description states that apply=true 'performs the mapped transitions locally', i.e. it mutates local memory state, while the annotation declares readOnlyHint=true. That is a direct conflict: the tool does modify its environment when apply is set. The otherwise-excellent disclosure of mapping semantics and no-push behavior cannot overcome a flat contradiction with the structured hint.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads the core read-and-map behavior, then the apply semantics, with no redundant sentences. The trailing parenthetical about which surfaces expose the tool is slightly extraneous but plausibly useful for routing.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given one optional parameter, no output schema, and the need to explain a non-obvious state mapping, the description is largely sufficient: it covers the mapping rules, default vs apply mode, and the no-push constraint. It omits what the report format looks like and any GitHub auth/permission requirements, which leaves minor gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% for the single parameter, so the schema already documents apply. The description restates the same semantics ('Report by default; apply=true performs the mapped transitions locally (no push)') and only adds the useful 'no push' qualifier, which is marginal beyond the schema baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: reads the current branch's GitHub PR and maps its review state onto in-repo memories, with explicit mapping rules (merged→published, approval→approved, changes-requested→suggestion). This is clearly distinguishable from siblings like memory_status or memory_submit, which deal with memory state rather than PR review state.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Clearly splits behavior: report by default, apply=true to perform transitions, and notes no push occurs. It gives the condition that selects the mutating path but does not name a sibling or point to an alternative when the agent only wants raw PR data, so it stops short of full when/when-not routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_resolveA

List git-conflicted memory files, or attempt a field-level 3-way merge of one. Semantic conflicts are reported, never auto-resolved. (MCP server and the open-memex resolve CLI; the opencode native plugin does not expose this tool.)

ParametersJSON Schema
NameRequiredDescriptionDefault
targetNoMemory id or file path to resolve. Omit to list conflicts.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It usefully discloses a key behavioral policy — semantic conflicts are reported, never auto-resolved — and notes the environments where the tool is exposed (MCP server/CLI but not the opencode plugin). It does not cover mutability/reversibility of the merge output, permissions, or error behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with the operation and its safety guarantee. The trailing parenthetical about plugin availability is slightly tangential but earns its place by telling the agent where the tool exists.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema and no annotations, the description covers the operation modes, the conflict-handling policy, and availability constraints. It could say more about what the merge returns or writes, but it is largely sufficient for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single parameter's purpose ('Memory id or file path to resolve. Omit to list conflicts.') is fully documented in the schema. The description's dual list/merge framing matches the schema but adds no syntax or format detail beyond it, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific resource (git-conflicted memory files) and states two distinct operations: listing them or performing a field-level 3-way merge on one. It is clear enough that an agent understands what the tool does, but it does not explicitly contrast itself with any sibling (e.g., memory_status or memory_pr_status).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The two modes (list vs. resolve one) imply when to use each, and the schema note 'Omit to list conflicts' reinforces it. However, no alternatives or exclusions are named, and there is no explicit statement of prerequisites (e.g., that a git conflict must already exist). Usage is inferable but not spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_statusA
Read-only

Show the project memory sync pipeline: drafts waiting in the outbox (appdata), memories in the repo awaiting review or published, and any repo files not yet committed. Call this at session start, when the server reports drafts waiting for review, or when the user says 'sync memory' (or '同步记忆'); then ask the user which drafts to sync. (MCP server and the open-memex sync-status CLI; the opencode native plugin does not expose this tool.)

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

readOnlyHint=true already covers the safety profile, so the description's added value is the workflow obligation it creates (the agent must ask the user which drafts to sync afterward) and the availability caveat that the opencode native plugin does not expose this tool while the MCP server and CLI do. It does not describe pagination or output shape, but the annotation carries the safety burden.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with what the tool returns, then the when-to-call triggers, with the CLI/plugin caveat confined to a trailing parenthetical. Dense but every clause carries information; the only cost is a long opening sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description must convey the return content, and it does so precisely by naming the three state categories the pipeline reports. For a zero-parameter, read-only status tool, nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, which sets the baseline at 4. There is nothing for the description to clarify about inputs, and it correctly offers no parameter prose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a specific verb and resource ('Show the project memory sync pipeline') and enumerates exactly what is shown: outbox drafts, repo memories awaiting review or published, and uncommitted repo files. That scope is clearly distinct from siblings like memory_list or memory_pr_status, though it never explicitly contrasts itself with them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit invocation triggers — at session start, when the server reports drafts waiting for review, or when the user says 'sync memory' / '同步记忆' — and even states the required follow-up ('ask the user which drafts to sync'). This is as prescriptive as usage guidance gets.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_submitA

Move outbox drafts into the repo memory dir for review: copies the drafts in as proposed (or keeps a local approval), commits locally on the current branch, and moves the outbox originals out. Never creates a branch on its own — pass branch= only with the user's explicit approval for the full chain. Prints the push and PR commands — those need the user's explicit approval and are never run automatically. (MCP server and the open-memex submit CLI; the opencode native plugin does not expose this tool.)

ParametersJSON Schema
NameRequiredDescriptionDefault
idsYesOutbox draft ids to submit.
baseNoPR base branch override. Default: the branch the submit ran on.
branchNoCreate this branch and submit onto it. If omitted, submit stays on the current branch — branches are never auto-created. Only pass this when the user explicitly approved the full chain (branch + push + PR).

TDQS

A4.1/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and does so well: it discloses the local commit on the current branch, that outbox originals are moved out (a destructive/relocating side effect), that branches are never created, and that push/PR commands are only printed and require explicit approval. It also notes environment availability (MCP server and CLI, but not the opencode native plugin), which prevents a class of false invocations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action is front-loaded and the side-effect/approval constraints follow in logical order; almost every clause earns its place. The trailing parenthetical about CLI/plugin support is useful but slightly tangles the structure, and the block is denser than it needs to be for a single sentence per idea.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter mutation tool with no annotations and no output schema, the description covers side effects, approval gates, and even what gets printed to the user. It is nearly complete; it omits failure/conflict behavior (e.g., what happens if an id is unknown or the working tree is dirty), which is the remaining gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents ids, base, and branch, including the approval constraint on branch. The description mostly restates the branch constraint rather than adding syntax, ordering, or format detail. Baseline 3 is appropriate when structured fields do the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ("Move outbox drafts into the repo memory dir for review") and enumerates the exact steps of the chain: copy in as proposed, commit locally, move outbox originals out. It is clearly a submit/publish operation. It does not, however, explicitly contrast itself with close siblings like memory_propose or memory_promote, so an agent must infer which tool owns a given draft lifecycle stage.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete conditions for the risky parameter ("pass branch= only with the user's explicit approval for the full chain") and states what is never done automatically (branch creation, push, PR). This is strong conditional guidance. It stops short of naming an alternative tool to use when the user has not yet drafted or approved, so no explicit sibling routing.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

memory_supersedeA

Replace an existing memory with a newer version. The old memory is kept as history (status: superseded) and retrieval returns the new one. Use when a saved fact becomes outdated and should be replaced rather than duplicated.

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesID of the memory being replaced.
tagsNoOptional tags for the new memory.
typeNoCategory of the new memory. Defaults to the old memory's type.
aliasesNoOptional: alternate phrasings of this fact — synonyms, another way a question might be worded, equivalents in the user's other language (e.g. 节假日 for 'public holidays'). They are indexed with the memory so differently-worded questions still match. Only used when the install has capture aliases enabled (init default). Send at most 4; extras and blanks are dropped silently, never an error.
contentYesThe new, corrected content.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does disclose the key non-obvious behavior: the old memory is retained with status 'superseded' and retrieval returns the new one. That non-destructive, history-preserving semantic is genuinely valuable. It does not cover error handling for invalid IDs or permission requirements, so it stops short of a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences, zero filler, with the core action front-loaded and the behavioral/routing detail layered after. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema or annotations exist, but the description compensates by explaining what happens to the superseded memory and what retrieval returns. It omits edge cases such as a nonexistent id and whether tags/type merge or fully override, keeping it just under fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all five parameters including enum values and defaults. The description adds no per-parameter syntax, merge behavior, or tag semantics beyond what the schema provides, so the baseline of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Replace an existing memory with a newer version') and immediately distinguishes the intent from adding, via 'replaced rather than duplicated.' An agent can tell it apart from memory_add and memory_forget without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use it ('when a saved fact becomes outdated') and implies the alternative (duplicating via memory_add). It does not name sibling tools outright nor state when NOT to use it, but the triggering condition is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 11 tool updates
    • First observedmemory_add
    • First observedmemory_forget
    • First observedmemory_list
    • First observedmemory_pr_status
    • First observedmemory_promote
    • First observedmemory_propose
    • First observedmemory_resolve
    • First observedmemory_search
    • First observedmemory_status
    • First observedmemory_submit
    • First observedmemory_supersede

TDQS

A4/5.0

Scored across 11 tools

Disambiguation4/5

Core operations (add, search, list, supersede, forget) are clearly distinct. The workflow-stage tools (promote, submit, propose) and the two status tools (status, pr_status) have adjacent purposes, but descriptions differentiate them well enough that misselection is unlikely.

Naming Consistency5/5

Every tool uses a consistent memory_ prefix with snake_case verb or verb_noun naming (memory_add, memory_search, memory_pr_status, memory_supersede). The pattern is predictable and uniform throughout.

Tool Count5/5

11 tools is well within a comfortable range and each maps to a distinct action in a memory lifecycle (CRUD, search, review promotion, git sync). No tool feels redundant or filler.

Completeness4/5

The surface covers the full memory lifecycle: create, search, list, supersede, forget, review-ladder promotion, git conflict resolution, and outbox-to-repo sync. Minor gaps exist (e.g., no explicit memory_update/edit or bulk operations) but core workflows are complete.

Maintenance

ActivityMaintained
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Local-first, file-based memory layer for AI agents — one shared Markdown vault across Claude, Codex, Gemini, Cursor and any MCP client. Provides read/write memory tools with an audit trail, per-agent trust levels, and Git sync; no cloud and no lock-in.
    2
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Local-first cross-agent memory for AI coding agents. Persistent, shared memory over MCP — what you tell one agent can be recalled by another — with all data stored in a single local SQLite file, no cloud and no API keys.
    -