Skip to content
Mimir

OpenCode Capture

opencodeOpenCode

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.

The canonical installer embeds and enrolls the plugin globally:

Terminal window
go run github.com/cloudboy-jh/mimir/cmd/mimir@latest install

The 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.

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.

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.