@eleboucher/opencode-memini

中文文档
0.7.38发布于 2026/11/01MITES Module零依赖

Automatic cross-session memory for opencode via memini — recall before each turn, capture after.

原始使用文档
文档目录9 节
  1. Recommended: the memory plugin
  2. Install
  3. opencode v2 (beta)
  4. Configure
  5. Repeat-injection cooldown
  6. Namespace resolution
  7. The memini_status tool
  8. Tests
  9. Alternative: manual MCP wire (tools, not automatic)

memini + opencode

opencode supports plugins — JS/TS modules that hook into its lifecycle. memini ships a native plugin in plugin/ that makes memory automatic: it recalls relevant memories before each turn and captures completed turns afterward, with no tool calls required from the model.

What it wires (two hooks):

  • chat.message — searches memini for the incoming user message and prepends the matches as a synthetic context part before the turn runs. It excludes this session's own captured turns (already in the live context), so they aren't echoed back as memory a turn behind; past sessions still recall.
  • event (session.idle) — once the session goes idle, stores the completed user/assistant turn back into memini (tagged with the session id) so it can be recalled later.

Install

Add the package to the plugin array in your opencode.json — a project opencode.json to scope it to one repo, or ~/.config/opencode/opencode.json for every project:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": ["@eleboucher/opencode-memini"]
}

opencode installs it from npm with Bun at startup.

opencode v2 (beta)

opencode's v2 preview (opencode2) uses a different plugin system: a plugins (plural) config array and a Plugin.define({ id, setup }) module — the v1 { id, server } contract does not load under it. @eleboucher/opencode-memini exports both, so the same package works on v1 and v2:

{
  "$schema": "https://opencode.ai/config.json",
  "plugins": ["@eleboucher/opencode-memini"],
}

@eleboucher/opencode-memini-v2 ships only the v2 module:

{
  "$schema": "https://opencode.ai/config.json",
  "plugins": ["@eleboucher/opencode-memini-v2"],
}

A bare entry resolves to the latest dist-tag, so that is where this package is published. opencode2 plugin add @eleboucher/opencode-memini-v2 writes the entry for you, using whatever specifier you pass it.

To run from a checkout, use the local entrypoint. opencode does not install dependencies for path-loaded plugins; this one has none, so nothing else is needed:

{
  "plugins": ["/absolute/path/to/memini/integrations/opencode/plugin/memini-v2.js"],
}

For options, use the documented object form:

{
  "plugins": [
    {
      "package": "@eleboucher/opencode-memini-v2",
      "options": { "namespace": "my-project" },
    },
  ],
}

The same options and env vars below apply. Recall injects into the request's system prompt (rather than a synthetic message part).

Beta status. Verified against opencode2 v0.0.0-next-16502 and re-checked through v0.0.0-beta-18050: the working request hook is context (the docs call it request); user/assistant turns are captured from session.inbox.enqueued, session.text.ended, and session.execution.* because these builds emit no session.idle and expose no session-message list method. next-17444 renamed the first event from session.input.admitted and moved its text from input.data to item.payload; the plugin reads both shapes, and registers both hook names so it remains compatible with the documented spelling.

The v2 plugin sends diagnostics through the structured ctx.app.log logger when available. Logging is best-effort and remains silent when that logger is absent or unavailable.

Configure

Pass options inline via the [name, options] form:

{
  "plugin": [["@eleboucher/opencode-memini", { "namespace": "my-project", "recall_limit": 8 }]]
}
OptionEnv varDefaultPurpose
base_urlMEMINI_BASE_URLhttp://localhost:8080memini REST base URL
namespaceMEMINI_NAMESPACEserver handshakeproject the memory is scoped to (X-Memini-Namespace)
homeMEMINI_HOMEunsetcaller's personal namespace, sent as X-Memini-Home; unset = no home leg
recallMEMINI_RECALLonfalse disables recall-before-turn
captureMEMINI_CAPTUREonfalse disables capture-after-turn
capture_child_sessionsMEMINI_CAPTURE_CHILD_SESSIONSoffcapture child sessions; off skips children and unknown ancestry (fail-closed), on records ancestry metadata
recall_limitMEMINI_RECALL_LIMIT3max memories injected per turn
recall_max_tokensMEMINI_INJECT_RECALL_MAX_TOK0hard ceiling on the recall-block tokens (0 = unbounded); the tail is dropped with a [… N item(s) truncated by token budget] footer
recall_min_scoreMEMINI_INJECT_RECALL_MIN_SCOREserver default 0.5 (0 pre-handshake)composite floor (>=) on the final ranked score, sent as min_rank_score (server-enforced; stripped + applied client-side on pre-min_rank_score servers, and for values ≥ 1)
inject_cooldown_msMEMINI_INJECT_COOLDOWN_MS1800000repeat-injection cooldown, time window (ms): an already-injected memory is held back this long before it may re-serve; 0 disables the time dimension
inject_cooldown_promptsMEMINI_INJECT_COOLDOWN_PROMPTS3repeat-injection cooldown, prompt window (counted per user message); 0 disables the prompt dimension; both cooldown knobs 0 = suppress for the whole session
recall_budget_msMEMINI_RECALL_BUDGET_MS2000how long a turn waits for recall before proceeding without it (0 = wait for the full timeout_ms)
timeout_msMEMINI_TIMEOUT_MS30000per-request timeout for memini requests
fallback_on_errorMEMINI_FALLBACKonfalse surfaces errors instead of degrading silently
auto_updateMEMINI_AUTO_UPDATEonfalse disables npm auto-update checks (opencode never re-fetches cached plugins otherwise)
—MEMINI_INJECT_LABELS—comma-separated label toggles for each bullet: tier, confidence, age, reason
—MEMINI_API_KEY—bearer token, if memini needs auth (env only — secret)
—MEMINI_REQUIRE_HTTPS—1 refuses to send the token over plaintext HTTP

opencode awaits chat.message before the model sees the message, so a slow or unreachable memini would otherwise freeze the turn for the full timeout_ms. Instead, recall races recall_budget_ms: if the search hasn't answered in time, the turn proceeds without memories and eventual results are discarded. Errors from the background request are still logged. The plugin also pings /healthz once at startup to warm the connection, so the first recall doesn't pay the DNS/TLS cold-start. Set recall_budget_ms: 0 to restore fully blocking same-turn injection.

Automatic captures leave tier selection to the server. Before retrieving messages, the plugin resolves session ancestry. Root sessions are captured by default; child sessions and sessions whose ancestry cannot be resolved are skipped by default. Set capture_child_sessions (or MEMINI_CAPTURE_CHILD_SESSIONS=1) to opt in; captures then include metadata.session_type (root, child, or unknown) and child captures also include metadata.parent_session_id.

Repeat-injection cooldown

The two inject_cooldown_* knobs are the windowed repeat-injection cooldown (shared with the Claude Code / hermes / openclaw integrations): an already-injected memory is excluded from recall (server-side via exclude_ids, with a client-side backstop) while it is inside either window — the time window (inject_cooldown_ms) or the prompt window (inject_cooldown_prompts, one prompt = one user message; in the v2 plugin, one request-hook fire) — and is re-served once both have lapsed. A memory whose content was updated in place re-injects immediately (the content-hash bypass), so a correction is never withheld for the window.

Behavior change (was: suppress forever). Earlier versions suppressed an injected memory for the whole session. With the default windows (30 min / 3 prompts) a long session is now re-reminded of a still-relevant memory once enough of the conversation has moved past it. Set both knobs to 0 to restore the old suppress-for-the-whole-session behavior.

Inline options win over the env vars. Secrets stay in the environment: set MEMINI_API_KEY (sent as Authorization: Bearer …), and optionally MEMINI_REQUIRE_HTTPS=1 to refuse plaintext HTTP, in the shell that launches opencode — not in opencode.json.

Every option is optional, namespace included: ["@eleboucher/opencode-memini"] runs with no config. On plugin load (and again every 10 minutes thereafter), the plugin calls POST /v1/handshake with what it cheaply knows about the project (the git remote/toplevel, when the worktree is a repo, plus the worktree basename) and lets the server resolve the namespace and behavioral settings (recall, capture, recall_limit, the recall-injection budget) the same way every other memini client does. The call is fail-soft: any error or a ~2.5s timeout falls back to purely local resolution below, so an unreachable or older memini never breaks a turn.

Namespace resolution

In full, in order: the namespace option / MEMINI_NAMESPACE > the server's handshake-resolved namespace > the git worktree basename > the built-in default (opencode).

The option/env tier wins over the handshake outright and deliberately: a namespace option in a global ~/.config/opencode/opencode.json, or a globally exported MEMINI_NAMESPACE, is this integration's own explicit pin and is honored as such rather than second-guessed by the server. Absent either, the server's resolution (which can draw on a pin, the git remote, or an operator's per-key default) wins over this plugin's own git worktree/default fallback, which only applies when the handshake itself is unavailable.

Each recall/capture setting follows the same shape: the plugin option beats MEMINI_NAMESPACE's sibling env vars above beats the server's resolved ClientSettings beats the built-in default baked into this plugin.

The memini_status tool

The plugin registers one tool, memini_status: read-only, no arguments. It reports the namespace in force and where it came from (the namespace option, MEMINI_NAMESPACE, the server's handshake, or the git worktree fallback), what it would be without the env/option pin, the connection settings (the API key fingerprinted, never printed), and warnings — a global MEMINI_NAMESPACE pin, a bearer token crossing plaintext HTTP.

There is no /memini:status slash command: opencode's plugin contract registers tools, not commands, and this plugin does not invent an API it does not have.

Tests

cd integrations/opencode/plugin && node --test

Alternative: manual MCP wire (tools, not automatic)

Instead of the plugin you can expose memini's memory_* tools to the model and let it call them on demand. opencode reads MCP servers from opencode.json under mcp. This wire gives the model the full tool set, including memory_recall (with tags / metadata filters), memory_list (query-less browse by tier / tags / metadata category), and memory_remember. Set metadata.category on writes to browse by subject later — see docs/categories.md.

Remote: merge opencode.json into your config.

Local (stdio): see opencode.local.json — opencode spawns memini mcp.

Mind the context budget: memini adds a handful of tools, which is light, but disable other large MCP servers you aren't using. Use the same X-Memini-Namespace as your other agents to share memory. my-project is a placeholder — replace it with your real project name, or drop the header and let memini auto-resolve from its own working directory.

版本与发布记录

@eleboucher/opencode-memini 共发布 98 个版本,首次发布于 2026/06/14;过去 12 个月发布了 98 个版本。

版本发布日期距今
0.7.38latest2026/11/012 天前
0.7.372026/10/2211 天前
0.7.362026/10/1420 天前
0.7.352026/10/1321 天前
0.7.342026/10/0529 天前
0.7.332026/10/0430 天前

关于 @eleboucher/opencode-memini 的常见问题

@eleboucher/opencode-memini 是什么?

自动跨会话存储器的开放代码,通过记忆-回忆之前,每回合,捕获后。

如何安装 @eleboucher/opencode-memini?

在项目目录运行 npm install @eleboucher/opencode-memini,或使用 pnpm add / yarn add / bun add。

@eleboucher/opencode-memini 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/eleboucher__opencode-memini 是否存在。

@eleboucher/opencode-memini 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@eleboucher/opencode-memini 可以商用吗?

@eleboucher/opencode-memini 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@eleboucher/opencode-memini 还在维护吗?

最新版本 0.7.38 发布于 2026/11/01(2 天前);至今共发布 98 个版本,其中过去 12 个月发布了 98 个;首次发布于 2026/06/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。