Skip to content

Build1 publisher3 min readPublished

This OpenCode plugin keeps a coding agent's memory in Markdown you can open and fix

The opencode-agent-memory plugin gives an OpenCode agent scoped Markdown blocks it rewrites through three tools, plus an opt-in journal it can search locally but never revise. The maintainer documents the failure modes himself.

The Engineer · Build desk

What happened

  • The opencode-agent-memory plugin hands an OpenCode agent three tools, memory_list, memory_set and memory_replace, over plain Markdown files that carry YAML frontmatter.
  • Global blocks sit in ~/.config/opencode/memory and follow the user across projects, while project blocks sit in .opencode/memory, persist across sessions in that codebase, and are gitignored automatically.
  • An optional append-only journal adds journal_write, journal_search and journal_read, storing each entry as Markdown stamped with the project, model, provider, agent and session it came from.
  • Journal search embeds entries on the machine with paraphrase-multilingual-MiniLM-L12-v2 at 384 dimensions through Transformers.js, so journal content is not sent to a hosted API to be searched.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint Automatic gitignoring keeps a codebase's accumulated agent state out of commits, and it also means that state never reaches code review and a fresh clone begins with none of it.
  • constraint Append-only with no update or delete tool means a wrong journal entry stays retrievable for as long as the file exists, and only a person working on disk can take it out.
  • cost A journal-enabled install puts six tools in the agent's tool list and a locally cached embedding model into the plugin process.
  • decision Keeping the journal off by default puts the collection decision on the operator, who has to decide that a searchable local record of the agent's conclusions is worth having.

Relevance in this plugin comes down to one frontmatter field. Each block carries a `description` telling the agent how to use it, and without one the agent gets a generic fallback and does not know when the block is relevant [6]. The maintainer, who publishes the experimental plugin under the `@ghilteras` scope, says this mirrors the emphasis Letta puts on describing memory blocks well [2][6]. So the retrieval rule for every block is prose a human writes and keeps current [5]. First run seeds three: `persona` and `human` globally, `project` for the current codebase [8].

The journal is off unless you turn it on, and turning it on is one line in `~/.config/opencode/agent-memory.json`: `{"journal": {"enabled": true}}` [10]. "I do not want the agent rewriting history; I want it to be able to find what happened last month," the maintainer wrote [11]. He is direct about what the log holds. It records what the agent observed, including wrong conclusions, and "Treat it as a log, not a knowledge base" [18].

Each `.embedding` sidecar stores `{ v, model, dimension, vector }`, and when the stored dimension does not match the current model the entry degrades to text matching instead of failing the search; bare-array embeddings written by earlier versions still read [13]. The in-memory index is per store instance and re-reads an entry only when the `.md` file or its sidecar changes by mtime plus size, so regenerating or deleting a sidecar is picked up on the next search without a restart [14]. An edit that leaves both mtime and size unchanged will not be re-read [2]. Both details look like the product of something having broken earlier. The model is warmed in the background at plugin init so the first search after a restart does not pay the cold load [14].

Since v0.4.2, a query whose text matches an entry title, in either direction and case-insensitively, is guaranteed a high score [15]. Titles work as keys, and semantic ranking is what you fall back on when you cannot remember the title [6].

The comparison with a flat instruction file is the author's own: he says he relies on AGENTS.md heavily, and describes it as a single document with no notion of scope, no size enforcement and no dedicated operations for the agent to maintain it [3]. The failure he is chasing is ordinary. Conventions, debugging decisions and preferences get re-explained after a restart or after context compaction [1]. The post reports no evaluation of retrieval quality, and he calls the plugin experimental [20]. Each block gets a size limit so it cannot silently grow without bound [7], and the caps and descriptions help the agent judge relevance without making the content true [17]. "Stale memory is worse than no memory," the maintainer wrote [16].

What to watch

  • Any published benchmark of scoped block retrieval against a single flat instruction file, on hit rate or tokens spent.
  • Whether the journal tools gain a supersede or delete operation; that would end the append-only property the maintainer wants.
  • Whether the v0.4.2 title-match floor holds up once a journal runs to several hundred entries with overlapping titles.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories