II.
Page overview
Reference · livepage:docs-agent-mux-reference-12-built-in-adapters
Built-in Adapter Implementations overview
Inspect the raw attributes, linked wiki pages, and inbound or outbound graph edges for page:docs-agent-mux-reference-12-built-in-adapters.
Attributes
nodeKind
Page
sourcePath
docs/agent-mux/reference/12-built-in-adapters.md
sourceKind
repo-docs
title
Built-in Adapter Implementations
displayName
Built-in Adapter Implementations
slug
docs/agent-mux/reference/12-built-in-adapters
articlePath
wiki/docs/agent-mux/reference/12-built-in-adapters.md
article
# Built-in Adapter Implementations
**Specification v1.0** | `@a5c-ai/agent-mux`
> **SCOPE EXTENSION:** hermes-agent (`@NousResearch/hermes-agent`) is included as a 10th supported agent per explicit project requirements from the project owner. It extends the original scope document's 9 built-in agents. All hermes-specific content in this spec is marked with this same scope extension note.
>
> **SCOPE EXTENSION (2026-04):** `agent-mux-remote` (11th, transport-only) and `qwen` (12th, Alibaba Qwen Code — a gemini-cli fork with MCP support) were added beyond the original 10. See [agents/qwen.md](agents/qwen.md) for qwen usage.
---
## 1. Overview
This specification defines the implementation details for all 13 built-in adapter implementations in `@a5c-ai/agent-mux`. Each adapter extends `BaseAgentAdapter` (spec 05 §4) and translates between the unified `AgentAdapter` interface and the native CLI of its target agent.
This is the reference document for adapter authors and consumers who need to understand per-agent behavioral differences. It covers CLI arguments, event parsing, session formats, thinking normalization, install methods, auth detection, plugin delegation, and platform-specific notes for each adapter.
### 1.1 Cross-References
| Type / Concept | Spec | Section |
|---|---|---|
| `AgentAdapter` interface | `05-adapter-system.md` | 2 |
| `BaseAgentAdapter` abstract class | `05-adapter-system.md` | 4 |
| `SpawnArgs` type | `05-adapter-system.md` | 3.1 |
| `AdapterRegistry` | `05-adapter-system.md` | 5 |
| `AgentCapabilities` | `06-capabilities-and-models.md` | 2 |
| `ModelCapabilities` | `06-capabilities-and-models.md` | 5 |
| Thinking normalization tables | `06-capabilities-and-models.md` | 8 |
| Install metadata | `06-capabilities-and-models.md` | 7 |
| Capability profiles (complete) | `06-capabilities-and-models.md` | 12 |
| Plugin support per agent | `06-capabilities-and-models.md` | 9 |
| Config file locations | `08-config-and-auth.md` | 7 |
| Auth detection strategies | `08-config-and-auth.md` | 10.1 |
| AuthMethod, AuthState | `08-config-and-auth.md` | 10, 9 |
| Session formats | `07-session-manager.md` | 5 |
| Process lifecycle, PTY | `11-process-lifecycle-and-platform.md` | 6 |
| Platform support matrix | `11-process-lifecycle-and-platform.md` | 5 |
| `AgentEvent` union | `04-agent-events.md` | 4 |
| `ErrorCode` union | `01-core-types-and-client.md` | 3.1 |
| Scope §20 summary table | `agent-mux-scope.md` | 20 |
---
## 2. Built-in Adapter Summary
From scope §20, extended with hermes-agent:
| Adapter | CLI | `cliCommand` | Session | Stream | Resume | Fork | Thinking | MCP | Skills | Plugins | ACP | Platforms |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Claude Code | `claude` | `claude` | JSONL | yes | yes | yes | yes | yes | yes | partial | no | all |
| Codex CLI | `codex` | `codex` | JSONL | yes | no | no | yes | yes | no | no | no | all |
| Gemini CLI | `gemini` | `gemini` | JSONL | yes | no | no | yes | yes | no | no | no | all |
| Copilot CLI | `gh copilot` | `copilot` | JSON | yes | no | no | no | no | no | no | no | all |
| Cursor | `cursor` | `cursor` | SQLite | partial | no | no | model-dep | yes | no | yes | no | all |
| OpenCode | `opencode` | `opencode` | SQLite | yes | yes | yes | model-dep | yes | yes | yes | yes | all |
| OpenCode HTTP | `opencode serve` | `opencode-http` | SQLite | yes | yes | yes | model-dep | yes | yes | yes | yes | all |
| Pi | `pi` | `pi` | JSONL tree | yes | yes | yes | model-dep | no | yes | yes | yes | all |
| omp | `omp` | `omp` | JSONL tree | yes | yes | yes | yes | no | yes | yes | yes | all (Win partial) |
| OpenClaw | `openclaw` | `openclaw` | JSON | partial | no | no | model-dep | yes | yes | yes | no | all |
| hermes | `hermes` | `hermes` | SQLite | yes | yes | no | no | yes | yes | yes | yes | darwin/linux |
> **SCOPE EXTENSION:** hermes-agent row added.
**Column notes:**
- **CLI**: The actual command invoked. For copilot, the command is `gh` with args `['copilot', ...]` (see §5).
- **`cliCommand`**: The `AgentAdapter.cliCommand` property value (logical agent name).
- **Stream**: "yes" = full text+tool+thinking streaming; "partial" = text streaming only.
- **Resume**: Whether `canResume: true` in capabilities.
- **Fork**: Whether `canFork: true` in capabilities.
- **Thinking**: "yes" = always supported; "model-dep" = depends on `ModelCapabilities.supportsThinking`; "no" = not supported.
- **Plugins**: "partial" for Claude = limited to skill-directory and mcp-server formats via `--add-dir`.
- **Platforms**: "all" = darwin, linux, win32; "all (Win partial)" = all three platforms but with reduced Windows functionality; "darwin/linux" = no native Windows support.
---
## 3. Claude Code Adapter
> **Implementation note (2026-04):** The `claude` adapter now uses Claude Code's real `--print` + `--input-format stream-json` + `--output-format stream-json` subprocess transport for live sessions. That lets agent-mux keep a single Claude subprocess alive and deliver later user turns over stdin while continuing to parse structured stream-json events from stdout. `claude remote-control` is now modeled separately as the `claude-remote-control` adapter: an external-host bridge surface for Claude.ai / Claude app sessions, not a local browser chat transport. Claude channels remain a separate MCP-mediated Claude surface and are still not represented as a first-class adapter.
### 3.1 Identity
| Property | Value |
|---|---|
| `agent` | `'claude'` |
| `displayName` | `'Claude Code'` |
| `cliCommand` | `'claude'` |
| `minVersion` | `'1.0.0'` |
### 3.2 buildSpawnArgs
```typescript
// Key CLI arguments
SpawnArgs {
command: 'claude',
args: [
'--print', // Required for structured output
'--input-format', 'stream-json', // Persistent stdin-driven user turns
'--output-format', 'stream-json', // Streaming JSON output
'--replay-user-messages', // Echo stdin user turns back on stdout
'--model', modelId, // Model selection
'--thinking-budget', budgetTokens, // Thinking (when enabled)
'--session', sessionId, // Resume session
'--add-dir', skillDir, // Skill directories
'--system', systemPrompt, // System prompt injection
'--system-mode', systemPromptMode, // prepend | append | replace
'--max-turns', maxTurns,
],
env: { ANTHROPIC_API_KEY: apiKey },
usePty: false,
}
```
**Prompt delivery:** Interactive Claude sessions use `SpawnArgs.stdin` and send newline-delimited `stream-json` user envelopes (`{ type: 'user', message: { role: 'user', content }, parent_tool_use_id: null }`) into the live Claude subprocess. Explicit `nonInteractive=true` falls back to a one-shot `--print <prompt>` invocation that exits after the first turn.
### 3.3 Event Parsing
**Native format:** Newline-delimited JSON (stream-json). Each line is a JSON object with a `type` field.
**Key native event types and their AgentEvent mappings:**
| Native type | AgentEvent type(s) |
|---|---|
| `message_start` | `message_start` |
| `content_block_start` (text) | (consumed internally — text streaming begins) |
| `content_block_delta` (text) | `text_delta` |
| `content_block_start` (thinking) | `thinking_start` |
| `content_block_delta` (thinking) | `thinking_delta` |
| `content_block_stop` (thinking) | `thinking_stop` |
| `content_block_start` (tool_use) | `tool_call_start` |
| `content_block_delta` (tool_use) | `tool_input_delta` (incremental tool input) |
| `content_block_stop` (tool_use) | `tool_call_ready` |
| replayed `user` event with `parent_tool_use_id` + `tool_use_result` | `tool_result` |
| `message_delta` | (cost extraction → `cost` event) |
| `message_stop` | `message_stop` |
| `system.status=requesting` | `turn_start` |
| `result` | `turn_end` (+ fallback `message_stop` / `cost` when needed) |
**Session lifecycle events:** When resuming a session (`--session`), the adapter emits `session_resume` after `session_start`. When forking (`--fork`), it emits `session_fork`. These events are synthesized by the adapter from the session metadata, not from native Claude output.
### 3.4 Session Format
- **Location:** `~/.claude/projects/<hash>/` where `<hash>` is a content-hash of the project path.
- **Format:** JSONL (one JSON object per line).
- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'file'`.
### 3.5 Thinking Normalization
| Effort | Mapping | CLI arg |
|---|---|---|
| `'low'` | `budget_tokens: 1024` | `--thinking-budget 1024` |
| `'medium'` | `budget_tokens: 8192` | `--thinking-budget 8192` |
| `'high'` | `budget_tokens: 32768` | `--thinking-budget 32768` |
| `'max'` | `budget_tokens: max_budget_tokens` | `--thinking-budget max_budget_tokens` |
`thinkingBudgetTokens` is passed through directly. `thinkingOverride` is merged last.
### 3.6 Install Methods
| Platform | Type | Command |
|---|---|---|
| all | npm | `npm install -g @anthropic-ai/claude-code` |
| darwin | brew | `brew install claude-code` |
### 3.7 Auth Detection
- **Primary:** `browser_login` — inspects session token files in `~/.claude/` (per spec 08 §10.1).
- **Alternative:** `api_key` — checks `ANTHROPIC_API_KEY` environment variable.
> **Cross-spec reconciliation:** Spec 06 §12.1 lists auth methods as `['api-key','oauth']` while spec 08 §10.1 lists primary method as `browser_login`. This spec follows spec 08 as the authoritative source for auth detection. The `browser_login` method describes the detection strategy (checking local session tokens), while `api-key` and `oauth` in spec 06 describe the underlying credential types.
### 3.8 Plugin Support
- **`supportsPlugins`:** `true` (partial — limited to skill-directory and mcp-server formats).
- **Formats:** `['skill-directory', 'mcp-server']`.
- **Mechanism:** `--add-dir` flag for skill directories; MCP servers via config.
- **No dedicated plugin install/list/uninstall commands.** Plugin operations are mapped to config file manipulation.
- **No marketplace URL.** No registry.
---
## 4. Codex CLI Adapter
### 4.1 Identity
| Property | Value |
|---|---|
| `agent` | `'codex'` |
| `displayName` | `'Codex CLI'` |
| `cliCommand` | `'codex'` |
| `minVersion` | `'1.0.0'` |
### 4.2 buildSpawnArgs
```typescript
SpawnArgs {
command: 'codex',
args: [
prompt,
'--model', modelId,
'--reasoning', reasoningLevel, // 'low' | 'medium' | 'high'
'--session', sessionId,
],
env: { OPENAI_API_KEY: apiKey },
usePty: false,
}
```
### 4.3 Event Parsing
**Native format:** JSONL. OpenAI-style structured events.
**Key native event types and their AgentEvent mappings:**
| Native type | AgentEvent type(s) |
|---|---|
| `response.start` | `message_start` |
| `response.text.delta` | `text_delta` |
| `response.reasoning.start` | `thinking_start` |
| `response.reasoning.delta` | `thinking_delta` |
| `response.reasoning.complete` | `thinking_stop` |
| `response.function_call` | `tool_call_start` |
| `response.function_call.delta` | `tool_input_delta` (when streaming tool input) |
| `response.function_call.complete` | `tool_call_ready` |
| `response.function_call_output` | `tool_result` |
| `response.cost` | `cost` |
| `response.complete` | `message_stop` |
| `error` | `error` |
### 4.4 Session Format
- **Location:** `~/.codex/sessions/`
- **Format:** JSONL.
- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'file'`.
> **Note:** Spec 06 §12.2 confirms `canResume=false, canFork=false` for Codex CLI.
### 4.5 Thinking Normalization
| Effort | Mapping | CLI arg |
|---|---|---|
| `'low'` | `'low'` | `--reasoning low` |
| `'medium'` | `'medium'` | `--reasoning medium` |
| `'high'` | `'high'` | `--reasoning high` |
| `'max'` | `'high'` | `--reasoning high` (no separate max tier) |
**Note:** Codex uses discrete reasoning levels, not token budgets. Setting `thinkingBudgetTokens` when `supportsThinkingBudgetTokens: false` throws `CapabilityError` before spawning, per spec 06 §11.
### 4.6 Install Methods
| Platform | Type | Command |
|---|---|---|
| all | npm | `npm install -g @openai/codex` |
### 4.7 Auth Detection
- **Primary:** `api_key` — checks `OPENAI_API_KEY` environment variable (validates format: must start with `'sk-'`).
- **Auth file:** `~/.codex/auth.json`.
### 4.8 Plugin Support
- **`supportsPlugins`:** `false`.
- All plugin operations throw `CapabilityError`.
---
## 5. Copilot CLI Adapter
### 5.1 Identity
| Property | Value |
|---|---|
| `agent` | `'copilot'` |
| `displayName` | `'GitHub Copilot CLI'` |
| `cliCommand` | `'copilot'` |
| `minVersion` | `'1.0.0'` |
### 5.2 buildSpawnArgs
```typescript
// Note: cliCommand is 'copilot' but actual command is 'gh'
SpawnArgs {
command: 'gh', // GitHub CLI binary
args: [
'copilot', // gh subcommand
prompt,
],
env: { GITHUB_TOKEN: token },
usePty: false,
}
```
**Important:** The `cliCommand` property is `'copilot'` (the logical agent name), but `SpawnArgs.command` is `'gh'` because Copilot CLI is installed as a GitHub CLI extension. The adapter's `detectVersion()` runs `gh copilot --version`, not `copilot --version`.
### 5.3 Event Parsing
**Native format:** Plain text streaming with JSON session metadata. Simpler parsing than most agents — primarily produces `text_delta` events.
**Parsing strategy:** Lines are checked for JSON structure first (session metadata). Non-JSON lines are treated as text output and emitted as `text_delta` events. Session metadata JSON objects (identified by having a `session_id` field) are consumed internally and not emitted.
**Native output → AgentEvent mappings:**
| Native output pattern | AgentEvent type(s) |
|---|---|
| First text line received | `message_start` (synthetic) |
| Non-JSON text line | `text_delta` |
| JSON metadata with `session_id` | (consumed internally, not emitted) |
| Process exit code 0 | `message_stop` (synthetic) |
| Process exit code non-zero | `crash` |
**Auth/error detection:** Since Copilot produces plain text, auth failures are detected by pattern-matching stderr and stdout for known error strings (e.g., "not authenticated", "requires authentication"). These are translated to `auth_error` events.
**Key limitations:**
- No `tool_call_start` / `tool_result` / `tool_input_delta` events (`supportsNativeTools: false`).
- No `thinking_start` / `thinking_delta` / `thinking_stop` events (`supportsThinking: false`).
- No `mcp_tool_call_start` events (`supportsMCP: false`).
- No `session_resume` / `session_fork` events (`canResume: false`, `canFork: false`).
### 5.4 Session Format
- **Location:** `~/.config/github-copilot/sessions/`
- **Format:** JSON.
- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'file'`.
### 5.5 Thinking Normalization
Not applicable. `supportsThinking: false`. Setting `thinkingEffort` throws `CapabilityError`.
### 5.6 Install Methods
| Platform | Type | Command | Notes |
|---|---|---|---|
| all | gh-extension | `gh extension install github/gh-copilot` | Requires GitHub CLI |
**Prerequisite:** `gh --version` must succeed. Install GitHub CLI with `brew install gh` (macOS), `apt install gh` (Debian/Ubuntu), or `winget install GitHub.cli` (Windows).
### 5.7 Auth Detection
- **Primary:** `oauth_device` — checks OAuth token cache in `~/.config/github-copilot/hosts.json`.
- **Alternative:** `github_token` — checks `GITHUB_TOKEN` environment variable.
### 5.8 Plugin Support
- **`supportsPlugins`:** `false`.
- All plugin operations throw `CapabilityError`.
---
## 6. Gemini CLI Adapter
### 6.1 Identity
| Property | Value |
|---|---|
| `agent` | `'gemini'` |
| `displayName` | `'Gemini CLI'` |
| `cliCommand` | `'gemini'` |
| `minVersion` | `'1.0.0'` |
### 6.2 buildSpawnArgs
```typescript
SpawnArgs {
command: 'gemini',
args: [
prompt,
'--model', modelId,
],
env: { GOOGLE_API_KEY: apiKey },
usePty: false,
}
```
**MCP servers:** Configured via the Gemini config file, not CLI args. The adapter writes MCP server definitions to `~/.config/gemini/settings.json` before spawn.
### 6.3 Event Parsing
**Native format:** JSONL streaming output. Google-specific event shapes translated to AgentEvent.
**Key native event types and their AgentEvent mappings:**
| Native type | AgentEvent type(s) |
|---|---|
| `generateContent.start` | `message_start` |
| `generateContent.text` | `text_delta` |
| `generateContent.thought.start` | `thinking_start` |
| `generateContent.thought` | `thinking_delta` |
| `generateContent.thought.done` | `thinking_stop` |
| `generateContent.functionCall` | `tool_call_start` |
| `generateContent.functionCall.delta` | `tool_input_delta` (when streaming tool input) |
| `generateContent.functionCall.done` | `tool_call_ready` |
| `generateContent.functionResponse` | `tool_result` |
| `generateContent.image` | `image_output` |
| `generateContent.done` | `message_stop` |
| `usage` | `cost` (token usage extraction) |
**Unique capability:** `supportsImageOutput: true` — Gemini is the only built-in agent that produces `image_output` events. The adapter parses base64-encoded image data from the native output.
### 6.4 Session Format
- **Location:** `~/.gemini/sessions/`
- **Format:** JSONL.
- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'file'`.
> **Note:** Spec 06 §12.3 confirms `canResume=false, canFork=false` for Gemini CLI.
### 6.5 Thinking Normalization
| Effort | Mapping | CLI mechanism |
|---|---|---|
| `'low'` | `thinkingConfig.thinkingBudget: 1024` | `--thinking-budget 1024` |
| `'medium'` | `thinkingConfig.thinkingBudget: 8192` | `--thinking-budget 8192` |
| `'high'` | `thinkingConfig.thinkingBudget: 32768` | `--thinking-budget 32768` |
| `'max'` | `thinkingConfig.thinkingBudget: max` | `--thinking-budget max` |
Maps to Gemini's `thinkingConfig` equivalents. The `--thinking-budget` CLI flag is passed in the `args` array of `SpawnArgs` when `thinkingEffort` is set.
### 6.6 Install Methods
| Platform | Type | Command |
|---|---|---|
| all | npm | `npm install -g @google/gemini-cli` |
### 6.7 Auth Detection
- **Primary:** `browser_login` and `api_key` (both equally primary per spec 08 §10.1) — checks `GOOGLE_API_KEY` and `GEMINI_API_KEY` environment variables; also checks browser-based login session at `~/.config/gemini/credentials.json`.
- No alternative methods. Spec 06 §12.3 lists `methods=['api-key','oauth']`; the `oauth` method is the same credential mechanism as `browser_login` (browser-based OAuth flow producing a cached credential file).
### 6.8 Plugin Support
- **`supportsPlugins`:** `false`.
- All plugin operations throw `CapabilityError`.
---
## 7. Cursor Adapter
### 7.1 Identity
| Property | Value |
|---|---|
| `agent` | `'cursor'` |
| `displayName` | `'Cursor'` |
| `cliCommand` | `'cursor'` |
| `minVersion` | `'0.45.0'` |
### 7.2 buildSpawnArgs
```typescript
SpawnArgs {
command: 'cursor',
args: [
prompt,
'--model', modelId,
],
env: {}, // Auth via session token, not env var
usePty: false,
}
```
> **Cross-spec reconciliation:** `06-capabilities-and-models.md` §12.5 lists `requiresPty=true` for Cursor, which is incorrect. The correct value is `false`. Evidence: (1) Scope §22 explicitly names only "OpenClaw" as requiring PTY ("PTY support via node-pty for agents that require it (OpenClaw, some interactive modes)"). (2) `11-process-lifecycle-and-platform.md` §6.1 lists only OpenClaw in the PTY-required agents table. (3) `03-run-handle-and-interaction.md` §7.1 confirms Cursor's `usePty=false`. The `requiresPty` values for Cursor and OpenClaw are swapped in spec 06 (see also §11.9).
### 7.3 Event Parsing
**Native format:** Partial streaming — text events are streamed, but tool call results may be buffered. The adapter handles both streaming and buffered output.
**Key native event types and their AgentEvent mappings:**
| Native output pattern | AgentEvent type(s) |
|---|---|
| Stream start marker | `message_start` |
| Text chunk | `text_delta` |
| Tool invocation (buffered JSON) | `tool_call_start`, `tool_call_ready` |
| Tool output (buffered JSON) | `tool_result` |
| Completion marker | `message_stop` |
| Non-zero exit / error JSON | `crash` or `error` |
**Note:** Cursor's output format is partially documented. The adapter's `parseEvent()` handles both streaming text lines and buffered JSON blocks for tool calls. Thinking events are model-dependent: emitted only when `ModelCapabilities.supportsThinking` is true for the selected model.
### 7.4 Session Format
- **Location:** `~/.cursor/sessions/`
- **Format:** SQLite.
- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'sqlite'`.
### 7.5 Thinking Normalization
Model-dependent. When the selected model's `ModelCapabilities.supportsThinking` is `true`, thinking effort is passed as a provider-level parameter. When `false`, setting `thinkingEffort` throws `CapabilityError`.
### 7.6 Install Methods
| Platform | Type | Command | Notes |
|---|---|---|---|
| darwin | manual | `open https://cursor.sh/download` | macOS .dmg installer |
| linux | manual | `open https://cursor.sh/download` | AppImage |
| win32 | winget | `winget install Cursor.Cursor` | |
**Note:** No headless-only install. Full app required even for CLI use.
### 7.7 Auth Detection
- **Primary:** `browser_login` — inspects session token in `~/.cursor/auth.json` (per spec 08 §10.1).
- **Alternative:** `api_key` — checks `CURSOR_API_KEY` environment variable.
> **Cross-spec reconciliation:** Spec 06 §12.5 lists auth methods as `['oauth']` while spec 08 §10.1 lists primary method as `browser_login`. This spec follows spec 08 as the authoritative source for auth detection strategies. The distinction is behavioral: `browser_login` describes how the user authenticates (via Cursor's built-in browser flow), while the token format stored in `auth.json` is an OAuth token.
### 7.8 Plugin Support
- **`supportsPlugins`:** `true`.
- **Formats:** `['extension-ts', 'mcp-server']`.
- **Registry:** `{ name: 'cursor-extensions', url: 'https://cursor.sh/extensions', searchable: true }`.
- Cursor uses its own extension system for TypeScript extensions.
---
## 8. OpenCode Adapter
### 8.1 Identity
| Property | Value |
|---|---|
| `agent` | `'opencode'` |
| `displayName` | `'OpenCode'` |
| `cliCommand` | `'opencode'` |
| `minVersion` | `'1.0.0'` |
### 8.2 buildSpawnArgs
```typescript
SpawnArgs {
command: 'opencode',
args: [
prompt,
'--model', modelId,
'--session', sessionId,
'--fork', forkSessionId,
],
env: { /* provider-specific: ANTHROPIC_API_KEY or OPENAI_API_KEY */ },
usePty: false,
}
```
### 8.3 Event Parsing
**Native format:** Structured JSON streaming. Full tool call streaming. ACP event types also emitted.
**Key native event types and their AgentEvent mappings:**
| Native type | AgentEvent type(s) |
|---|---|
| `message.start` | `message_start` |
| `message.text.delta` | `text_delta` |
| `message.thinking.start` | `thinking_start` (when model supports thinking) |
| `message.thinking.delta` | `thinking_delta` (when model supports thinking) |
| `message.thinking.done` | `thinking_stop` (when model supports thinking) |
| `tool.call` | `tool_call_start` |
| `tool.call.delta` | `tool_input_delta` |
| `tool.call.done` | `tool_call_ready` |
| `tool.result` | `tool_result` |
| `mcp.tool.call` | `mcp_tool_call_start` |
| `mcp.tool.result` | `mcp_tool_result` |
| `message.complete` | `message_stop` |
**ACP events:** OpenCode emits native ACP protocol events (`acp.request`, `acp.response`) that are not part of the AgentEvent union (spec 04). These are translated to `debug` events with `{ type: 'debug', message: JSON.stringify(nativeEvent) }`, preserving ACP data without extending the event union.
**Unique capability:** `supportsStructuredOutput: true` — OpenCode is the only built-in agent supporting structured output. When structured output is requested, the agent's final text output (in the last `text_delta` events before `message_stop`) contains the JSON-formatted structured response conforming to the user-specified schema. The adapter does not introduce new event types; consumers parse the accumulated text from `text_delta` events.
**Session lifecycle events:** When resuming (`--session`), the adapter emits `session_resume`. When forking (`--fork`), it emits `session_fork`. These are synthesized by the adapter from session metadata.
### 8.4 Session Format
- **Location:** `~/.local/share/opencode/` (XDG data home on Linux; platform-appropriate on macOS/Windows).
- **Format:** SQLite.
- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'sqlite'`.
### 8.5 Thinking Normalization
Model-dependent. Passed as provider-level parameter when model supports thinking.
### 8.6 Install Methods
| Platform | Type | Command |
|---|---|---|
| all | npm | `npm install -g opencode` |
| darwin | brew | `brew install opencode/tap/opencode` |
### 8.7 Auth Detection
- **Primary:** `api_key` — checks provider-specific env vars (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`) based on configured provider.
- **Auth file:** `~/.config/opencode/auth.json`.
### 8.8 Plugin Support
- **`supportsPlugins`:** `true`.
- **Formats:** `['npm-package', 'skill-file', 'mcp-server']`.
- **Registry:** `{ name: 'npm', url: 'https://www.npmjs.com/search?q=opencode-', searchable: true }`.
- **Marketplace:** `https://www.npmjs.com/search?q=opencode-`.
---
## 8.b OpenCode HTTP Adapter
### 8.b.1 Identity
| Property | Value |
|---|---|
| `agent` | `'opencode-http'` |
| `displayName` | `'OpenCode (HTTP)'` |
| `adapterType` | `'remote'` |
| `connectionType` | `'http'` |
| `minVersion` | `'0.1.0'` |
**Note**: This is a **remote adapter** (not subprocess), implementing the `RemoteAdapter` interface.
### 8.b.2 Connection Management
```typescript
// HTTP connection via RemoteAdapter interface
interface OpenCodeHttpConnection {
connectionType: 'http';
baseUrl: string; // e.g., 'http://localhost:9527'
// Server-Sent Events streaming
stream(path: string, data: unknown): AsyncIterableIterator<AgentEvent>;
// REST API methods
get(path: string, params?: Record<string, unknown>): Promise<unknown>;
post(path: string, data?: unknown): Promise<unknown>;
}
```
**Server management**: The adapter automatically starts `opencode serve --port 0` when needed and manages the server lifecycle.
### 8.b.3 Event Parsing
**Transport:** HTTP POST to `/api/chat/stream` with Server-Sent Events (SSE).
**Event format:** SSE events are parsed from `data: {...}` lines, with JSON payloads matching OpenCode's native event structure.
| SSE Event Type | AgentEvent type(s) |
|---|---|
| `message.start` | `message_start` |
| `message.text.delta` | `text_delta` |
| `tool_start`, `tool_call` | `tool_call_start` |
| `tool_input` | `tool_input_delta` |
| `tool_ready` | `tool_call_ready` |
| `tool_result` | `tool_result` |
| `message.stop` | `message_stop` |
**Enhanced streaming**: SSE provides lower latency than subprocess stdout parsing.
### 8.b.4 Session Format
- **Location:** Same as subprocess OpenCode: `~/.local/share/opencode/` (XDG data home on Linux).
- **Format:** SQLite (shared with subprocess adapter).
- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'sqlite'`.
### 8.b.5 Server Lifecycle
- **Startup**: `opencode serve --port 0 --host 127.0.0.1` with dynamic port allocation.
- **Health monitoring**: Regular `/health` endpoint checks.
- **Cleanup**: Graceful server shutdown on adapter disposal.
- **Port management**: Automatic port discovery to avoid conflicts.
### 8.b.6 Auth Detection
- **Inherited**: Uses same auth detection as subprocess OpenCode adapter.
- **Provider support**: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`.
- **Config file**: `~/.config/opencode/config.json`.
### 8.b.7 Plugin Support
- **Identical to subprocess adapter**: Supports MCP servers via HTTP API.
- **Formats:** `['mcp-server']`.
- **Registry:** MCP server marketplace at https://modelcontextprotocol.io.
**Advantage**: HTTP interface enables enhanced MCP plugin management compared to subprocess limitations.
---
## 10. Pi Adapter
### 9.1 Identity
| Property | Value |
|---|---|
| `agent` | `'pi'` |
| `displayName` | `'Pi'` |
| `cliCommand` | `'pi'` |
| `minVersion` | `'1.0.0'` |
### 9.2 buildSpawnArgs
```typescript
SpawnArgs {
command: 'pi',
args: [
prompt,
'--model', modelId,
'--session', sessionId,
'--fork', forkSessionId,
],
env: { /* provider-specific */ },
usePty: false,
}
```
### 9.3 Event Parsing
**Native format:** JSONL streaming. Each line is a JSON object with `id`, `parentId`, `type`, and `data` fields.
**Live event parsing vs. session parsing:** During a live run, the adapter processes each JSONL line as it arrives. The `id` and `parentId` fields are used for session reconstruction (§9.4) but are not needed for real-time event emission. The `type` field determines the AgentEvent mapping:
| Native `type` field | AgentEvent type(s) |
|---|---|
| `message_start` | `message_start` |
| `text` | `text_delta` |
| `thinking_start` | `thinking_start` (when model supports thinking) |
| `thinking` | `thinking_delta` (when model supports thinking) |
| `thinking_end` | `thinking_stop` (when model supports thinking) |
| `tool_call` | `tool_call_start` |
| `tool_call_input` | `tool_input_delta` (when streaming tool input) |
| `tool_call_ready` | `tool_call_ready` |
| `tool_result` | `tool_result` |
| `message_end` | `message_stop` |
| `error` | `error` |
**Session lifecycle events:** When resuming (`--session`), the adapter emits `session_resume`. When forking (`--fork`), it emits `session_fork`. These are synthesized by the adapter from session metadata.
### 9.4 Session Format
- **Location:** `~/.pi/agent/sessions/`
- **Format:** JSONL tree (each entry has `id` and `parentId` fields forming a conversation tree).
- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'file'`.
**Tree reconstruction:** The session parser must reconstruct the conversation tree from `id`/`parentId` references rather than treating entries as a flat list. A given session file may contain multiple conversation branches.
### 9.5 Thinking Normalization
Model-dependent. Passed as provider-level parameter when model supports thinking.
### 9.6 Install Methods
| Platform | Type | Command |
|---|---|---|
| all | npm | `npm install -g @mariozechner/pi-coding-agent` |
### 9.7 Auth Detection
- **Primary:** `api_key` — checks provider-specific env vars based on configured provider.
- **Auth file:** `~/.pi/agent/auth.json`.
### 9.8 Plugin Support
- **`supportsPlugins`:** `true`.
- **Formats:** `['npm-package', 'skill-file']`.
- **Registry:** `{ name: 'npm', url: 'https://www.npmjs.com/search?q=%40mariozechner%2Fpi-', searchable: true }`.
---
## 11. omp Adapter
### 10.1 Identity
| Property | Value |
|---|---|
| `agent` | `'omp'` |
| `displayName` | `'omp (oh-my-pi)'` |
| `cliCommand` | `'omp'` |
| `minVersion` | `'1.0.0'` |
### 10.2 buildSpawnArgs
```typescript
SpawnArgs {
command: 'omp',
args: [
prompt,
'--model', modelId,
'--session', sessionId,
'--fork', forkSessionId,
],
env: { /* provider-specific */ },
usePty: false,
}
```
### 10.3 Event Parsing
**Native format:** JSONL tree (identical format to Pi). Same `id`/`parentId` tree structure. Same native event type → AgentEvent mappings as Pi (§9.3), including `tool_input_delta` and session lifecycle events.
**Key difference from Pi:** omp unconditionally emits `thinking_start`, `thinking_delta`, and `thinking_stop` events regardless of model, since omp always supports thinking (§10.5).
### 10.4 Session Format
- **Location:** `~/.omp/agent/sessions/`
- **Format:** JSONL tree (identical to Pi — same `id`/`parentId` structure).
- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'file'`.
### 10.5 Thinking Normalization
**Always supported** (not model-dependent, unlike Pi):
| Effort | Mapping |
|---|---|
| `'low'` | `budget_tokens: 1024` |
| `'medium'` | `budget_tokens: 8192` |
| `'high'` | `budget_tokens: 32768` |
| `'max'` | `budget_tokens: max_budget_tokens` |
**Key difference from Pi:** omp unconditionally supports all thinking effort levels. Setting `thinkingEffort` never throws `CapabilityError` for omp, regardless of model.
### 10.6 Install Methods
| Platform | Type | Command |
|---|---|---|
| all | npm | `npm install -g @oh-my-pi/pi-coding-agent` |
### 10.7 Auth Detection
- Same approach as Pi: provider-specific env var inspection.
- **Auth file:** `~/.omp/agent/auth.json`.
### 10.8 Plugin Support
- **`supportsPlugins`:** `true`.
- **Formats:** `['npm-package', 'skill-file']`.
- **Registry:** `{ name: 'npm', url: 'https://www.npmjs.com/search?q=%40oh-my-pi%2F', searchable: true }`.
### 10.9 Platform Notes
- **Windows:** Partial support. Core run/prompt functionality works. Some shell-dependent tool operations may behave differently under `cmd.exe`. The adapter emits a `debug` event with `level: 'warn'` on Windows.
- **`supportedPlatforms`:** `['darwin', 'linux', 'win32']`.
- See `11-process-lifecycle-and-platform.md` §5.2 for full details.
---
## 12. OpenClaw Adapter
### 11.1 Identity
| Property | Value |
|---|---|
| `agent` | `'openclaw'` |
| `displayName` | `'OpenClaw'` |
| `cliCommand` | `'openclaw'` |
| `minVersion` | `'1.0.0'` |
### 11.2 buildSpawnArgs
```typescript
SpawnArgs {
command: 'openclaw',
args: [
prompt,
'--model', modelId,
],
env: { OPENCLAW_API_KEY: apiKey },
usePty: true, // Requires PTY
}
```
### 11.3 Event Parsing
**Native format:** Interactive TUI output via PTY. Requires VT escape sequence stripping (`VtStripper`, spec 11 §6.3) before line-based parsing. After stripping, output lines are JSON objects.
**Parsing pipeline:** Raw PTY output → `VtStripper.strip()` → JSON.parse per line → native type → AgentEvent.
**Key native event types and their AgentEvent mappings (after VT stripping):**
| Native JSON `type` field | AgentEvent type(s) |
|---|---|
| `response.start` | `message_start` |
| `response.text` | `text_delta` |
| `response.thinking.start` | `thinking_start` (model-dependent) |
| `response.thinking` | `thinking_delta` (model-dependent) |
| `response.thinking.end` | `thinking_stop` (model-dependent) |
| `tool.invoke` | `tool_call_start` |
| `tool.invoke.delta` | `tool_input_delta` |
| `tool.invoke.done` | `tool_call_ready` |
| `tool.output` | `tool_result` |
| `channel.event` | `plugin_invoked` (channel-plugin activity) |
| `plugin.loaded` | `plugin_loaded` |
| `response.end` | `message_stop` |
| `error` | `error` |
**Session lifecycle:** OpenClaw has `canResume: false`, `canFork: false`, so `session_resume` and `session_fork` events are never emitted.
**Channel-plugin events:** Native channel-plugin activity (messages from Telegram, Discord, Slack, etc.) is identified by the `channel.event` type and translated to `plugin_invoked` AgentEvents. The `plugin_loaded` event fires when a channel-plugin successfully connects to its messaging platform.
**Partial streaming:** Text events are streamed in real-time, but tool results may be buffered until the tool completes.
### 11.4 Session Format
- **Location:** `~/.openclaw/sessions/`
- **Format:** JSON (per channel/session).
- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'file'`.
### 11.5 Thinking Normalization
Model-dependent. Passed as provider-level parameter when model supports thinking.
### 11.6 Install Methods
| Platform | Type | Command | Notes |
|---|---|---|---|
| all | npm | `npm install -g openclaw` | Requires Node 22.16+, 16GB RAM minimum |
### 11.7 Auth Detection
- **Primary:** `api_key` — checks provider-specific env vars.
- **Auth file:** `~/.openclaw/auth.json`.
### 11.8 Plugin Support
- **`supportsPlugins`:** `true`.
- **Formats:** `['npm-package', 'skill-file', 'channel-plugin']`.
- **Registries:** `[{ name: 'npm', searchable: true }, { name: 'openclaw-registry', url: 'https://openclaw.ai/plugins', searchable: true }]`.
- **Unique format:** `channel-plugin` for messaging gateways (Telegram, Discord, Slack, WhatsApp, Signal).
### 11.9 PTY Requirement
OpenClaw is the only built-in agent with `requiresPty: true` (scope §22). See `11-process-lifecycle-and-platform.md` §6 for PTY details.
> **Cross-spec reconciliation:** `06-capabilities-and-models.md` §12.9 incorrectly lists `requiresPty=false` for OpenClaw. The correct value is `true`, per scope §22 ("PTY support via node-pty for agents that require it (OpenClaw, some interactive modes)"), `03-run-handle-and-interaction.md` §7.1, and `11-process-lifecycle-and-platform.md` §6.1.
### 11.10 Platform Notes
- **Windows:** Requires ConPTY (Windows 10 1809+). Older Windows versions fall back to winpty with potential output buffering differences.
---
## 13. Hermes Adapter
> **SCOPE EXTENSION:** hermes-agent (`@NousResearch/hermes-agent`) is included as a 10th supported agent.
### 12.1 Identity
| Property | Value |
|---|---|
| `agent` | `'hermes'` |
| `displayName` | `'hermes-agent'` |
| `cliCommand` | `'hermes'` |
| `minVersion` | `'0.1.0'` |
### 12.2 buildSpawnArgs
```typescript
SpawnArgs {
command: 'hermes',
args: [
prompt,
'--output-format', 'jsonl', // Required for structured output
'--model', modelId, // Model selection (multi-provider)
'--session', sessionId, // Resume session (canResume=true)
],
env: {
// Multi-provider: set whichever key is configured
OPENROUTER_API_KEY: ...,
NOUS_API_KEY: ...,
ANTHROPIC_API_KEY: ...,
OPENAI_API_KEY: ...,
GITHUB_TOKEN: ...,
GOOGLE_API_KEY: ...,
},
usePty: false,
}
```
**Critical:** The `--output-format jsonl` flag must always be passed. Without it, hermes produces human-readable text that cannot be parsed by `parseEvent()`.
### 12.3 Event Parsing
**Native format:** JSONL via `--output-format jsonl`. Python process emits structured events.
**Key native event types and their AgentEvent mappings:**
| Native `type` field | AgentEvent type(s) |
|---|---|
| `message_start` | `message_start` |
| `text_delta` | `text_delta` |
| `tool_call` | `tool_call_start` |
| `tool_call_input` | `tool_input_delta` |
| `tool_call_ready` | `tool_call_ready` |
| `tool_result` | `tool_result` |
| `mcp_tool_call` | `mcp_tool_call_start` |
| `mcp_tool_result` | `mcp_tool_result` |
| `skill_loaded` | `skill_loaded` (maps to `SkillLoadedEvent`, not `PluginLoadedEvent`) |
| `skill_invoked` | `skill_invoked` (maps to `SkillInvokedEvent`, not `PluginInvokedEvent`) |
| `message_end` | `message_stop` |
| `usage` | `cost` |
| `error` | `error` |
**Skill events:** hermes skills are mapped to the `skill_loaded` / `skill_invoked` AgentEvent types (spec 04), not to `plugin_loaded` / `plugin_invoked`, because hermes's skill system matches the skill event semantics (name + source) rather than the plugin event semantics (pluginId + version).
**MCP events:** MCP tool events (`mcp_tool_call_start`, `mcp_tool_result`) are emitted when hermes invokes tools from connected MCP servers.
**Session lifecycle:** hermes has `canResume: true`, `canFork: false`. The adapter synthesizes `session_resume` when invoked with `--session`. No `session_fork` events.
**Thinking:** hermes has `supportsThinking: false`, so `thinking_start`, `thinking_delta`, and `thinking_stop` events are never emitted.
### 12.4 Session Format
- **Location:** `~/.hermes/` (SQLite database).
- **Format:** SQLite with FTS5 full-text search support.
- **Capabilities:** `canResume: true`, `canFork: false`, `sessionPersistence: 'sqlite'`.
> **SCOPE EXTENSION:** hermes session location and SQLite format are not in the original scope's session table (scope §16). This is a spec-level extension derived from hermes-agent's actual behavior.
### 12.5 Thinking Normalization
Not applicable. `supportsThinking: false`. Setting `thinkingEffort` throws `CapabilityError`.
### 12.6 Install Methods
| Platform | Type | Command | Notes |
|---|---|---|---|
| all | pip | `pip install hermes-agent` | Requires Python >= 3.11 |
| all | curl | `curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh \| bash` | Shell installer; requires Unix shell (bash). On Windows, use WSL2 or Git Bash. |
| all | nix | `nix run github:NousResearch/hermes-agent` | Nix flake available |
> **SCOPE EXTENSION:** hermes install methods are Python-based (pip), unlike all other agents which use npm or platform-specific methods. The `'pip'` and `'nix'` install types are already incorporated into the `InstallMethod.type` union in spec 06 §3.3.
### 12.7 Auth Detection
- **Primary:** `api_key` (per spec 08 §10.1) — checks environment variables in priority order: `OPENROUTER_API_KEY`, `NOUS_API_KEY`, `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GITHUB_TOKEN`, `GOOGLE_API_KEY`.
- **Alternative:** `oauth` — checks OAuth token cache from `hermes login` (Nous Portal or OpenAI Codex).
- **Alternative:** `github_token` — checks `GITHUB_TOKEN` for GitHub-backed model access.
- **Alternative:** `config_file` — inspects `~/.hermes/cli-config.yaml` for embedded API keys (YAML safe-load only).
- Returns `'authenticated'` if any valid credential is found for any provider.
- `AuthState.details` lists all detected providers with their auth method.
> **SCOPE EXTENSION:** hermes-agent supports the broadest set of auth methods (6+ env vars, YAML config, OAuth) reflecting its multi-provider architecture.
### 12.8 Plugin Support
- **`supportsPlugins`:** `true`.
- **Formats:** `['skill-file', 'skill-directory', 'mcp-server']`.
- **Registry:** `{ name: 'agentskills-hub', url: 'https://agentskills.io', searchable: true }`.
- **MCP:** Supports both MCP client (connecting to external MCP servers) and MCP server (exposing hermes capabilities via `mcp_serve.py`).
- **Note:** hermes MCP server plugins have no registry discovery path — they are configured directly via `~/.hermes/cli-config.yaml`. See `09-plugin-manager.md` for details.
### 12.9 Platform Notes
- **macOS / Linux:** Fully supported.
- **Windows:** WSL2 only. Native Windows is not supported. See `11-process-lifecycle-and-platform.md` §5.3.
- **`supportedPlatforms`:** `['darwin', 'linux']` — does not include `'win32'`.
- **Python dependency:** hermes is the only Python-based agent. It requires Python >= 3.11 on PATH. Virtual environment installations must ensure `hermes` is accessible on PATH.
---
## 14. Per-Adapter Thinking Effort Summary
| Agent | `'low'` | `'medium'` | `'high'` | `'max'` | Budget tokens | Notes |
|---|---|---|---|---|---|---|
| claude | 1024 | 8192 | 32768 | max_budget_tokens | Passed through | `--thinking-budget` flag |
| codex | `'low'` | `'medium'` | `'high'` | `'high'` | Ignored | `--reasoning` flag; max→high |
| gemini | 1024 | 8192 | 32768 | max | Via thinkingConfig | thinkingConfig equivalents |
| copilot | — | — | — | — | — | `supportsThinking: false` |
| cursor | model-dep | model-dep | model-dep | model-dep | model-dep | Provider-level param |
| opencode | model-dep | model-dep | model-dep | model-dep | model-dep | Provider-level param |
| pi | model-dep | model-dep | model-dep | model-dep | model-dep | Provider-level param |
| omp | 1024 | 8192 | 32768 | max_budget_tokens | Passed through | Always supported |
| openclaw | model-dep | model-dep | model-dep | model-dep | model-dep | Provider-level param |
| hermes | — | — | — | — | — | `supportsThinking: false` |
**Cross-reference:** Full thinking normalization tables are in `06-capabilities-and-models.md` §8.
---
## 15. Per-Adapter Auth Summary
| Agent | Primary method | Env var(s) | Auth file |
|---|---|---|---|
| claude | `browser_login` | `ANTHROPIC_API_KEY` | `~/.claude/` (session tokens) |
| codex | `api_key` | `OPENAI_API_KEY` | `~/.codex/auth.json` |
| gemini | `browser_login` / `api_key` | `GOOGLE_API_KEY`, `GEMINI_API_KEY` | `~/.config/gemini/credentials.json` |
| copilot | `oauth_device` | `GITHUB_TOKEN` | `~/.config/github-copilot/hosts.json` |
| cursor | `browser_login` | `CURSOR_API_KEY` (fallback) | `~/.cursor/auth.json` |
| opencode | `api_key` | Provider-specific | `~/.config/opencode/auth.json` |
| pi | `api_key` | Provider-specific | `~/.pi/agent/auth.json` |
| omp | `api_key` | Provider-specific | `~/.omp/agent/auth.json` |
| openclaw | `api_key` | Provider-specific | `~/.openclaw/auth.json` |
| hermes | Multi (6+ methods) | 6+ env vars | `~/.hermes/.env`, `~/.hermes/cli-config.yaml` |
**Cross-reference:** Full auth detection strategies are in `08-config-and-auth.md` §10.1.
**Invariant:** All auth detection is read-only, local-only, no network calls, completes under 100ms.
---
## 16. Per-Adapter Plugin Support Summary
| Agent | `supportsPlugins` | Formats | Registry | Marketplace |
|---|---|---|---|---|
| claude | `true` (partial) | skill-directory, mcp-server | — | — |
| codex | `false` | — | — | — |
| gemini | `false` | — | — | — |
| copilot | `false` | — | — | — |
| cursor | `true` | extension-ts, mcp-server | cursor-extensions | `https://cursor.sh/extensions` |
| opencode | `true` | npm-package, skill-file, mcp-server | npm | `https://www.npmjs.com/search?q=opencode-` |
| pi | `true` | npm-package, skill-file | npm | `https://www.npmjs.com/search?q=%40mariozechner%2Fpi-` |
| omp | `true` | npm-package, skill-file | npm | `https://www.npmjs.com/search?q=%40oh-my-pi%2F` |
| openclaw | `true` | npm-package, skill-file, channel-plugin | npm + openclaw-registry | `https://openclaw.ai/plugins` |
| hermes | `true` | skill-file, skill-directory, mcp-server | agentskills-hub | `https://agentskills.io` |
**Cross-reference:** Full plugin support matrix in `06-capabilities-and-models.md` §9 and `09-plugin-manager.md`.
---
## 17. Error Format Translation
All adapters translate native agent errors into typed `AgentEvent` objects. The `BaseAgentAdapter` class (spec 05 §4) provides hook methods for common error scenarios:
### 16.1 Error Event Mappings
| Native error type | AgentEvent `type` | Fields |
|---|---|---|
| Auth failure (invalid/missing key) | `auth_error` | `agent`, `message`, `guidance` |
| Rate limit / quota exceeded | `rate_limit_error` | `message`, `retryAfterMs` |
| Context window exceeded | `context_exceeded` | `usedTokens`, `maxTokens` |
| Process crash (non-zero exit) | `crash` | `exitCode`, `stderr` |
| Generic / unknown error | `error` | `code: ErrorCode`, `message`, `recoverable` |
### 16.2 parseEvent() Contract
- `parseEvent()` **must never throw**. Unrecognized lines return `null`.
- In debug mode (`ClientOptions.debug: true`, spec 01 §5.1.1), unrecognized lines are emitted as `{ type: 'log', source: 'stdout', line: rawLine }` (conforming to the `LogEvent` type defined in spec 04).
- Empty lines and whitespace-only lines are silently dropped.
### 16.3 BaseAgentAdapter Error Hooks
Per spec 05 §4 (canonical signatures):
| Hook | Signature | Trigger | Default behavior |
|---|---|---|---|
| `onSpawnError(error)` | `(error: Error) → AgentEvent` | Subprocess fails to start | Returns `{ type: 'crash', exitCode: -1, stderr: error.message }` |
| `onTimeout()` | `() → AgentEvent` | Run or inactivity timeout | Returns `{ type: 'error', code: 'TIMEOUT', recoverable: false }` |
| `onProcessExit(code, signal)` | `(exitCode: number, signal: string \| null) → AgentEvent[]` | Subprocess exits | Returns terminal events based on exit code/signal |
| `shouldRetry(event, attempt, policy)` | `(event: AgentEvent, attempt: number, policy: RetryPolicy) → boolean` | After error, before retry | Returns `false` (no retry by default) |
---
## 18. Version Detection
All adapters detect the installed agent version via `detectVersionFromCli()` (a `BaseAgentAdapter` utility):
```typescript
// Default: runs `<cliCommand> --version` and parses semver
const version = await detectVersionFromCli(adapter.cliCommand);
```
**Exceptions:**
- **Copilot:** Runs `gh copilot --version` (not `copilot --version`).
- **hermes:** Runs `hermes --version`; output is Python-formatted (e.g., `hermes-agent 0.1.0`).
The detected version is compared against `minVersion`. If the installed version is below `minVersion`, `AdapterRegistry.detect()` returns an `InstalledAgentInfo` with `meetsMinVersion: false` and `mux.run()` emits a `debug` warning.
---
## 19. Adapter Registration
All 10 built-in adapters are registered with the `AdapterRegistry` during `createClient()`:
```typescript
// Simplified registration sequence
const registry = new AdapterRegistry();
registry.register(new ClaudeCodeAdapter());
registry.register(new CodexAdapter());
registry.register(new GeminiAdapter());
registry.register(new CopilotAdapter());
registry.register(new CursorAdapter());
registry.register(new OpenCodeAdapter());
registry.register(new PiAdapter());
registry.register(new OmpAdapter());
registry.register(new OpenClawAdapter());
registry.register(new HermesAdapter());
```
Plugin adapters registered via `mux.adapters.register()` are added after built-in adapters and extend the `AgentName` union at runtime.
---
## 20. Spec-Level Additions
The following items are spec-level additions not explicitly stated in the scope:
| Addition | Section | Rationale |
|---|---|---|
| `minVersion` per adapter | §3–12 | Required for version compatibility checking |
| hermes `--output-format jsonl` requirement | §12.2 | Not stated in scope; discovered through research |
| hermes FTS5 session search | §12.4 | SQLite FTS5 support is hermes-specific |
| Claude session hash-based paths | §3.4 | Implementation detail not in scope |
| Codex `'max'` → `'high'` mapping | §4.5 | Scope says `'max'→'high'` but only in comment |
| `parseEvent()` never-throw contract | §16.2 | Implied by spec 05 but not explicit in scope |
| Debug-mode logging of unrecognized lines | §16.2 | Extension for adapter debugging |
| Copilot `gh` vs `copilot` command split | §5.2 | Scope lists `copilot` as CLI but actual binary is `gh` |
| OpenClaw PTY reconciliation note | §11.9 | Corrects spec 06 cross-spec error |
| Cursor PTY reconciliation note | §7.2 | Corrects spec 06 cross-spec error (swapped with OpenClaw) |
| Auth method reconciliation notes | §3.7, §7.7 | Resolves spec 06 vs spec 08 auth method naming discrepancies |
| Per-adapter event mapping tables | §3–12 | Scope describes formats, not specific native event types |
| Session lifecycle event synthesis | §3–12 | Adapters synthesize session_resume/session_fork from metadata |
| hermes nix install method | §12.6 | From spec 06 §7.10; extends scope's install union |
| Prompt delivery via stdin | §3.2 | Implementation detail for long/array prompts |
| OpenCode ACP events as debug | §8.3 | ACP events not in AgentEvent union; translated to debug |
---
## Implementation Status (2026-04-12)
### Per-adapter session directories
Verified from each adapter's `sessionDir()`:
| Agent | Session directory |
|---|---|
| `claude` | `~/.claude/projects` |
| `codex` | `~/.codex/sessions` |
| `gemini` | `~/.gemini/sessions` |
| `copilot` | `~/.config/github-copilot/sessions` |
| `cursor` | `~/.cursor/sessions` |
| `opencode` | `~/.local/share/opencode` |
| `pi` | `~/.pi/agent/sessions` |
| `omp` | `~/.omp/agent/sessions` |
| `openclaw` | `~/.openclaw/sessions` |
| `hermes` | `~/.hermes/sessions` |
| `agent-mux-remote` | (none — transport-delegated) |
All adapters use `listJsonlFiles()` from `packages/adapters/src/session-fs.ts` to enumerate session files; writes route through the tmp + `fs.rename` atomic helper in the same module.
### 13. `agent-mux-remote` (11th built-in adapter)
`AgentMuxRemoteAdapter` (`packages/adapters/src/agent-mux-remote-adapter.ts`) is a pass-through adapter that emits plain `amux run …` spawn args. Transport is *out of scope* for the adapter: the caller wraps the returned `SpawnArgs` with a `RunOptions.invocation` of `'local'`, `'docker'`, `'ssh'`, or `'k8s'` via `buildInvocationCommand()`. This lets agent-mux **nest**: a local amux can dispatch to a second amux executing in a Docker container, on a remote SSH host, or in a Kubernetes pod.
Key fields:
| Field | Value |
|---|---|
| `agent` | `'agent-mux-remote'` |
| `displayName` | `agent-mux (remote via invocation mode)` |
| `cliCommand` | `amux` |
| `hostEnvSignals` | `[]` |
| `sessionDir()` | throws (delegated; the remote amux owns sessions) |
| Auth | `{ type: 'api_key', name: 'Transport' }` — handled by the chosen invocation mode. |
Runtime configuration is supplied via `RunOptions.env`:
- `AMUX_REMOTE_AGENT` — the harness to invoke on the remote side (default `claude`).
Structured JSONL events produced by the nested `amux run` are passed through unchanged.
documents
[]
Outgoing edges
None.
Incoming edges
contains_page1
- page:docs-agent-mux-reference·PageAgent Mux Reference