examples/opencode-memory-plugin/README.md
OpenCode plugin example that exposes OpenViking memories as explicit tools and automatically syncs conversation sessions into OpenViking.
Chinese install guide: INSTALL-ZH.md
This example uses OpenCode's tool mechanism to expose OpenViking capabilities as explicit agent-callable tools.
In practice, that means:
memcommitThis example focuses on explicit memory access, filesystem-style browsing, and session-to-memory synchronization inside OpenCode.
memsearchmemreadmembrowsememcommitcommit tasks to avoid repeated synchronous timeout failuresThis example contains:
openviking-memory.ts: the plugin implementation used by OpenCodeopenviking-config.example.json: template config.gitignore: ignores local runtime files after you copy the example into a workspaceStart the server first if it is not already running:
openviking-server --config ~/.openviking/ov.conf
Recommended location from the OpenCode docs:
~/.config/opencode/plugins
Install with:
mkdir -p ~/.config/opencode/plugins
cp examples/opencode-memory-plugin/openviking-memory.ts ~/.config/opencode/plugins/openviking-memory.ts
cp examples/opencode-memory-plugin/openviking-config.example.json ~/.config/opencode/plugins/openviking-config.json
cp examples/opencode-memory-plugin/.gitignore ~/.config/opencode/plugins/.gitignore
Then edit ~/.config/opencode/plugins/openviking-config.json.
OpenCode auto-discovers first-level *.ts and *.js files under ~/.config/opencode/plugins, so no explicit plugin entry is required in ~/.config/opencode/opencode.json.
This plugin also works if you intentionally place it in a workspace-local plugin directory, because it stores config and runtime files next to the plugin file itself.
Recommended: provide the API key and tenant identity via environment variables instead of writing them into the config file:
export OPENVIKING_API_KEY="your-api-key-here"
export OPENVIKING_ACCOUNT="default"
export OPENVIKING_USER="opencode"
Example config:
{
"endpoint": "http://localhost:1933",
"apiKey": "",
"account": "default",
"user": "opencode",
"enabled": true,
"timeoutMs": 30000,
"autoCommit": {
"enabled": true,
"intervalMinutes": 10
}
}
account and user are sent as X-OpenViking-Account and X-OpenViking-User tenant headers on every plugin API request; leave them empty to omit the headers.
The environment variables OPENVIKING_API_KEY, OPENVIKING_ACCOUNT, and OPENVIKING_USER take precedence over the config file.
After installation, the plugin creates these local files next to the plugin file:
openviking-config.jsonopenviking-memory.logopenviking-session-map.jsonThese are runtime artifacts and should not be committed.
memsearchUnified search across memories, resources, and skills.
Parameters:
query: search querytarget_uri?: narrow search to a URI prefix such as viking://user/memories/mode?: auto | fast | deeplimit?: max resultsscore_threshold?: optional minimum scorememreadRead content from a specific viking:// URI.
Parameters:
uri: target URIlevel?: auto | abstract | overview | readmembrowseBrowse the OpenViking filesystem layout.
Parameters:
uri: target URIview?: list | tree | statrecursive?: only for view: "list"simple?: only for view: "list"memcommitTrigger immediate memory extraction for the current session.
Parameters:
session_id?: optional explicit OpenViking session IDReturns background task progress or completion details, including task_id, per-category memories_extracted, and archived.
Search and then read:
const results = await memsearch({
query: "user coding preferences",
target_uri: "viking://user/memories/",
mode: "auto"
})
const content = await memread({
uri: results[0].uri,
level: "auto"
})
Browse first:
const tree = await membrowse({
uri: "viking://resources/",
view: "tree"
})
Force a mid-session commit:
const result = await memcommit({})
The plugin can automatically search OpenViking memories and inject relevant context into each user message before it reaches the LLM. This uses OpenCode's chat.message hook to prepend a synthetic memory part to the outgoing message.
Note: This feature relies on OpenCode's
chat.messagehook contract. The hook signature or behavior may change in future OpenCode versions.
<relevant-memories> XML blocksynthetic: true) on the outgoing message so the memory persists across turns without polluting user inputIf OpenViking is unavailable or the search times out, the message is passed through unchanged.
Add an autoRecall block to your openviking-config.json to customize recall behavior:
enabled: boolean (default: true) — enable or disable automatic memory recalllimit: number (default: 6) — maximum number of memories to inject (1–50)scoreThreshold: number (default: 0.15) — minimum relevance score for a memory to be included (0–1)maxContentChars: number (default: 500) — maximum characters per individual memory contentpreferAbstract: boolean (default: true) — prefer abstract (L0) content over full (L2) content when availabletokenBudget: number (default: 2000) — approximate total token budget for injected memories (100–10000, estimated at 4 chars per token){
"endpoint": "http://localhost:1933",
"apiKey": "",
"account": "default",
"user": "opencode",
"enabled": true,
"timeoutMs": 30000,
"autoCommit": {
"enabled": true,
"intervalMinutes": 10
},
"autoRecall": {
"enabled": true,
"limit": 6,
"scoreThreshold": 0.15,
"maxContentChars": 500,
"preferAbstract": true,
"tokenBudget": 2000
}
}
To disable recall, set "autoRecall": { "enabled": false }.
*.ts file in the OpenCode plugins directory~/.config/opencode/plugins/openviking-memory.tsopenviking-server is running and reachable at the configured endpointOPENVIKING_API_KEY or openviking-config.jsonvlm and embedding configuration