Ambient recall-and-capture for OpenCode. A thin TypeScript shell over the cairn CLI; all memory logic stays in Python.
| Hook | Behaviour |
|---|---|
experimental.chat.system.transform |
Before each LLM call, recalls current-project memories and injects them as quoted, untrusted historical evidence—not instructions. |
chat.message |
Buffers the latest user message text so the recall hook has a query string. |
event (session.idle / session.compacted) |
After the session ends or is compacted, fires cairn sweep to ingest the transcript and reindex. Sweep is non-blocking and fire-and-forget. |
No background daemon, no cloud dependency. The vault lives on disk (plain Markdown).
cairn CLI must be on $PATH:
pip install agentcairn # or: uv tool install agentcairn
cairn --versionSet CAIRN_VAULT (or accept the default ~/agentcairn) and ensure the OpenCode harness is registered:
cairn install opencode # installs this plugin + slash commands into ~/.config/opencode/, and writes the MCP server into opencode.jsoncairn install opencode does everything below. To install manually instead:
# Copy the plugin into OpenCode's plugin directory (auto-loaded at startup)
mkdir -p ~/.config/opencode/plugin
cp /path/to/integrations/opencode/agentcairn.ts ~/.config/opencode/plugin/agentcairn.ts(Optionally reference it explicitly in ~/.config/opencode/opencode.json:)
{
"plugin": ["~/.config/opencode/plugin/agentcairn.ts"]
}Copy the command files to make /recall and /remember available in OpenCode:
mkdir -p ~/.config/opencode/commands
cp integrations/opencode/commands/recall.md ~/.config/opencode/commands/
cp integrations/opencode/commands/remember.md ~/.config/opencode/commands//recall <query>— search vault and surface relevant notes/remember <fact>— write a durable note immediately
Ambient recall always calls cairn recall --scope project. The manual /recall
command keeps the CLI's cross-project default. Injected items are individually
quoted and tagged with available permalink/project provenance so note content
cannot blur into the surrounding system instructions.
The pure-logic tests use Node's built-in test runner (no extra deps):
node --test integrations/opencode/agentcairn.test.tsNode 22+ strips TypeScript types natively; no build step required.
OpenCode's plugin API is under active development. The following assumptions are made and isolated in the hook wiring in agentcairn.ts; a signature change only requires updating those hooks:
| Assumption | Basis |
|---|---|
experimental.chat.system.transform receives (input: { sessionID?: string; model: Model }, output: { system: string[] }). Mutating output.system appends text to the system prompt. |
@opencode-ai/plugin source, packages/plugin/src/index.ts, inspected 2026-06. |
chat.message receives output.parts as Part[]; text parts have { type: "text", text: string }. |
@opencode-ai/sdk types.gen.ts + plugin Hooks interface, inspected 2026-06. |
session.idle and session.compacted are event types dispatched through the single event hook (event.type === "session.idle" / "session.compacted"), not separate top-level Hooks keys. |
OpenCode docs notification example + packages/opencode/src/session/status.ts (Idle event defined as type: "session.idle"), inspected 2026-06. |
OpenCode loads .ts files directly via Bun — no pre-compilation needed. |
OpenCode plugin docs + loader behaviour, inspected 2026-06. |
Hook wiring should be verified in a live OpenCode session before shipping. See the inline // NOTE: comments in agentcairn.ts for per-hook reasoning.