OpenCode Capture
OpenCode capture runs through the Mimir plugin at
plugins/opencode/mimir.ts. It observes
completed turns inside the harness, above provider transport and authentication.
OpenRouter traffic remains canonical at the Worker proxy. For the Zen
subscription, Claude API keys, Codex/ChatGPT OAuth, and other direct providers,
the plugin reads the completed user and assistant records from OpenCode’s
session store and uploads a bounded reconstructed exchange.
Install
Section titled “Install”The canonical installer embeds and enrolls the plugin globally:
go run github.com/cloudboy-jh/mimir/cmd/mimir@latest installThe managed target is the exact file
~/.config/opencode/plugins/mimir.ts. Mimir records ownership in
~/.mimir/install-receipt.json and operations in
~/.mimir/install-log.jsonl. $MIMIR_HOME replaces ~/.mimir when set.
Existing different content is a conflict and is preserved; a receipt-owned
file modified after installation is also preserved. Symlinked targets are
rejected.
Manual copying from plugins/opencode/mimir.ts
is recovery-only when the installer cannot be used. The plugin carries no
credentials and no configuration: it resolves the Worker URL and machine
token from
MIMIR_URL/MIMIR_TOKEN, then $MIMIR_HOME, then ~/.mimir/config and
~/.mimir/token as written by mimir setup or mimir login.
What It Reports
Section titled “What It Reports”Lifecycle events go to POST /sessions/:id/events on the Worker and are owned
by the session Durable Object (see
session-lifecycle.md):
- Turn — each completed assistant message (model, provider, token usage, latency), deduplicated by message ID.
- Heartbeat — every 60 seconds while the harness is active, plus on session create/update. This drives the dashboard liveness projection.
- End — on session deletion when OpenCode exposes that event. If the
process exits or dies first, the server-side silence timer finalizes the
session within ~10 minutes. Explicit end via
mimir session end <id>always works.
For a completed non-OpenRouter turn, POST /sessions/:id/exchanges receives
the reconstructed user and assistant parts, tool parts, model/provider, token
counts, timing, finish reason, and reported error when OpenCode exposes them.
Payloads are bounded to 512 KiB and individual strings to 64 KiB; parts may be
trimmed to fit. This is a redacted durable R2 exchange with searchable D1
metadata, but it is not a byte-for-byte provider request or response. If the
session-store read, normalization, or best-effort delivery fails, only the turn
event may remain.
The plugin never throws into OpenCode: delivery failures are swallowed and capture never interrupts the harness.
Safety Boundary
Section titled “Safety Boundary”Mimir does not modify general OpenCode configuration. OpenCode merges
JSON, JSONC, project, environment, and managed configuration, and rewriting
one guessed file can override user-owned provider, credential, plugin, and
command settings. Installation and an opted-in mimir update may create or
refresh only the exact plugin and skill files recorded in the Mimir receipt;
they never rewrite OpenCode JSON/JSONC, provider, credential, or command
configuration. mimir doctor checks state without taking ownership of
conflicting files.
Existing installations created by Mimir versions through v0.3.0 are not automatically removed or restored because Mimir did not retain the prior user values. Review any Mimir-created OpenCode files and provider entries before keeping them.
mimir uninstall removes unchanged receipt-owned plugin and skill files while
preserving modified, missing, unowned, non-regular, and symlinked paths. It does
not remove general OpenCode directories or configuration. The local Mimir
connection and Cloudflare deployment remain available for reconnection.
session_status remains the authoritative proof that a real session was
saved.
