Repository navigation
Releases
v2.0.1
Fixes
- Projects below the git root. OpenCode reports
snapshot.filesandvcs.statusrelative to the repository root, so in a project that is a subdirectory of the repository the touched files, the handoff file statuses and the anchor candidates offered to DREAM were wrong. They are now resolved against the worktree root and mapped to project-relative paths; files outside the project are dropped.
See CHANGELOG.md.
v2.0.0 — rem-memory
@cioffi_ai/opencode-memory continues as rem-memory 2.0 (OpenCode V2 only).
Highlights
- Code-anchored memories: project facts can point at
path#symbol; state (fresh / drifted / broken) is derived on every read, broken anchors are not surfaced,memory_inspect({ show: "stale" }). - Session handoff: a mechanical "where were we" note on session completion, enriched by DREAM at no extra model call, injected once on the next session's first request; new
memory_handofftool and/memory resume. - Built-in
/memorycommand (no manual copy);command: falseto keep a custom one. - DREAM works on OpenCode's free tier: internal generation moved from
generate.text(rejected there) tosession.generate, with system prompt and conversation stripped; tools are never executed. - Host-neutral engine (
src/engine) behind aHostinterface, ready for other agents.
Breaking
- Package renamed to
rem-memory; OpenCode V1 adapter removed. REM_MEMORY_*env vars (OPENCODE_MEMORY_*still read with a deprecation warning).- Default dir
~/.local/share/rem-memory, one-time copy of the old store (old dir untouched). - Store schema v3 (1.7.3 refuses it instead of reading it as empty).
See the upgrade guide in the README and CHANGELOG.md.
Verification
bun run check: 252 tests pass; retrieval benchmark (dev + held-out) byte-identical to 1.7.2.verify:packageagainst the real OpenCode 2.0.18 CLI with a local mock model.- End-to-end with the free
muse-spark-1.3model: anchors fresh/drifted/broken, mechanical + DREAM-enriched handoff, first-request injection,/memory resume(11/11).
v1.7.3 — final 1.x release
Final release of @cioffi_ai/opencode-memory. The package continues as rem-memory 2.0 (OpenCode V2 only); see the upgrade guide.
Fixes
- A store written by rem-memory 2.x (schema version 3 or later) is no longer read as an empty store, which let the next write overwrite every fact. 1.x now refuses to read or write it and reports an error instead.
Stay on 1.7.3 only if you still run OpenCode V1.
v1.7.2
Fixes
- #11 — Parallel memory writes: distinct explicit facts no longer overwrite one another because of similar wording. Jack's exact
Promise.allexample now preserves both preferences. Identical text still refreshes an entry; usememory_updateby ID for corrections. - Mutations queue across plugin instances sharing a directory, avoiding local lock-retry timeouts while retaining cross-process filesystem locking.
Summary controls (#12)
- Set
summary: falsein plugin options orOPENCODE_MEMORY_SUMMARY=0to hide the stored summary from model context andmemory_read, and prevent DREAM from generating or updating it. memory_clear({ summaryOnly: true })erases only the shared summary, retaining all facts. Do not combine it withscope.- Disabling the summary preserves it on disk. If summary/DREAM remains enabled, a later consolidation can generate it again after clearing.
Both OpenCode V1 and V2 adapters support these changes.
Verification
199 tests passed; 2 existing live-server tests skipped. Typecheck, build and clean packed-package checks passed for both adapters. Real OpenCode V2 2.0.18 checks passed with a local deterministic model, including Code Mode parallel writes, summary controls, DREAM, context injection, store migration and local-only privacy. Real V1 CLI coverage was unavailable; V1 adapter and isolated-package checks passed.
Install or update to @cioffi_ai/opencode-memory@1.7.2 and restart OpenCode.
v1.7.1
What's new
- DREAM and SURFACE can be switched off independently while explicit memory tools remain available (#8).
- Every memory setting can be configured in
opencode.jsoncfor OpenCode V1 and V2. Plugin options take precedence over environment variables and are isolated per plugin instance (#9). - Existing environment switches keep their 1.7.0 behavior.
Verification
- 181 tests passed; typecheck and build passed.
- The npm tarball installed and exercised the V1 and V2 adapters in an isolated directory.
- OpenCode V2 2.0.18 passed live checks with automatic memory active and with DREAM/SURFACE disabled through
opencode.jsoncusing a local mock model.
OpenCode V1 was checked through the adapter and isolated package tests; a real V1 CLI was not available for this release.
v1.7.0 — OpenCode V2 compatibility
OpenCode V2 can now load @cioffi_ai/opencode-memory without the default-export error reported in #6. The same package retains the OpenCode V1 adapter for 1.18.29+.
Highlights
- Native V2
id/setupadapter registers all ninememory_*tools, context hooks and event handling. - DREAM handles V2
session.execution.*completion events. V2 internal generation runs without helper sessions or exposed tools; V1 keeps its existing allow-none child sessions. - The package also exposes
./serverfor V2 directory loading and cleans up registrations on unload.
Install
For OpenCode V2 2.0.18+, add @cioffi_ai/opencode-memory@1.7.0 to the plugins array and restart OpenCode. OpenCode V1 1.18.29+ uses the singular plugin key.
Verification
The published npm package is byte-identical to the files and built bundle from merge commit 876d8e1. bun run check passed (168 tests; 2 live-server tests skipped). The downloaded package passed V1/V2 adapter checks: nine tools, V2 read/write, legacy store migration, context injection and cleanup. See CHANGELOG.md for details.
v1.6.0 — Retrieval Evaluation / Relevance
[1.6.0] — 2026-09-18
Retrieval Evaluation / Relevance. Retrieval semantics change (user-visible);
API compatible. No new features; no new packages (the plugin's runtime
dependency is now declared correctly, see below).
Fixed
memory_readmulti-term queries (issue #4).readQuerykeeps the
legacy contiguous substring match and adds an all-terms whole-token path:
coffee morningmatches "coffee in the morning" (any order,
non-contiguous) while short and technical terms are not dropped (AI,
UI,DB,C,R,no,C++,C#,Node.js,.NET). No stemming,
synonyms or accent folding; scope/category filters, score ordering and the
privacy policy are unchanged. Covered bytests/read-query.test.ts.- Identifier tokenization is symmetric in
memory_read. Query and memory
go through the same word grammar: a camelCase identifier matches its compact
form OR all of its case-boundary parts, soJavaScriptmatches both
"JavaScript" and "javascript"/"java script" anduserStorematches
"user store" (one half alone never satisfies it; query casing cannot change
the outcome). Same coverage intests/read-query.test.ts. - Unsafe substring matching removed. The matcher now respects token
boundaries:useno longer matchesuser,testno longer matches
pytest/greatest,redno longer matchesredesign. Confirmed by the
v1.5.1 evidence filebench/evidence/v1.5.1-fp-taxonomy.json. - Synonym groups restricted to substitutable terms. Opinion/preference
verbs were removed from the color group (they bridged "color" queries to
unrelated "favorite X" facts);designandprojectfamilies are split;
the standalone Italian wordbancano longer expands to database terms;
the dead phrase member"sistema operativo"was dropped. - camelCase identifiers tokenize correctly: the boundary splitter only
splits at lowercase→uppercase transitions ("RAM", "GB" stay whole;
"userStore"/"JavaScript" produce both parts and the whole form). - Runtime dependency declared (issues #2/#3).
@opencode-ai/pluginis
imported at load time by the publisheddist/index.js, so it moved from
devDependenciestodependencies: a clean install of the tarball now
resolves it. New release gatebun run verify:package(wired into
prepublishOnly) builds, packs, installs the tarball outside the checkout,
imports it by package name, asserts the ninememory_*tools are
registered and callsdispose()to release the timers.
Changed
- Candidate generation is separated from surfacing relevance.
retrieve()returns high-recall candidates; a named single-source
relevance gate (passesRelevanceGate) decides what enters the injected
block, shared by the plugin and the benchmark harness. - Every match carries provenance (
keyword,kind
exact/inflection/category,direct,viaquery term):
bun run bench --explain-negatives [--heldout] [--fp-only]emits the full
machine-readable taxonomy of what surfaced and why. - Morphology is explicit: plural s/es/ies, gerund -ing and participle -ed
match in both directions; nothing else does. - Reranker extracted to
src/rerank.tswith an injectable client:
abstention, invalid-answer fallback, timeout fallback, per-query caching,
zero-tool containment propagation and local-only filtering are unit-tested
with deterministic fakes (tests/reranker.test.ts). Behavior unchanged. - Benchmark: added Recall@1, entry-level surface precision with pooled
counts, false-abstention rate on positives, memory-level FP counts,
negative-outcome breakdown (abstained / core-only / non-core surfaced),
Wilson 95% confidence intervals, average memories surfaced; separate
HELD-OUT evaluation set (bench/scenarios-heldout.ts,--heldout)
written before the fixes and not iterated against.
Measured (lexical pipeline, reranker disabled)
| metric | v1.5.1 | v1.6.0 |
|---|---|---|
| Recall@5 (dev) | 100% | 100% |
| MRR (dev) | 95.2% | 95.2% |
| Surface precision macro (dev) | 65.8% | 63.2% |
| FPR negative queries (dev) | 39.5% (15/38) | 34.2% (13/38) |
| FPR held-out | 46.7% (7/15) | 26.7% (4/15) |
| False abstentions (dev) | 26.0% (20/77) | 31.2% (24/77) |
The four new false abstentions (kw-02, pa-10, co-05, ob-05) all relied on the
removed substring behavior: use matching inside the universal "user" token
(kw-02, co-05, ob-05) and uni matching inside "university" (pa-10).
All 13 remaining dev-set failures are exact-token or true-translation matches
whose intent differs — documented as the lexical ceiling; embeddings are NOT
yet justified by this evidence.
v1.5.1 — Trust Boundaries
Trust-boundaries hardening release. No new features; every change tightens an
existing guarantee.
Fixed
- Project isolation enforced end-to-end.
memory_readpreviously returned
project-scoped entries of ALL projects (no directory filter); theproject
inspector view listed other projects' entries;memory_clear(scope="project")
deleted every project's memories, not just the current project's;
memory_update/memory_forget/ feedback tools could mutate another
project's entries by id or text match. All lookups now go through a single
visibility policy (readableEntries/readQuery/clearProjectEntriesin
core.ts): global + current project only. Regression-tested with two
distinct directories plus global entries. - DREAM cross-project contamination. Consolidation dedup searched the whole
store: a fact extracted in project A could refresh/rewrite project B's
dreamed entry, be suppressed by B's explicit entry via similarity or topic
clash, or update/supersede/flag entries it was never shown. All consolidation
lookups are now restricted to the consolidating session's visible set. memory_writerewrite targeting. A write with an explicit scope could
overwrite a semantically similar entry from a DIFFERENT scope/project;
rewrite-dedup is now same-scope + same-project only (global and equivalent
project facts coexist by design).- Relevance gate silently defeated. The word "user" (and "utente") was not
in the retrieval stopword list while nearly every stored fact contains it, so
any query mentioning "user" matched every entry and the keyword relevance
gate introduced in 1.5.0 never actually gated anything. Found by the new
falsifiable benchmark (negative-query FP rate dropped from 76.3% to 39.5%
after the fix, Recall unchanged at 100%).
Changed
- Surfacing no longer refreshes recency. Automatic exposure used to bump
lastSeen, letting frequently surfaced memories stay artificially fresh
(a self-reinforcing retrieval loop, immortal under pruning). Exposure is now
recorded separately (lastSurfaced,surfacedCount) and never affects the
score; only explicit confirmation (memory_useful, writes,
consolidation refreshes) resets decay. Negative feedback never touches
recency. - Semantic reranker can abstain. With
OPENCODE_MEMORY_RERANK=1the
reranker may answer{"order":[]}when no candidate answers the question;
abstention surfaces nothing beyond the core slot instead of forcing a
ranking. Unparseable output still falls back to the deterministic lexical
order. Rerank orphan children are now garbage-collected like consolidation
ones. - Falsifiable benchmark.
bench/run.tsrewritten around a pure harness:
the old "false-surface rate" counted unsupported surfacing AFTER the keyword
gate had already filtered those entries (0.0% by construction). The suite now
has 38 negative scenarios across six categories that can genuinely fail
(clean no-match, hard lexical negatives, semantic distractors, cross-language
collisions, project-isolation negatives, core-only queries) and reports
separately candidate quality (Recall@5, MRR), surface precision, false-
positive / abstention rate and context overhead. Positive scenarios are
unchanged.
Security
- DREAM child sessions run with zero tools. The headless consolidation,
semantic-dedup and rerank sessions previously disabled only the five memory
tools by name — shell, filesystem, network fetch, MCP and subagent tools
remained available to a session processing untrusted conversation text.
They are now created with a single wildcard denial (tools: {"*": false}),
verified against OpenCode server source v1.18.0–v1.18.20 to remove the
entire toolset from the model-visible request (allow-none). Crash recovery,
orphan GC and at-least-once semantics are unchanged. A contract test pins
the deny-all shape so per-tool enumerations cannot creep back. - Honest
local-onlyprivacy contract. The previous claim "never leave
the machine" was not enforceable:memory_readreturned local-only entries
as tool output (which reaches the provider), and the DREAM dedup prompt
included them among existing entries. Local-only entries are now excluded
from EVERY model-visible path: SURFACE injection, DREAM entries and dedup
prompts, rerank candidates, all tool responses (memory_read,
memory_why,memory_inspect) and all mutating tools. The documented
access path is direct human inspection ofOPENCODE_MEMORY_DIR; remaining
limitations (the write call itself, prior transcript exposure, summary
generation by the provider) are documented in the README threat model.
v1.5.0
Local-first persistent memory for OpenCode — decay fix, provenance, contradiction lifecycle, memory tiers, hybrid retrieval, per-fact privacy and an evaluation suite.
What's new in 1.5.0
- Decay fix: time-based decay now applies exactly once in
score()(fromlastSeen);weightis a static importance baseline, so forgetting no longer depends on how often pruning runs. - Provenance: dreamed facts record their source session, messages, extraction time and confidence; new
memory_whytool audits where a memory comes from and why it ranks where it does. - Contradiction lifecycle: conflicting explicit facts are flagged CONFLICTED (never silently overwritten) and resolved via
memory_update/memory_write; replaced dreamed facts become SUPERSEDED tombstones. - Memory tiers:
core(always surfaced) /archival(on relevance) /temporary(auto-expiry) /pinned(never decays), with automatic v1 → v2 store migration. - Hybrid retrieval: lexical pipeline (scope filter + bilingual keyword expansion + time score) with optional semantic reranking stage (
OPENCODE_MEMORY_RERANK=1); off-topic queries surface only the core slot. - Retrieval feedback:
memory_useful/memory_irrelevanttune ranking from real usage. - Per-memory privacy:
sensitivity: "local-only"facts never leave the machine — not surfaced to providers, not sent during consolidation. - Memory Inspector:
/memorywith stats, conflicts, project scope and "why was this surfaced" breakdown. - Evaluation suite:
bun run bench— 90 scenarios across 13 failure modes (paraphrase, IT/EN cross-language, synonyms, distractors, contradictions, duplicates, isolation, obsolete, false positives, none, feedback, multi-expected).
Benchmark (lexical pipeline, suite of 90)
Recall@5: 100.0%
MRR (first hit): 95.0%
False-surface rate: 0.0%
Context overhead: 13.8 tokens/query
Install: add @cioffi_ai/opencode-memory to plugin in ~/.config/opencode/opencode.json(c) (or update your cached version to 1.5.0).
v1.1.0
Local-first persistent memory for OpenCode.
- WRITE → DREAM → SURFACE lifecycle
- Local JSON storage with file locking, no external database
- Headless child-session consolidation (at-least-once, crash recovery)
- Cross-language semantic deduplication with explicit-wins source hierarchy
- Topic-aware retrieval with bilingual (EN/IT) synonym expansion
- Orphan child-session GC
- Privacy: data stays on disk; only DREAM processing goes through your configured provider
Install: add @cioffi_ai/opencode-memory to plugin in ~/.config/opencode/opencode.json(c).