Skip to content

OpenCode Adapter

OpenCode is an open-source AI coding agent that runs in the terminal. Unlike Claude Code, pi, and Codex (which write JSONL conversation files to central directories), OpenCode stores sessions in a SQLite database at .opencode/opencode.db relative to the working directory. This per-project storage model is why the adapter needs an adapter-owned conversation source to discover sessions.

Implement the core Adapter and Launchable interfaces.

  • Name: opencode
  • Binary: opencode
  • Match: scan command args for opencode (same pattern as claude/codex)
  • Discover: exec.LookPath("opencode")
  • Turn state: no PTY parsing (OpenCode’s animated bubbletea TUI makes byte inference unreliable); until a hook exists, sessions run the runner’s default turn model.
  • Launcher: { id: "opencode", label: "OpenCode", command: ["opencode"], description: "Coding Agent" }

This is enough for sessions to appear in gmux and be launchable from the UI. No working/idle status, no session discovery, no resume.

The adapter’s ConversationSource checks each configured project directory for .opencode/opencode.db and queries it for sessions.

OpenCode’s SQLite schema stores sessions and messages in two tables:

-- sessions table
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
message_count INTEGER NOT NULL DEFAULT 0,
updated_at INTEGER NOT NULL, -- Unix ms
created_at INTEGER NOT NULL -- Unix ms
-- messages table
id TEXT PRIMARY KEY,
session_id TEXT NOT NULL,
role TEXT NOT NULL,
parts TEXT NOT NULL default '[]', -- JSON array
finished_at INTEGER

The adapter would implement ConversationDescriber (with the session row’s id as the opaque conversation ref — ADR 0022) by:

  • Querying SELECT id, title, message_count, updated_at, created_at FROM sessions WHERE id = ?
  • Mapping results to ConversationInfo structs (updated_atLastActivity)

Enumeration comes from a ConversationSource that snapshots the sessions table and watches the WAL for changes, emitting row-id refs to the sink.

This requires a SQLite dependency. modernc.org/sqlite (pure Go, no CGo) is preferred to avoid requiring a C compiler in the build chain.

Detect working/idle state by monitoring the SQLite database for changes.

The approach: watch the .opencode/opencode.db-wal file via inotify. On change, query the messages table for the latest message in the active session. If the most recent message has role = "user" and no subsequent assistant message with finished_at IS NOT NULL, the session is working. Otherwise idle.

An alternative is to propose that OpenCode write a lightweight status file (e.g. .opencode/status.json) upstream, which a ConversationSource (or a future status hook) could consume.

Blocked on upstream. OpenCode has no --session <id> CLI flag; session resume is TUI-only via an in-app session picker dialog. Once upstream adds CLI resume support, the adapter can implement Resumer.