0
583
近 7 天 583
37.0
生态多维模型
8 小时前
2026-10-21
快速安装与配置
opencode.json写入当前项目的 opencode.json,只对这个仓库生效。
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-self-improvement@0.2.2"]
}写入 ~/.config/opencode/opencode.json,对所有项目生效。
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-self-improvement@0.2.2"]
}若你要在本地改造这个插件,先装到项目里再从本地路径引用。
shell
pnpm add -D opencode-self-improvementOpenCode 启动时会通过内嵌运行时自动加载 npm 依赖并缓存至本地目录,无需手动在全局环境执行安装。
Durable memory for opencode, plus a one-command per-repo setup.
Why is this here?
LLMs waste a lot of tokens reading and re-reading your code and asking you for clarifications you've already given it. This tells it to store those decisions so the next time you hit a similar part of the code, it knows more and gets to the answer faster.
What you get
memory_*tools — remember facts, decisions, and commands the agent should keep across sessions (memory_init,memory_remember,memory_recall,memory_update,memory_forget,memory_list,memory_undo,memory_evidence,memory_export,memory_import,memory_decay)./repo-init— for each repo: indexes the code graph and remembers the test/build commands, keyed to the git head. The command installs itself; no setup beyond the plugin.- Memory-aware compaction — durable memories are handed to the compaction summarizer, so a long session doesn't get an amnesia wipe exactly when it needs its memory most.
- Export / import (JSONL) —
memory_export/memory_importback the store up or move it between machines. Every imported row re-enters through the same write gates, so an export can't smuggle junk in. - Decay —
memory_decayretires stale open threads. Dry run by default; supersede-not-delete, snapshot-first, undoable. - Auto-capture (opt-in) — with
autoCaptureon, session-idle events get one cheap model pass that proposes memory candidates; every candidate still faces the same write gates. Off by default, so the install stays zero-token. - Automatically de-dupes similar memories and avoids contradictions by searching for existing memories before saving new ones.
- Write gates — every memory passes 4 checks before it sticks: code references are
verified against your actual repo, near-duplicates are collapsed, contradictions with
superseded memories are rejected. Blocked writes are logged with a reason
(
memory_evidence), and nothing is ever deleted — updates supersede the old row andmemory_undorolls back. - Automatically looks for insights when you complete the verification gates (tests, linting, etc)
- Always defaults to memories first before sending a prompt to the LLM, which saves tokens!
Token cost, on purpose
Memory plugins have a reputation for burning tokens and busting the provider's prompt cache on every message. This one is built the other way around:
- Epoch-frozen injection. The "Relevant durable memory" block is computed once per epoch — first prompt of a session, a change to the memory store, or a compaction — and stays byte-identical in between. A stable system prefix means the provider's prompt cache survives ordinary turns instead of being invalidated on every message.
- Hard character budget. The block is capped at 1200 characters by default (see Options) and trimmed at whole-memory boundaries — never cut mid-sentence.
- Evidence is never injected, and the standing system digest is two lines.
Measured on a deterministic workload (50 memories, 20 prompts, 3 mid-session store writes) using the plugin's real injection code:
| Policy | Recomputes | Injected chars (20 turns) | Avg/turn | Worst block |
|---|---|---|---|---|
| A — recompute per prompt, uncapped (pre-0.2) | 20 | 27748 | 1387.4 | 1575 |
| B — epoch freeze + 1200-char cap (0.2) | 4 | 20654 | 1032.7 | 1157 |
Policy B injects 25.6% fewer characters — and the bigger saving isn't even in the character count: B's block is byte-identical between store changes, so the prompt cache stays warm across ordinary turns. Reproduce (byte-identical output):
bun bench/inject-cost.ts
Recall quality — no models required
Memory plugins get told "keyword matching isn't good enough," and the usual prescription is a vector database or a local embedding model. This plugin ships neither — no model, no download, no API key, ever. The question is what that actually costs you, so we measured it:
bun bench:recall
A deterministic, auditable eval of the shipped matcher against classic BM25, on query classes assigned by measured vocabulary overlap with the right memory (store of 200; k=3 = the production injection limit):
| Query, vs. the stored memory | share | R@1 | R@3 |
|---|---|---|---|
| lexical — reuses your project's words | 46% | 100% | 100% |
| near — reworded, one overlap | 17% | 44% | 83% |
| strict — zero shared words | 37% | 0% | 0% |
What the benchmark bought us:
- In-project prompts are overwhelmingly lexical — you keep saying
bun test, "the rate limiter", "staging deploys". The shipped matcher nails those: 100% R@3, flat from store size 50 to 500. - It caught a real bug. Function words ("the", "what", "how") counted as matches, so nearly half the time the top memory was the wrong one. The matcher now ignores them on the query side: wrong-first rate fell 49% → 34%, and classic BM25 — a tuned scoring algorithm — no longer beats the shipped matcher on any class except the hopeless one.
- Strict paraphrase is the real lexical wall, and we won't pretend
otherwise. Nothing keyword-side crosses it. So instead of confident noise the
matcher now goes silent when the vocabulary shares nothing (a third of
strict queries inject nothing at all), and the agent's
memory_recallloop remains as the pull path. Embeddings are the only known crossing — the bench exposes a scorer seam if you want to measure them — but requiring an inference engine just to remember things is a non-starter for a zero-dependency plugin. - Caveats, honestly: the dataset is synthetic (52 memories / 105 queries, a fictional project), its class mix is deliberately adversarial (far richer in zero-overlap paraphrases than real prompts), and scoring is single-gold.
Full methodology, all store sizes: bench/recall-results.md
(regenerate with bun bench:recall).
Quick start
Add the plugin to your Opencode config (see install below) and restart Opencode.
In any repo, run:
/repo-init
That's it. Rerun /repo-init force after a refactor to refresh.
How to install
Add a plugins entry to your opencode config —
~/.config/opencode/opencode.jsonc (global) or any project opencode.jsonc:
{
"$schema": "https://opencode.ai/config.json",
"plugins": ["opencode-self-improvement@0.2.2"]
}
Opencode installs the package (and its dependencies) automatically with Bun at
startup. Quit and restart opencode; the plugin loads and /repo-init installs
itself. Nothing else to do.
Pin the exact version (as above). An unpinned entry resolves @latest exactly
once and is never re-resolved afterwards, so it silently sticks. To update,
bump the version in the config and restart. On Opencode v2 you can also manage
it with the CLI:
opencode plugin add opencode-self-improvement@0.2.2
opencode plugin update opencode-self-improvement
Install from a clone (development)
git clone https://github.com/abogartz/opencode-self-improvement.git
cd opencode-self-improvement
bun install
Then point the plugins entry at the local file instead:
{
"$schema": "https://opencode.ai/config.json",
"plugins": ["/full/path/to/opencode-self-improvement/index.ts"]
}
After changes, git pull and restart opencode.
Options
Zero configuration is the default. To tune the plugin, use the object form of
the plugin entry in opencode.json(c) instead of the plain string:
{
"plugins": [{ "package": "opencode-self-improvement", "options": { "injectBudget": 1200 } }]
}
| Option | Default | What it does |
|---|---|---|
injectBudget |
1200 |
Character cap on the injected relevance block, trimmed at whole-memory boundaries. Env fallback: OPENCODE_MEMORY_INJECT_BUDGET. |
autoCapture |
false (off) |
When on, each session-idle event makes one cheap model pass that proposes memory candidates. Every candidate still goes through the 4-gate write pipeline — capture can never bypass the gates. Off by default: the zero-token install stays zero-token. |
captureModel |
— | "provider/id" model used for auto-capture. Required when autoCapture is on; a missing or invalid value disables capture with a startup warning. |
captureMax |
3 |
Maximum candidates proposed per idle event. |
Code graph (optional)
/repo-init also indexes the repo into a queryable knowledge graph via
codebase-memory-mcp,
pinned to 0.11.0 as an optional dependency, so opencode's auto-install at
startup brings it in. If a copy is already on your PATH, that one is used
instead; override explicitly with OPENCODE_CBM_BIN=/path/to/codebase-memory-mcp.
When no graph binary is available, /repo-init still records scripts and the
init stamp — the graph is a lookup bonus, not a requirement (see below).
Manual install of the pinned binary (if you want it globally):
curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash
First use
Run /repo-init once in every repo you work in. It:
- indexes the repo's code graph (
codebase-memory-mcp), only when missing or forced; - stores the test/lint/typecheck commands as memories;
- writes an init stamp tied to the current git head.
Ongoing use is just the memory tools. Ask the agent to remember something and it
sticks across sessions; check what's stored with memory_list, refine with
memory_update, retract with memory_forget, roll back with memory_undo.
memory_update takes a query that picks the row: its id, a clock fragment such
as 00:11:25.867, or a unique substring of its text. Omit it to update the newest
entry of that scope and type. A query matching nothing, or matching several rows,
writes nothing and says so rather than updating the wrong memory.
Backup & move between machines
memory_export writes the live store as JSONL — one JSON object per line
({ts,type,scope,content,status,tags,issue}), active rows only (superseded
history stays in the store). memory_import reads such a file back. Defaults
to <memory-root>/exports/<timestamp>.jsonl; pass file to choose the path
and scope to export just one scope.
In practice you just ask the agent:
Export my memories to ~/memories.jsonl # memory_export
# …copy the file to the other machine…
Import ~/memories.jsonl # memory_import
Import is safe by construction: every row re-enters through the same 4-gate
write pipeline as memory_remember (tagged import, original tags preserved),
and the tool reports a tally of four outcomes per line —
| Outcome | Meaning |
|---|---|
promoted |
passed the gates and was stored |
collapsed |
near-duplicate of an existing memory; nothing written |
blocked |
rejected by a gate; reason is in memory_evidence |
skipped |
malformed line; never reaches the gates |
so re-running the same import is a no-op (everything collapses). Copying an export to a fresh machine is how you seed a new laptop from an old one.
Admin Tool
Editing and deleting memories is easy!
Run bun memory-view in your terminal and visit http://127.0.0.1:8787 in your browser.
Troubleshooting
| Problem | Fix |
|---|---|
memory_* tools not available |
The plugin didn't load. Restart opencode and check the plugins entry in your config. |
memory_remember says blocked |
A gate rejected the write (stale code reference, a cited path/to/file.ts that doesn't exist in the repo, overlap with a superseded memory, or an ambiguous claim). The reason is logged — check memory_evidence, then rephrase against current code and retry. |
/repo-init missing from the command list |
The self-install couldn't write to ~/.config/opencode/commands/ (e.g. read-only config dir). Create it, restart, or just ask the model to "init memory for this repo" — it calls the same tool. |
Init says Graph: unavailable |
codebase-memory-mcp couldn't start (not installed, or its once-only download is blocked). Install pinned 0.11.0 via the one-liner above, or point OPENCODE_CBM_BIN at the binary. Scripts are still remembered without it. |
| Stale plugin after an update | Bump the pinned version in the plugin entry (or opencode plugin update opencode-self-improvement on v2) and restart opencode. |
| Auto-capture does nothing | autoCapture needs a valid captureModel in provider/id form — a bad one disables capture with a startup warning. Candidates rejected by the write gates are logged as evidence, not errors; check memory_evidence. |
| Reset all memories | Delete ~/.config/opencode/memory/. |
同类生态推荐
Claude Memory
opencode-claude-memory
OpenCode plugin for Claude Code memory: persistent, local-first shared memory with Claude Code-compatible Markdown files, LLM recall, in-process auto extraction, and auto-dream consolidation
Kevin
@jmtrin/opencode-kevin
Kevin — Observa y aprende: capa de aprendizaje para OpenCode
Session Manager
@enerjizeit/opencode-session-manager
Never lose an opencode AI conversation — pin, back up, restore & auto-cleanup sessions, via natural language.