# The `opencode-native` harness `omnigent opencode` runs the real **OpenCode** TUI in a runner-owned tmux pane and mirrors it into an Omnigent conversation. The runner starts one private `opencode serve` per conversation. An SSE forwarder mirrors OpenCode's events into the session, and web turns are injected over loopback HTTP. | Harness id | Aliases | Integration | |---|---|---| | `opencode-native` | `opencode`, `native-opencode` | Native server: `opencode serve` + `opencode --server` TUI | ## Supported version OpenCode **2.0.18 or a later 2.0.x patch** (`>=2.0.18,<2.1.0`), published on npm as `@opencode/cli`. Newer minors are refused until they are validated. OpenCode 1.x (`opencode-ai`) is no longer supported. A host running an unsupported version reports the harness as *outdated* until it is upgraded. `OMNIGENT_OPENCODE_SKIP_VERSION_CHECK=1` bypasses the gate at your own risk. ## Install and sign in npm rm -g opencode-ai # only if OpenCode 1.x is installed npm i -g @opencode/cli@2.0.32 opencode auth login # optional; free models need no sign-in omnigent opencode No sign-in is required. An installed OpenCode is ready to use with its built-in free models, such as `opencode/big-pickle`. Sign in to a provider only to use your own models. `omni setup` → OpenCode does the same install and offers the optional login. The web UI's setup dialog shows the same checklist for a remote host. Omnigent never removes packages; if `opencode-ai` is still installed, setup stops with a message asking you to remove it first. Omnigent stores no OpenCode credential. At launch, the runner writes a per-conversation `auth.json` merged from your legacy `auth.json` and your OpenCode 2.x credential store (`~/.local/share/opencode/opencode.db`; the store wins on conflicts), and OpenCode imports it once into the conversation's private database. Provider keys that exist only in the runner's environment (for example `ANTHROPIC_API_KEY`) are then connected through OpenCode's integration API at launch. With none of these, OpenCode runs on its free models. ## Agent YAML ```yaml spec_version: 1 name: my-opencode description: OpenCode with Omnigent policies and tools. executor: type: omnigent config: harness: opencode-native model: anthropic/ # optional; OpenCode's provider/model form prompt: | You are a careful coding agent. Keep changes scoped to the task. ``` - **Model override:** a model id is OpenCode's `provider/model`, for example `anthropic/` or `openai/`. When the agent is bound to the Omnigent or Databricks gateway, give a bare endpoint name and Omnigent qualifies it as `/`. `omnigent opencode --model` and `omni setup` → OpenCode → "Set default model" (`opencode_model`) set the same value. `/model ` in the web composer switches the running session. - **Instructions:** the agent's `prompt` / `instructions`, plus Omnigent's framework instructions, are written to the conversation's private `AGENTS.md` once per launch. The config's `instructions` key lists that file, but OpenCode 2.x does not read config `instructions` directly — it always reads the per-session `AGENTS.md` from its config dir. ## What is mirrored | OpenCode | Omnigent | |---|---| | Text and reasoning (`session.text.delta`, `session.reasoning.delta`) | Live streaming in the chat | | Tool calls (`shell`, `edit`, `subagent`, MCP tools) | Tool cards with output | | Permission requests (`permission.asked`) | Omnigent policies first; ASK becomes a web approval card. First answer wins between the web card and the TUI | | Question forms (`form.created`) | Web question card (single/multi select, boolean, number, text) | | Compaction (`session.compaction.*`, `/compact`) | Compaction status in the chat | | Step cost and tokens (`session.step.ended`, `session.usage.updated`) | Session cost and usage | | Model changes (TUI picker or `/model`) | Model badge | | Child sessions (`subagent`) | Sub-agent sessions | Every tool call asks: the runner writes a `permissions` rule `{action: "*", resource: "*", effect: "ask"}` into the per-conversation config and never passes `--auto`. This routes every call through the Omnigent policy engine. Omnigent's relay tools, and any MCP servers merged from your own OpenCode config, run with Code Mode off, so each call is asked under its own `_` name and a policy can gate it by name. OpenCode's own MCP builtins (`opencode_list_mcp_resources`, `opencode_read_mcp_resource`) can still reach any configured server and have no config switch to turn them off. They are gated as OS tools: `ask_on_os_tools` asks before each one. Images attached in the web UI are sent as `data:` URIs. Other attachments are flattened to text. A message sent during a running turn is delivered as a *steer*. Queued messages use OpenCode's own queue. ## One server per conversation Each conversation gets its own `opencode serve --stdio` process, its own password (`OPENCODE_PASSWORD`) and its own data directory, with its own `opencode.db`, under `$OMNIGENT_DATA_DIR/opencode-native/` (default `~/.omnigent/opencode-native/`). OpenCode 2.x scopes plugins, MCP servers, instructions (`AGENTS.md`) and the process environment to the server, and Omnigent binds the policy plugin, the tool relay and the agent's instructions per conversation; a shared server would need a session-to-conversation registry inside the plugin and a union of every agent's MCP servers and prompts. One process per conversation also keeps the fork snapshot and cleanup simple. Resume reattaches to the same data directory on the same host. A resume on a different host, or of a lost session, starts a new OpenCode session seeded with the Omnigent transcript. A same-agent fork into the same workspace clones the source OpenCode session natively from a snapshot of the source conversation's database (in-flight claims cleared); a fork from an earlier message, into another workspace, or whose source is unreachable replays the history as a text preamble instead. ## Known limits - **Policy token snapshot.** The policy plugin gets its Omnigent credentials when the server launches. A session that outlives that token's expiry fails open on the request/tool-result phases until it is relaunched. Tool-call approvals are unaffected, because they go through `permission.asked`. - **No shared server.** Each conversation runs its own `opencode serve`; one process never serves several conversations. - **No Direct mode.** `opencode acp` is not wired as an ACP harness. - **Session import** starts a short-lived `opencode serve` on a snapshot copy of your OpenCode 2.x database (never the live store) and reads sessions over its HTTP API. There is no `opencode export`. ## Troubleshooting - *Harness is outdated*: install `@opencode/cli@2.0.32` as shown above. - *Auth-shaped turn error*: the model's provider needs a sign-in. Run `opencode auth login` on the host, or pick a free `opencode/…` model. - Diagnostics: set `OMNIGENT_HARNESS_STDERR_ENABLED=1` before starting the host to copy OpenCode's server logs, redacted, into the runner log; startup errors then quote the last lines. See [harness-diagnostics.md](harness-diagnostics.md). The per-conversation bridge directory holds `opencode.json`, the policy plugin, and OpenCode's own log under `xdg-data/opencode/log/`.