Local-only memory for OpenCode. The plugin extracts durable facts from conversations, stores them as Markdown files on your machine, injects relevant memories back into future OpenCode sessions, and provides a local Web UI for manual memory management.
- Stores memories locally as human-readable Markdown.
- Uses OpenCode's configured model path for automatic extraction.
- Keeps system memory instructions stable and injects dynamic memory through OpenCode's message transform hook.
- Starts a local Web UI automatically at
http://127.0.0.1:3765. - Avoids mem0, hosted vector stores, external databases, and provider-specific API keys.
- Keeps the agent-facing
memorytool disabled by default.
This repository includes a prebuilt plugin bundle at dist/index.js, so non-developers can install it without compiling TypeScript. Copy dist/index.js into one of OpenCode's plugin directories.
Developers can rebuild the bundle from source when needed:
bun install
bun run buildUse this when only one project should load the memory plugin:
mkdir -p .opencode/plugins
cp dist/index.js .opencode/plugins/opencode-memory.jsOn Windows PowerShell:
New-Item -ItemType Directory -Force -Path ".opencode/plugins"
Copy-Item -LiteralPath "dist/index.js" -Destination ".opencode/plugins/opencode-memory.js" -ForceUse this when every OpenCode project should load the memory plugin:
mkdir -p ~/.config/opencode/plugins
cp dist/index.js ~/.config/opencode/plugins/opencode-memory.jsOn Windows PowerShell:
New-Item -ItemType Directory -Force -Path "$HOME/.config/opencode/plugins"
Copy-Item -LiteralPath "dist/index.js" -Destination "$HOME/.config/opencode/plugins/opencode-memory.js" -ForceRestart OpenCode after copying the bundle. Running OpenCode processes do not reload plugin files automatically.
Memories are stored under the first available location:
OPENCODE_MEMORY_DIR$XDG_DATA_HOME/opencode/opencode-memory~/.local/share/opencode/opencode-memory
The store is split by scope:
global.md
users/default.md
projects/<project-key>.md
sessions/<session-id>.md
Each Markdown file contains readable memory content plus HTML-comment metadata:
<!-- memory
id: mem_global_no_push
tags: git, safety
source: manual-seed
createdAt: 2026-06-23T13:04:17.240Z
updatedAt: 2026-06-23T13:04:17.240Z
-->
Do not push to git remotes unless the user explicitly asks.The metadata is not injected into the agent prompt. It is used by the store and Web UI for IDs, tags, source tracking, and sorting. Writes use per-file lock directories and same-directory atomic rename to reduce lost updates when multiple OpenCode processes are running.
No secrets should be stored as memories.
| Scope | File | Injection behavior |
|---|---|---|
| Global | global.md |
Always injected. Use for cross-project rules and durable preferences. |
| User | users/default.md |
Always injected. Use for user-level preferences. |
| Project | projects/<project-key>.md |
Injected when relevant to the latest prompt. |
| Session | sessions/<session-id>.md |
Injected only for the matching session and only when relevant. |
- OpenCode emits
chat.message; the plugin records the latest user prompt for that session. - OpenCode emits
experimental.text.complete; the plugin records the assistant response. - The plugin asks OpenCode's own session API to run extraction in a separate internal extraction session.
- The extraction result is parsed with Zod.
- Empty, duplicate, malformed, low-confidence, or failed extraction results are ignored.
- Valid memory additions are written to the scoped Markdown store.
The extraction session is marked internal so the plugin skips its hooks and avoids recursive memory extraction.
- OpenCode calls
experimental.chat.system.transformbefore sending the prompt to the model. - The plugin appends only stable memory instructions to the system prompt.
- OpenCode calls
experimental.chat.messages.transformwith the outgoing message list. - The plugin loads local memories from the Markdown store and groups them by scope.
- The plugin inserts an advisory synthetic memory context message containing the
<opencode-memory>block.
Example injected memory context:
<opencode-memory>
These memories are durable background context. Do not repeat these memories unless useful; current user message wins; compacted conversation/history may overlap.
## Global Memory
- Do not push to git remotes unless the user explicitly asks.
## Project Memory
- This project stores memories in split Markdown files.
</opencode-memory>The block is advisory. The current user request still has priority over memory content.
The system prompt contains only stable memory instructions. Dynamic memory content is inserted later through experimental.chat.messages.transform, which keeps the provider-cache-friendly system prompt prefix stable across sessions. The plugin also keeps same-session memory rendering stable with a per-session render cache and filters project/session memories by relevance.
The plugin starts a local Web UI automatically when it loads:
http://127.0.0.1:3765
Features:
- List memories across all scopes.
- Search memory content.
- Add new memories manually.
- Edit memory content and tags.
- Delete memories.
- Filter by global, user, project, or session scope.
Configuration:
| Variable | Default | Description |
|---|---|---|
OPENCODE_MEMORY_WEB_HOST |
127.0.0.1 |
Host for the local Web UI. Keep localhost unless you understand the security risk. |
OPENCODE_MEMORY_WEB_PORT |
3765 |
Port for the local Web UI. |
OPENCODE_MEMORY_WEB_AUTOSTART |
enabled | Set to 0 to disable automatic Web UI startup. |
Multiple OpenCode processes share one local UI instance. The plugin checks /health, uses runtime metadata under .runtime/web, and hands ownership to another process when the current owner exits or becomes unhealthy.
There is no /open-memory or /show-memory command. OpenCode command templates route through the agent, so the UI is opened directly in the browser instead.
The agent-facing memory tool is disabled by default. Automatic extraction writes memories internally, and users manage memories through the Web UI.
Enable it only when needed:
| Value | Behavior |
|---|---|
unset / off |
Default. No agent-facing memory tool. |
read-only |
Register memory for search only. |
full |
Register memory for add, search, list, and delete. |
OPENCODE_MEMORY_AGENT_TOOL=read-only opencodeflowchart TD
A[OpenCode starts] --> B[Load opencode-memory plugin]
B --> C[Resolve memory directory]
C --> D[Start or reuse local Web UI]
B --> E[Register OpenCode hooks]
E --> F[Capture user prompts]
E --> G[Capture assistant responses]
E --> H[Transform system prompt]
E --> I[Transform chat messages]
sequenceDiagram
participant U as User
participant O as OpenCode
participant P as Memory Plugin
participant X as Internal Extraction Session
participant S as Markdown Store
U->>O: Send prompt
O->>P: chat.message
P->>P: Save latest prompt
O->>P: experimental.text.complete
P->>P: Save assistant response
P->>X: Extract durable memory with OpenCode model policy
X-->>P: JSON operations
P->>P: Parse, dedupe, confidence filter
P->>S: Write scoped Markdown memory
sequenceDiagram
participant O as OpenCode
participant P as Memory Plugin
participant S as Markdown Store
participant M as Model
O->>P: experimental.chat.system.transform
P-->>O: System prompt plus stable memory instructions
O->>P: experimental.chat.messages.transform
P->>S: Load all scoped memories
S-->>P: Memory records
P->>P: Always include global and user memories
P->>P: Filter project and session memories by relevance
P-->>O: Messages plus synthetic opencode-memory context
O->>M: Send transformed prompt
flowchart LR
R[opencode-memory directory] --> G[global.md]
R --> U[users/default.md]
R --> P[projects/project-key.md]
R --> S[sessions/session-id.md]
R --> W[.runtime/web]
Run the full local gate:
bun run test
bun run typecheck
bun run buildbun run test is preferred over naked bun test because the repository contains ignored reference projects under ref/.
This plugin intentionally does not depend on mem0, Supermemory, hosted vector stores, or provider-specific SDKs for runtime behavior:
- Memory data stays local.
- Markdown is the canonical store.
- Extraction uses OpenCode's configured model flow.
- No separate OpenAI, Anthropic, Gemini, Ollama, or cloud memory credentials are required.
Related projects inspired parts of the prompt and UI direction, but runtime behavior is OpenCode-native and local-first.