II.
Page JSON
Structured · livepage:docs-agent-mux-reference-12-built-in-adapters
Built-in Adapter Implementations json
Inspect the normalized record payload exactly as the atlas UI reads it.
{
"id": "page:docs-agent-mux-reference-12-built-in-adapters",
"_kind": "Page",
"_file": "wiki/docs/agent-mux/reference/12-built-in-adapters.md",
"_cluster": "wiki",
"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": "\n# Built-in Adapter Implementations\n\n**Specification v1.0** | `@a5c-ai/agent-mux`\n\n> **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.\n>\n> **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.\n\n---\n\n## 1. Overview\n\nThis 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.\n\nThis 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.\n\n### 1.1 Cross-References\n\n| Type / Concept | Spec | Section |\n|---|---|---|\n| `AgentAdapter` interface | `05-adapter-system.md` | 2 |\n| `BaseAgentAdapter` abstract class | `05-adapter-system.md` | 4 |\n| `SpawnArgs` type | `05-adapter-system.md` | 3.1 |\n| `AdapterRegistry` | `05-adapter-system.md` | 5 |\n| `AgentCapabilities` | `06-capabilities-and-models.md` | 2 |\n| `ModelCapabilities` | `06-capabilities-and-models.md` | 5 |\n| Thinking normalization tables | `06-capabilities-and-models.md` | 8 |\n| Install metadata | `06-capabilities-and-models.md` | 7 |\n| Capability profiles (complete) | `06-capabilities-and-models.md` | 12 |\n| Plugin support per agent | `06-capabilities-and-models.md` | 9 |\n| Config file locations | `08-config-and-auth.md` | 7 |\n| Auth detection strategies | `08-config-and-auth.md` | 10.1 |\n| AuthMethod, AuthState | `08-config-and-auth.md` | 10, 9 |\n| Session formats | `07-session-manager.md` | 5 |\n| Process lifecycle, PTY | `11-process-lifecycle-and-platform.md` | 6 |\n| Platform support matrix | `11-process-lifecycle-and-platform.md` | 5 |\n| `AgentEvent` union | `04-agent-events.md` | 4 |\n| `ErrorCode` union | `01-core-types-and-client.md` | 3.1 |\n| Scope §20 summary table | `agent-mux-scope.md` | 20 |\n\n---\n\n## 2. Built-in Adapter Summary\n\nFrom scope §20, extended with hermes-agent:\n\n| Adapter | CLI | `cliCommand` | Session | Stream | Resume | Fork | Thinking | MCP | Skills | Plugins | ACP | Platforms |\n|---|---|---|---|---|---|---|---|---|---|---|---|---|\n| Claude Code | `claude` | `claude` | JSONL | yes | yes | yes | yes | yes | yes | partial | no | all |\n| Codex CLI | `codex` | `codex` | JSONL | yes | no | no | yes | yes | no | no | no | all |\n| Gemini CLI | `gemini` | `gemini` | JSONL | yes | no | no | yes | yes | no | no | no | all |\n| Copilot CLI | `gh copilot` | `copilot` | JSON | yes | no | no | no | no | no | no | no | all |\n| Cursor | `cursor` | `cursor` | SQLite | partial | no | no | model-dep | yes | no | yes | no | all |\n| OpenCode | `opencode` | `opencode` | SQLite | yes | yes | yes | model-dep | yes | yes | yes | yes | all |\n| OpenCode HTTP | `opencode serve` | `opencode-http` | SQLite | yes | yes | yes | model-dep | yes | yes | yes | yes | all |\n| Pi | `pi` | `pi` | JSONL tree | yes | yes | yes | model-dep | no | yes | yes | yes | all |\n| omp | `omp` | `omp` | JSONL tree | yes | yes | yes | yes | no | yes | yes | yes | all (Win partial) |\n| OpenClaw | `openclaw` | `openclaw` | JSON | partial | no | no | model-dep | yes | yes | yes | no | all |\n| hermes | `hermes` | `hermes` | SQLite | yes | yes | no | no | yes | yes | yes | yes | darwin/linux |\n\n> **SCOPE EXTENSION:** hermes-agent row added.\n\n**Column notes:**\n- **CLI**: The actual command invoked. For copilot, the command is `gh` with args `['copilot', ...]` (see §5).\n- **`cliCommand`**: The `AgentAdapter.cliCommand` property value (logical agent name).\n- **Stream**: \"yes\" = full text+tool+thinking streaming; \"partial\" = text streaming only.\n- **Resume**: Whether `canResume: true` in capabilities.\n- **Fork**: Whether `canFork: true` in capabilities.\n- **Thinking**: \"yes\" = always supported; \"model-dep\" = depends on `ModelCapabilities.supportsThinking`; \"no\" = not supported.\n- **Plugins**: \"partial\" for Claude = limited to skill-directory and mcp-server formats via `--add-dir`.\n- **Platforms**: \"all\" = darwin, linux, win32; \"all (Win partial)\" = all three platforms but with reduced Windows functionality; \"darwin/linux\" = no native Windows support.\n\n---\n\n## 3. Claude Code Adapter\n\n> **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.\n\n### 3.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'claude'` |\n| `displayName` | `'Claude Code'` |\n| `cliCommand` | `'claude'` |\n| `minVersion` | `'1.0.0'` |\n\n### 3.2 buildSpawnArgs\n\n```typescript\n// Key CLI arguments\nSpawnArgs {\n command: 'claude',\n args: [\n '--print', // Required for structured output\n '--input-format', 'stream-json', // Persistent stdin-driven user turns\n '--output-format', 'stream-json', // Streaming JSON output\n '--replay-user-messages', // Echo stdin user turns back on stdout\n '--model', modelId, // Model selection\n '--thinking-budget', budgetTokens, // Thinking (when enabled)\n '--session', sessionId, // Resume session\n '--add-dir', skillDir, // Skill directories\n '--system', systemPrompt, // System prompt injection\n '--system-mode', systemPromptMode, // prepend | append | replace\n '--max-turns', maxTurns,\n ],\n env: { ANTHROPIC_API_KEY: apiKey },\n usePty: false,\n}\n```\n\n**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.\n\n### 3.3 Event Parsing\n\n**Native format:** Newline-delimited JSON (stream-json). Each line is a JSON object with a `type` field.\n\n**Key native event types and their AgentEvent mappings:**\n\n| Native type | AgentEvent type(s) |\n|---|---|\n| `message_start` | `message_start` |\n| `content_block_start` (text) | (consumed internally — text streaming begins) |\n| `content_block_delta` (text) | `text_delta` |\n| `content_block_start` (thinking) | `thinking_start` |\n| `content_block_delta` (thinking) | `thinking_delta` |\n| `content_block_stop` (thinking) | `thinking_stop` |\n| `content_block_start` (tool_use) | `tool_call_start` |\n| `content_block_delta` (tool_use) | `tool_input_delta` (incremental tool input) |\n| `content_block_stop` (tool_use) | `tool_call_ready` |\n| replayed `user` event with `parent_tool_use_id` + `tool_use_result` | `tool_result` |\n| `message_delta` | (cost extraction → `cost` event) |\n| `message_stop` | `message_stop` |\n| `system.status=requesting` | `turn_start` |\n| `result` | `turn_end` (+ fallback `message_stop` / `cost` when needed) |\n\n**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.\n\n### 3.4 Session Format\n\n- **Location:** `~/.claude/projects/<hash>/` where `<hash>` is a content-hash of the project path.\n- **Format:** JSONL (one JSON object per line).\n- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'file'`.\n\n### 3.5 Thinking Normalization\n\n| Effort | Mapping | CLI arg |\n|---|---|---|\n| `'low'` | `budget_tokens: 1024` | `--thinking-budget 1024` |\n| `'medium'` | `budget_tokens: 8192` | `--thinking-budget 8192` |\n| `'high'` | `budget_tokens: 32768` | `--thinking-budget 32768` |\n| `'max'` | `budget_tokens: max_budget_tokens` | `--thinking-budget max_budget_tokens` |\n\n`thinkingBudgetTokens` is passed through directly. `thinkingOverride` is merged last.\n\n### 3.6 Install Methods\n\n| Platform | Type | Command |\n|---|---|---|\n| all | npm | `npm install -g @anthropic-ai/claude-code` |\n| darwin | brew | `brew install claude-code` |\n\n### 3.7 Auth Detection\n\n- **Primary:** `browser_login` — inspects session token files in `~/.claude/` (per spec 08 §10.1).\n- **Alternative:** `api_key` — checks `ANTHROPIC_API_KEY` environment variable.\n\n> **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.\n\n### 3.8 Plugin Support\n\n- **`supportsPlugins`:** `true` (partial — limited to skill-directory and mcp-server formats).\n- **Formats:** `['skill-directory', 'mcp-server']`.\n- **Mechanism:** `--add-dir` flag for skill directories; MCP servers via config.\n- **No dedicated plugin install/list/uninstall commands.** Plugin operations are mapped to config file manipulation.\n- **No marketplace URL.** No registry.\n\n---\n\n## 4. Codex CLI Adapter\n\n### 4.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'codex'` |\n| `displayName` | `'Codex CLI'` |\n| `cliCommand` | `'codex'` |\n| `minVersion` | `'1.0.0'` |\n\n### 4.2 buildSpawnArgs\n\n```typescript\nSpawnArgs {\n command: 'codex',\n args: [\n prompt,\n '--model', modelId,\n '--reasoning', reasoningLevel, // 'low' | 'medium' | 'high'\n '--session', sessionId,\n ],\n env: { OPENAI_API_KEY: apiKey },\n usePty: false,\n}\n```\n\n### 4.3 Event Parsing\n\n**Native format:** JSONL. OpenAI-style structured events.\n\n**Key native event types and their AgentEvent mappings:**\n\n| Native type | AgentEvent type(s) |\n|---|---|\n| `response.start` | `message_start` |\n| `response.text.delta` | `text_delta` |\n| `response.reasoning.start` | `thinking_start` |\n| `response.reasoning.delta` | `thinking_delta` |\n| `response.reasoning.complete` | `thinking_stop` |\n| `response.function_call` | `tool_call_start` |\n| `response.function_call.delta` | `tool_input_delta` (when streaming tool input) |\n| `response.function_call.complete` | `tool_call_ready` |\n| `response.function_call_output` | `tool_result` |\n| `response.cost` | `cost` |\n| `response.complete` | `message_stop` |\n| `error` | `error` |\n\n### 4.4 Session Format\n\n- **Location:** `~/.codex/sessions/`\n- **Format:** JSONL.\n- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'file'`.\n\n> **Note:** Spec 06 §12.2 confirms `canResume=false, canFork=false` for Codex CLI.\n\n### 4.5 Thinking Normalization\n\n| Effort | Mapping | CLI arg |\n|---|---|---|\n| `'low'` | `'low'` | `--reasoning low` |\n| `'medium'` | `'medium'` | `--reasoning medium` |\n| `'high'` | `'high'` | `--reasoning high` |\n| `'max'` | `'high'` | `--reasoning high` (no separate max tier) |\n\n**Note:** Codex uses discrete reasoning levels, not token budgets. Setting `thinkingBudgetTokens` when `supportsThinkingBudgetTokens: false` throws `CapabilityError` before spawning, per spec 06 §11.\n\n### 4.6 Install Methods\n\n| Platform | Type | Command |\n|---|---|---|\n| all | npm | `npm install -g @openai/codex` |\n\n### 4.7 Auth Detection\n\n- **Primary:** `api_key` — checks `OPENAI_API_KEY` environment variable (validates format: must start with `'sk-'`).\n- **Auth file:** `~/.codex/auth.json`.\n\n### 4.8 Plugin Support\n\n- **`supportsPlugins`:** `false`.\n- All plugin operations throw `CapabilityError`.\n\n---\n\n## 5. Copilot CLI Adapter\n\n### 5.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'copilot'` |\n| `displayName` | `'GitHub Copilot CLI'` |\n| `cliCommand` | `'copilot'` |\n| `minVersion` | `'1.0.0'` |\n\n### 5.2 buildSpawnArgs\n\n```typescript\n// Note: cliCommand is 'copilot' but actual command is 'gh'\nSpawnArgs {\n command: 'gh', // GitHub CLI binary\n args: [\n 'copilot', // gh subcommand\n prompt,\n ],\n env: { GITHUB_TOKEN: token },\n usePty: false,\n}\n```\n\n**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`.\n\n### 5.3 Event Parsing\n\n**Native format:** Plain text streaming with JSON session metadata. Simpler parsing than most agents — primarily produces `text_delta` events.\n\n**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.\n\n**Native output → AgentEvent mappings:**\n\n| Native output pattern | AgentEvent type(s) |\n|---|---|\n| First text line received | `message_start` (synthetic) |\n| Non-JSON text line | `text_delta` |\n| JSON metadata with `session_id` | (consumed internally, not emitted) |\n| Process exit code 0 | `message_stop` (synthetic) |\n| Process exit code non-zero | `crash` |\n\n**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.\n\n**Key limitations:**\n- No `tool_call_start` / `tool_result` / `tool_input_delta` events (`supportsNativeTools: false`).\n- No `thinking_start` / `thinking_delta` / `thinking_stop` events (`supportsThinking: false`).\n- No `mcp_tool_call_start` events (`supportsMCP: false`).\n- No `session_resume` / `session_fork` events (`canResume: false`, `canFork: false`).\n\n### 5.4 Session Format\n\n- **Location:** `~/.config/github-copilot/sessions/`\n- **Format:** JSON.\n- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'file'`.\n\n### 5.5 Thinking Normalization\n\nNot applicable. `supportsThinking: false`. Setting `thinkingEffort` throws `CapabilityError`.\n\n### 5.6 Install Methods\n\n| Platform | Type | Command | Notes |\n|---|---|---|---|\n| all | gh-extension | `gh extension install github/gh-copilot` | Requires GitHub CLI |\n\n**Prerequisite:** `gh --version` must succeed. Install GitHub CLI with `brew install gh` (macOS), `apt install gh` (Debian/Ubuntu), or `winget install GitHub.cli` (Windows).\n\n### 5.7 Auth Detection\n\n- **Primary:** `oauth_device` — checks OAuth token cache in `~/.config/github-copilot/hosts.json`.\n- **Alternative:** `github_token` — checks `GITHUB_TOKEN` environment variable.\n\n### 5.8 Plugin Support\n\n- **`supportsPlugins`:** `false`.\n- All plugin operations throw `CapabilityError`.\n\n---\n\n## 6. Gemini CLI Adapter\n\n### 6.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'gemini'` |\n| `displayName` | `'Gemini CLI'` |\n| `cliCommand` | `'gemini'` |\n| `minVersion` | `'1.0.0'` |\n\n### 6.2 buildSpawnArgs\n\n```typescript\nSpawnArgs {\n command: 'gemini',\n args: [\n prompt,\n '--model', modelId,\n ],\n env: { GOOGLE_API_KEY: apiKey },\n usePty: false,\n}\n```\n\n**MCP servers:** Configured via the Gemini config file, not CLI args. The adapter writes MCP server definitions to `~/.config/gemini/settings.json` before spawn.\n\n### 6.3 Event Parsing\n\n**Native format:** JSONL streaming output. Google-specific event shapes translated to AgentEvent.\n\n**Key native event types and their AgentEvent mappings:**\n\n| Native type | AgentEvent type(s) |\n|---|---|\n| `generateContent.start` | `message_start` |\n| `generateContent.text` | `text_delta` |\n| `generateContent.thought.start` | `thinking_start` |\n| `generateContent.thought` | `thinking_delta` |\n| `generateContent.thought.done` | `thinking_stop` |\n| `generateContent.functionCall` | `tool_call_start` |\n| `generateContent.functionCall.delta` | `tool_input_delta` (when streaming tool input) |\n| `generateContent.functionCall.done` | `tool_call_ready` |\n| `generateContent.functionResponse` | `tool_result` |\n| `generateContent.image` | `image_output` |\n| `generateContent.done` | `message_stop` |\n| `usage` | `cost` (token usage extraction) |\n\n**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.\n\n### 6.4 Session Format\n\n- **Location:** `~/.gemini/sessions/`\n- **Format:** JSONL.\n- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'file'`.\n\n> **Note:** Spec 06 §12.3 confirms `canResume=false, canFork=false` for Gemini CLI.\n\n### 6.5 Thinking Normalization\n\n| Effort | Mapping | CLI mechanism |\n|---|---|---|\n| `'low'` | `thinkingConfig.thinkingBudget: 1024` | `--thinking-budget 1024` |\n| `'medium'` | `thinkingConfig.thinkingBudget: 8192` | `--thinking-budget 8192` |\n| `'high'` | `thinkingConfig.thinkingBudget: 32768` | `--thinking-budget 32768` |\n| `'max'` | `thinkingConfig.thinkingBudget: max` | `--thinking-budget max` |\n\nMaps to Gemini's `thinkingConfig` equivalents. The `--thinking-budget` CLI flag is passed in the `args` array of `SpawnArgs` when `thinkingEffort` is set.\n\n### 6.6 Install Methods\n\n| Platform | Type | Command |\n|---|---|---|\n| all | npm | `npm install -g @google/gemini-cli` |\n\n### 6.7 Auth Detection\n\n- **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`.\n- 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).\n\n### 6.8 Plugin Support\n\n- **`supportsPlugins`:** `false`.\n- All plugin operations throw `CapabilityError`.\n\n---\n\n## 7. Cursor Adapter\n\n### 7.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'cursor'` |\n| `displayName` | `'Cursor'` |\n| `cliCommand` | `'cursor'` |\n| `minVersion` | `'0.45.0'` |\n\n### 7.2 buildSpawnArgs\n\n```typescript\nSpawnArgs {\n command: 'cursor',\n args: [\n prompt,\n '--model', modelId,\n ],\n env: {}, // Auth via session token, not env var\n usePty: false,\n}\n```\n\n> **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).\n\n### 7.3 Event Parsing\n\n**Native format:** Partial streaming — text events are streamed, but tool call results may be buffered. The adapter handles both streaming and buffered output.\n\n**Key native event types and their AgentEvent mappings:**\n\n| Native output pattern | AgentEvent type(s) |\n|---|---|\n| Stream start marker | `message_start` |\n| Text chunk | `text_delta` |\n| Tool invocation (buffered JSON) | `tool_call_start`, `tool_call_ready` |\n| Tool output (buffered JSON) | `tool_result` |\n| Completion marker | `message_stop` |\n| Non-zero exit / error JSON | `crash` or `error` |\n\n**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.\n\n### 7.4 Session Format\n\n- **Location:** `~/.cursor/sessions/`\n- **Format:** SQLite.\n- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'sqlite'`.\n\n### 7.5 Thinking Normalization\n\nModel-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`.\n\n### 7.6 Install Methods\n\n| Platform | Type | Command | Notes |\n|---|---|---|---|\n| darwin | manual | `open https://cursor.sh/download` | macOS .dmg installer |\n| linux | manual | `open https://cursor.sh/download` | AppImage |\n| win32 | winget | `winget install Cursor.Cursor` | |\n\n**Note:** No headless-only install. Full app required even for CLI use.\n\n### 7.7 Auth Detection\n\n- **Primary:** `browser_login` — inspects session token in `~/.cursor/auth.json` (per spec 08 §10.1).\n- **Alternative:** `api_key` — checks `CURSOR_API_KEY` environment variable.\n\n> **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.\n\n### 7.8 Plugin Support\n\n- **`supportsPlugins`:** `true`.\n- **Formats:** `['extension-ts', 'mcp-server']`.\n- **Registry:** `{ name: 'cursor-extensions', url: 'https://cursor.sh/extensions', searchable: true }`.\n- Cursor uses its own extension system for TypeScript extensions.\n\n---\n\n## 8. OpenCode Adapter\n\n### 8.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'opencode'` |\n| `displayName` | `'OpenCode'` |\n| `cliCommand` | `'opencode'` |\n| `minVersion` | `'1.0.0'` |\n\n### 8.2 buildSpawnArgs\n\n```typescript\nSpawnArgs {\n command: 'opencode',\n args: [\n prompt,\n '--model', modelId,\n '--session', sessionId,\n '--fork', forkSessionId,\n ],\n env: { /* provider-specific: ANTHROPIC_API_KEY or OPENAI_API_KEY */ },\n usePty: false,\n}\n```\n\n### 8.3 Event Parsing\n\n**Native format:** Structured JSON streaming. Full tool call streaming. ACP event types also emitted.\n\n**Key native event types and their AgentEvent mappings:**\n\n| Native type | AgentEvent type(s) |\n|---|---|\n| `message.start` | `message_start` |\n| `message.text.delta` | `text_delta` |\n| `message.thinking.start` | `thinking_start` (when model supports thinking) |\n| `message.thinking.delta` | `thinking_delta` (when model supports thinking) |\n| `message.thinking.done` | `thinking_stop` (when model supports thinking) |\n| `tool.call` | `tool_call_start` |\n| `tool.call.delta` | `tool_input_delta` |\n| `tool.call.done` | `tool_call_ready` |\n| `tool.result` | `tool_result` |\n| `mcp.tool.call` | `mcp_tool_call_start` |\n| `mcp.tool.result` | `mcp_tool_result` |\n| `message.complete` | `message_stop` |\n\n**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.\n\n**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.\n\n**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.\n\n### 8.4 Session Format\n\n- **Location:** `~/.local/share/opencode/` (XDG data home on Linux; platform-appropriate on macOS/Windows).\n- **Format:** SQLite.\n- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'sqlite'`.\n\n### 8.5 Thinking Normalization\n\nModel-dependent. Passed as provider-level parameter when model supports thinking.\n\n### 8.6 Install Methods\n\n| Platform | Type | Command |\n|---|---|---|\n| all | npm | `npm install -g opencode` |\n| darwin | brew | `brew install opencode/tap/opencode` |\n\n### 8.7 Auth Detection\n\n- **Primary:** `api_key` — checks provider-specific env vars (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`) based on configured provider.\n- **Auth file:** `~/.config/opencode/auth.json`.\n\n### 8.8 Plugin Support\n\n- **`supportsPlugins`:** `true`.\n- **Formats:** `['npm-package', 'skill-file', 'mcp-server']`.\n- **Registry:** `{ name: 'npm', url: 'https://www.npmjs.com/search?q=opencode-', searchable: true }`.\n- **Marketplace:** `https://www.npmjs.com/search?q=opencode-`.\n\n---\n\n## 8.b OpenCode HTTP Adapter\n\n### 8.b.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'opencode-http'` |\n| `displayName` | `'OpenCode (HTTP)'` |\n| `adapterType` | `'remote'` |\n| `connectionType` | `'http'` |\n| `minVersion` | `'0.1.0'` |\n\n**Note**: This is a **remote adapter** (not subprocess), implementing the `RemoteAdapter` interface.\n\n### 8.b.2 Connection Management\n\n```typescript\n// HTTP connection via RemoteAdapter interface\ninterface OpenCodeHttpConnection {\n connectionType: 'http';\n baseUrl: string; // e.g., 'http://localhost:9527'\n \n // Server-Sent Events streaming\n stream(path: string, data: unknown): AsyncIterableIterator<AgentEvent>;\n \n // REST API methods\n get(path: string, params?: Record<string, unknown>): Promise<unknown>;\n post(path: string, data?: unknown): Promise<unknown>;\n}\n```\n\n**Server management**: The adapter automatically starts `opencode serve --port 0` when needed and manages the server lifecycle.\n\n### 8.b.3 Event Parsing\n\n**Transport:** HTTP POST to `/api/chat/stream` with Server-Sent Events (SSE).\n\n**Event format:** SSE events are parsed from `data: {...}` lines, with JSON payloads matching OpenCode's native event structure.\n\n| SSE Event Type | AgentEvent type(s) |\n|---|---|\n| `message.start` | `message_start` |\n| `message.text.delta` | `text_delta` |\n| `tool_start`, `tool_call` | `tool_call_start` |\n| `tool_input` | `tool_input_delta` |\n| `tool_ready` | `tool_call_ready` |\n| `tool_result` | `tool_result` |\n| `message.stop` | `message_stop` |\n\n**Enhanced streaming**: SSE provides lower latency than subprocess stdout parsing.\n\n### 8.b.4 Session Format\n\n- **Location:** Same as subprocess OpenCode: `~/.local/share/opencode/` (XDG data home on Linux).\n- **Format:** SQLite (shared with subprocess adapter).\n- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'sqlite'`.\n\n### 8.b.5 Server Lifecycle\n\n- **Startup**: `opencode serve --port 0 --host 127.0.0.1` with dynamic port allocation.\n- **Health monitoring**: Regular `/health` endpoint checks.\n- **Cleanup**: Graceful server shutdown on adapter disposal.\n- **Port management**: Automatic port discovery to avoid conflicts.\n\n### 8.b.6 Auth Detection\n\n- **Inherited**: Uses same auth detection as subprocess OpenCode adapter.\n- **Provider support**: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GOOGLE_API_KEY`.\n- **Config file**: `~/.config/opencode/config.json`.\n\n### 8.b.7 Plugin Support\n\n- **Identical to subprocess adapter**: Supports MCP servers via HTTP API.\n- **Formats:** `['mcp-server']`.\n- **Registry:** MCP server marketplace at https://modelcontextprotocol.io.\n\n**Advantage**: HTTP interface enables enhanced MCP plugin management compared to subprocess limitations.\n\n---\n\n## 10. Pi Adapter\n\n### 9.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'pi'` |\n| `displayName` | `'Pi'` |\n| `cliCommand` | `'pi'` |\n| `minVersion` | `'1.0.0'` |\n\n### 9.2 buildSpawnArgs\n\n```typescript\nSpawnArgs {\n command: 'pi',\n args: [\n prompt,\n '--model', modelId,\n '--session', sessionId,\n '--fork', forkSessionId,\n ],\n env: { /* provider-specific */ },\n usePty: false,\n}\n```\n\n### 9.3 Event Parsing\n\n**Native format:** JSONL streaming. Each line is a JSON object with `id`, `parentId`, `type`, and `data` fields.\n\n**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:\n\n| Native `type` field | AgentEvent type(s) |\n|---|---|\n| `message_start` | `message_start` |\n| `text` | `text_delta` |\n| `thinking_start` | `thinking_start` (when model supports thinking) |\n| `thinking` | `thinking_delta` (when model supports thinking) |\n| `thinking_end` | `thinking_stop` (when model supports thinking) |\n| `tool_call` | `tool_call_start` |\n| `tool_call_input` | `tool_input_delta` (when streaming tool input) |\n| `tool_call_ready` | `tool_call_ready` |\n| `tool_result` | `tool_result` |\n| `message_end` | `message_stop` |\n| `error` | `error` |\n\n**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.\n\n### 9.4 Session Format\n\n- **Location:** `~/.pi/agent/sessions/`\n- **Format:** JSONL tree (each entry has `id` and `parentId` fields forming a conversation tree).\n- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'file'`.\n\n**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.\n\n### 9.5 Thinking Normalization\n\nModel-dependent. Passed as provider-level parameter when model supports thinking.\n\n### 9.6 Install Methods\n\n| Platform | Type | Command |\n|---|---|---|\n| all | npm | `npm install -g @mariozechner/pi-coding-agent` |\n\n### 9.7 Auth Detection\n\n- **Primary:** `api_key` — checks provider-specific env vars based on configured provider.\n- **Auth file:** `~/.pi/agent/auth.json`.\n\n### 9.8 Plugin Support\n\n- **`supportsPlugins`:** `true`.\n- **Formats:** `['npm-package', 'skill-file']`.\n- **Registry:** `{ name: 'npm', url: 'https://www.npmjs.com/search?q=%40mariozechner%2Fpi-', searchable: true }`.\n\n---\n\n## 11. omp Adapter\n\n### 10.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'omp'` |\n| `displayName` | `'omp (oh-my-pi)'` |\n| `cliCommand` | `'omp'` |\n| `minVersion` | `'1.0.0'` |\n\n### 10.2 buildSpawnArgs\n\n```typescript\nSpawnArgs {\n command: 'omp',\n args: [\n prompt,\n '--model', modelId,\n '--session', sessionId,\n '--fork', forkSessionId,\n ],\n env: { /* provider-specific */ },\n usePty: false,\n}\n```\n\n### 10.3 Event Parsing\n\n**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.\n\n**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).\n\n### 10.4 Session Format\n\n- **Location:** `~/.omp/agent/sessions/`\n- **Format:** JSONL tree (identical to Pi — same `id`/`parentId` structure).\n- **Capabilities:** `canResume: true`, `canFork: true`, `sessionPersistence: 'file'`.\n\n### 10.5 Thinking Normalization\n\n**Always supported** (not model-dependent, unlike Pi):\n\n| Effort | Mapping |\n|---|---|\n| `'low'` | `budget_tokens: 1024` |\n| `'medium'` | `budget_tokens: 8192` |\n| `'high'` | `budget_tokens: 32768` |\n| `'max'` | `budget_tokens: max_budget_tokens` |\n\n**Key difference from Pi:** omp unconditionally supports all thinking effort levels. Setting `thinkingEffort` never throws `CapabilityError` for omp, regardless of model.\n\n### 10.6 Install Methods\n\n| Platform | Type | Command |\n|---|---|---|\n| all | npm | `npm install -g @oh-my-pi/pi-coding-agent` |\n\n### 10.7 Auth Detection\n\n- Same approach as Pi: provider-specific env var inspection.\n- **Auth file:** `~/.omp/agent/auth.json`.\n\n### 10.8 Plugin Support\n\n- **`supportsPlugins`:** `true`.\n- **Formats:** `['npm-package', 'skill-file']`.\n- **Registry:** `{ name: 'npm', url: 'https://www.npmjs.com/search?q=%40oh-my-pi%2F', searchable: true }`.\n\n### 10.9 Platform Notes\n\n- **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.\n- **`supportedPlatforms`:** `['darwin', 'linux', 'win32']`.\n- See `11-process-lifecycle-and-platform.md` §5.2 for full details.\n\n---\n\n## 12. OpenClaw Adapter\n\n### 11.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'openclaw'` |\n| `displayName` | `'OpenClaw'` |\n| `cliCommand` | `'openclaw'` |\n| `minVersion` | `'1.0.0'` |\n\n### 11.2 buildSpawnArgs\n\n```typescript\nSpawnArgs {\n command: 'openclaw',\n args: [\n prompt,\n '--model', modelId,\n ],\n env: { OPENCLAW_API_KEY: apiKey },\n usePty: true, // Requires PTY\n}\n```\n\n### 11.3 Event Parsing\n\n**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.\n\n**Parsing pipeline:** Raw PTY output → `VtStripper.strip()` → JSON.parse per line → native type → AgentEvent.\n\n**Key native event types and their AgentEvent mappings (after VT stripping):**\n\n| Native JSON `type` field | AgentEvent type(s) |\n|---|---|\n| `response.start` | `message_start` |\n| `response.text` | `text_delta` |\n| `response.thinking.start` | `thinking_start` (model-dependent) |\n| `response.thinking` | `thinking_delta` (model-dependent) |\n| `response.thinking.end` | `thinking_stop` (model-dependent) |\n| `tool.invoke` | `tool_call_start` |\n| `tool.invoke.delta` | `tool_input_delta` |\n| `tool.invoke.done` | `tool_call_ready` |\n| `tool.output` | `tool_result` |\n| `channel.event` | `plugin_invoked` (channel-plugin activity) |\n| `plugin.loaded` | `plugin_loaded` |\n| `response.end` | `message_stop` |\n| `error` | `error` |\n\n**Session lifecycle:** OpenClaw has `canResume: false`, `canFork: false`, so `session_resume` and `session_fork` events are never emitted.\n\n**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.\n\n**Partial streaming:** Text events are streamed in real-time, but tool results may be buffered until the tool completes.\n\n### 11.4 Session Format\n\n- **Location:** `~/.openclaw/sessions/`\n- **Format:** JSON (per channel/session).\n- **Capabilities:** `canResume: false`, `canFork: false`, `sessionPersistence: 'file'`.\n\n### 11.5 Thinking Normalization\n\nModel-dependent. Passed as provider-level parameter when model supports thinking.\n\n### 11.6 Install Methods\n\n| Platform | Type | Command | Notes |\n|---|---|---|---|\n| all | npm | `npm install -g openclaw` | Requires Node 22.16+, 16GB RAM minimum |\n\n### 11.7 Auth Detection\n\n- **Primary:** `api_key` — checks provider-specific env vars.\n- **Auth file:** `~/.openclaw/auth.json`.\n\n### 11.8 Plugin Support\n\n- **`supportsPlugins`:** `true`.\n- **Formats:** `['npm-package', 'skill-file', 'channel-plugin']`.\n- **Registries:** `[{ name: 'npm', searchable: true }, { name: 'openclaw-registry', url: 'https://openclaw.ai/plugins', searchable: true }]`.\n- **Unique format:** `channel-plugin` for messaging gateways (Telegram, Discord, Slack, WhatsApp, Signal).\n\n### 11.9 PTY Requirement\n\nOpenClaw is the only built-in agent with `requiresPty: true` (scope §22). See `11-process-lifecycle-and-platform.md` §6 for PTY details.\n\n> **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.\n\n### 11.10 Platform Notes\n\n- **Windows:** Requires ConPTY (Windows 10 1809+). Older Windows versions fall back to winpty with potential output buffering differences.\n\n---\n\n## 13. Hermes Adapter\n\n> **SCOPE EXTENSION:** hermes-agent (`@NousResearch/hermes-agent`) is included as a 10th supported agent.\n\n### 12.1 Identity\n\n| Property | Value |\n|---|---|\n| `agent` | `'hermes'` |\n| `displayName` | `'hermes-agent'` |\n| `cliCommand` | `'hermes'` |\n| `minVersion` | `'0.1.0'` |\n\n### 12.2 buildSpawnArgs\n\n```typescript\nSpawnArgs {\n command: 'hermes',\n args: [\n prompt,\n '--output-format', 'jsonl', // Required for structured output\n '--model', modelId, // Model selection (multi-provider)\n '--session', sessionId, // Resume session (canResume=true)\n ],\n env: {\n // Multi-provider: set whichever key is configured\n OPENROUTER_API_KEY: ...,\n NOUS_API_KEY: ...,\n ANTHROPIC_API_KEY: ...,\n OPENAI_API_KEY: ...,\n GITHUB_TOKEN: ...,\n GOOGLE_API_KEY: ...,\n },\n usePty: false,\n}\n```\n\n**Critical:** The `--output-format jsonl` flag must always be passed. Without it, hermes produces human-readable text that cannot be parsed by `parseEvent()`.\n\n### 12.3 Event Parsing\n\n**Native format:** JSONL via `--output-format jsonl`. Python process emits structured events.\n\n**Key native event types and their AgentEvent mappings:**\n\n| Native `type` field | AgentEvent type(s) |\n|---|---|\n| `message_start` | `message_start` |\n| `text_delta` | `text_delta` |\n| `tool_call` | `tool_call_start` |\n| `tool_call_input` | `tool_input_delta` |\n| `tool_call_ready` | `tool_call_ready` |\n| `tool_result` | `tool_result` |\n| `mcp_tool_call` | `mcp_tool_call_start` |\n| `mcp_tool_result` | `mcp_tool_result` |\n| `skill_loaded` | `skill_loaded` (maps to `SkillLoadedEvent`, not `PluginLoadedEvent`) |\n| `skill_invoked` | `skill_invoked` (maps to `SkillInvokedEvent`, not `PluginInvokedEvent`) |\n| `message_end` | `message_stop` |\n| `usage` | `cost` |\n| `error` | `error` |\n\n**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).\n\n**MCP events:** MCP tool events (`mcp_tool_call_start`, `mcp_tool_result`) are emitted when hermes invokes tools from connected MCP servers.\n\n**Session lifecycle:** hermes has `canResume: true`, `canFork: false`. The adapter synthesizes `session_resume` when invoked with `--session`. No `session_fork` events.\n\n**Thinking:** hermes has `supportsThinking: false`, so `thinking_start`, `thinking_delta`, and `thinking_stop` events are never emitted.\n\n### 12.4 Session Format\n\n- **Location:** `~/.hermes/` (SQLite database).\n- **Format:** SQLite with FTS5 full-text search support.\n- **Capabilities:** `canResume: true`, `canFork: false`, `sessionPersistence: 'sqlite'`.\n\n> **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.\n\n### 12.5 Thinking Normalization\n\nNot applicable. `supportsThinking: false`. Setting `thinkingEffort` throws `CapabilityError`.\n\n### 12.6 Install Methods\n\n| Platform | Type | Command | Notes |\n|---|---|---|---|\n| all | pip | `pip install hermes-agent` | Requires Python >= 3.11 |\n| 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. |\n| all | nix | `nix run github:NousResearch/hermes-agent` | Nix flake available |\n\n> **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.\n\n### 12.7 Auth Detection\n\n- **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`.\n- **Alternative:** `oauth` — checks OAuth token cache from `hermes login` (Nous Portal or OpenAI Codex).\n- **Alternative:** `github_token` — checks `GITHUB_TOKEN` for GitHub-backed model access.\n- **Alternative:** `config_file` — inspects `~/.hermes/cli-config.yaml` for embedded API keys (YAML safe-load only).\n- Returns `'authenticated'` if any valid credential is found for any provider.\n- `AuthState.details` lists all detected providers with their auth method.\n\n> **SCOPE EXTENSION:** hermes-agent supports the broadest set of auth methods (6+ env vars, YAML config, OAuth) reflecting its multi-provider architecture.\n\n### 12.8 Plugin Support\n\n- **`supportsPlugins`:** `true`.\n- **Formats:** `['skill-file', 'skill-directory', 'mcp-server']`.\n- **Registry:** `{ name: 'agentskills-hub', url: 'https://agentskills.io', searchable: true }`.\n- **MCP:** Supports both MCP client (connecting to external MCP servers) and MCP server (exposing hermes capabilities via `mcp_serve.py`).\n- **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.\n\n### 12.9 Platform Notes\n\n- **macOS / Linux:** Fully supported.\n- **Windows:** WSL2 only. Native Windows is not supported. See `11-process-lifecycle-and-platform.md` §5.3.\n- **`supportedPlatforms`:** `['darwin', 'linux']` — does not include `'win32'`.\n- **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.\n\n---\n\n## 14. Per-Adapter Thinking Effort Summary\n\n| Agent | `'low'` | `'medium'` | `'high'` | `'max'` | Budget tokens | Notes |\n|---|---|---|---|---|---|---|\n| claude | 1024 | 8192 | 32768 | max_budget_tokens | Passed through | `--thinking-budget` flag |\n| codex | `'low'` | `'medium'` | `'high'` | `'high'` | Ignored | `--reasoning` flag; max→high |\n| gemini | 1024 | 8192 | 32768 | max | Via thinkingConfig | thinkingConfig equivalents |\n| copilot | — | — | — | — | — | `supportsThinking: false` |\n| cursor | model-dep | model-dep | model-dep | model-dep | model-dep | Provider-level param |\n| opencode | model-dep | model-dep | model-dep | model-dep | model-dep | Provider-level param |\n| pi | model-dep | model-dep | model-dep | model-dep | model-dep | Provider-level param |\n| omp | 1024 | 8192 | 32768 | max_budget_tokens | Passed through | Always supported |\n| openclaw | model-dep | model-dep | model-dep | model-dep | model-dep | Provider-level param |\n| hermes | — | — | — | — | — | `supportsThinking: false` |\n\n**Cross-reference:** Full thinking normalization tables are in `06-capabilities-and-models.md` §8.\n\n---\n\n## 15. Per-Adapter Auth Summary\n\n| Agent | Primary method | Env var(s) | Auth file |\n|---|---|---|---|\n| claude | `browser_login` | `ANTHROPIC_API_KEY` | `~/.claude/` (session tokens) |\n| codex | `api_key` | `OPENAI_API_KEY` | `~/.codex/auth.json` |\n| gemini | `browser_login` / `api_key` | `GOOGLE_API_KEY`, `GEMINI_API_KEY` | `~/.config/gemini/credentials.json` |\n| copilot | `oauth_device` | `GITHUB_TOKEN` | `~/.config/github-copilot/hosts.json` |\n| cursor | `browser_login` | `CURSOR_API_KEY` (fallback) | `~/.cursor/auth.json` |\n| opencode | `api_key` | Provider-specific | `~/.config/opencode/auth.json` |\n| pi | `api_key` | Provider-specific | `~/.pi/agent/auth.json` |\n| omp | `api_key` | Provider-specific | `~/.omp/agent/auth.json` |\n| openclaw | `api_key` | Provider-specific | `~/.openclaw/auth.json` |\n| hermes | Multi (6+ methods) | 6+ env vars | `~/.hermes/.env`, `~/.hermes/cli-config.yaml` |\n\n**Cross-reference:** Full auth detection strategies are in `08-config-and-auth.md` §10.1.\n\n**Invariant:** All auth detection is read-only, local-only, no network calls, completes under 100ms.\n\n---\n\n## 16. Per-Adapter Plugin Support Summary\n\n| Agent | `supportsPlugins` | Formats | Registry | Marketplace |\n|---|---|---|---|---|\n| claude | `true` (partial) | skill-directory, mcp-server | — | — |\n| codex | `false` | — | — | — |\n| gemini | `false` | — | — | — |\n| copilot | `false` | — | — | — |\n| cursor | `true` | extension-ts, mcp-server | cursor-extensions | `https://cursor.sh/extensions` |\n| opencode | `true` | npm-package, skill-file, mcp-server | npm | `https://www.npmjs.com/search?q=opencode-` |\n| pi | `true` | npm-package, skill-file | npm | `https://www.npmjs.com/search?q=%40mariozechner%2Fpi-` |\n| omp | `true` | npm-package, skill-file | npm | `https://www.npmjs.com/search?q=%40oh-my-pi%2F` |\n| openclaw | `true` | npm-package, skill-file, channel-plugin | npm + openclaw-registry | `https://openclaw.ai/plugins` |\n| hermes | `true` | skill-file, skill-directory, mcp-server | agentskills-hub | `https://agentskills.io` |\n\n**Cross-reference:** Full plugin support matrix in `06-capabilities-and-models.md` §9 and `09-plugin-manager.md`.\n\n---\n\n## 17. Error Format Translation\n\nAll adapters translate native agent errors into typed `AgentEvent` objects. The `BaseAgentAdapter` class (spec 05 §4) provides hook methods for common error scenarios:\n\n### 16.1 Error Event Mappings\n\n| Native error type | AgentEvent `type` | Fields |\n|---|---|---|\n| Auth failure (invalid/missing key) | `auth_error` | `agent`, `message`, `guidance` |\n| Rate limit / quota exceeded | `rate_limit_error` | `message`, `retryAfterMs` |\n| Context window exceeded | `context_exceeded` | `usedTokens`, `maxTokens` |\n| Process crash (non-zero exit) | `crash` | `exitCode`, `stderr` |\n| Generic / unknown error | `error` | `code: ErrorCode`, `message`, `recoverable` |\n\n### 16.2 parseEvent() Contract\n\n- `parseEvent()` **must never throw**. Unrecognized lines return `null`.\n- 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).\n- Empty lines and whitespace-only lines are silently dropped.\n\n### 16.3 BaseAgentAdapter Error Hooks\n\nPer spec 05 §4 (canonical signatures):\n\n| Hook | Signature | Trigger | Default behavior |\n|---|---|---|---|\n| `onSpawnError(error)` | `(error: Error) → AgentEvent` | Subprocess fails to start | Returns `{ type: 'crash', exitCode: -1, stderr: error.message }` |\n| `onTimeout()` | `() → AgentEvent` | Run or inactivity timeout | Returns `{ type: 'error', code: 'TIMEOUT', recoverable: false }` |\n| `onProcessExit(code, signal)` | `(exitCode: number, signal: string \\| null) → AgentEvent[]` | Subprocess exits | Returns terminal events based on exit code/signal |\n| `shouldRetry(event, attempt, policy)` | `(event: AgentEvent, attempt: number, policy: RetryPolicy) → boolean` | After error, before retry | Returns `false` (no retry by default) |\n\n---\n\n## 18. Version Detection\n\nAll adapters detect the installed agent version via `detectVersionFromCli()` (a `BaseAgentAdapter` utility):\n\n```typescript\n// Default: runs `<cliCommand> --version` and parses semver\nconst version = await detectVersionFromCli(adapter.cliCommand);\n```\n\n**Exceptions:**\n- **Copilot:** Runs `gh copilot --version` (not `copilot --version`).\n- **hermes:** Runs `hermes --version`; output is Python-formatted (e.g., `hermes-agent 0.1.0`).\n\nThe 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.\n\n---\n\n## 19. Adapter Registration\n\nAll 10 built-in adapters are registered with the `AdapterRegistry` during `createClient()`:\n\n```typescript\n// Simplified registration sequence\nconst registry = new AdapterRegistry();\nregistry.register(new ClaudeCodeAdapter());\nregistry.register(new CodexAdapter());\nregistry.register(new GeminiAdapter());\nregistry.register(new CopilotAdapter());\nregistry.register(new CursorAdapter());\nregistry.register(new OpenCodeAdapter());\nregistry.register(new PiAdapter());\nregistry.register(new OmpAdapter());\nregistry.register(new OpenClawAdapter());\nregistry.register(new HermesAdapter());\n```\n\nPlugin adapters registered via `mux.adapters.register()` are added after built-in adapters and extend the `AgentName` union at runtime.\n\n---\n\n## 20. Spec-Level Additions\n\nThe following items are spec-level additions not explicitly stated in the scope:\n\n| Addition | Section | Rationale |\n|---|---|---|\n| `minVersion` per adapter | §3–12 | Required for version compatibility checking |\n| hermes `--output-format jsonl` requirement | §12.2 | Not stated in scope; discovered through research |\n| hermes FTS5 session search | §12.4 | SQLite FTS5 support is hermes-specific |\n| Claude session hash-based paths | §3.4 | Implementation detail not in scope |\n| Codex `'max'` → `'high'` mapping | §4.5 | Scope says `'max'→'high'` but only in comment |\n| `parseEvent()` never-throw contract | §16.2 | Implied by spec 05 but not explicit in scope |\n| Debug-mode logging of unrecognized lines | §16.2 | Extension for adapter debugging |\n| Copilot `gh` vs `copilot` command split | §5.2 | Scope lists `copilot` as CLI but actual binary is `gh` |\n| OpenClaw PTY reconciliation note | §11.9 | Corrects spec 06 cross-spec error |\n| Cursor PTY reconciliation note | §7.2 | Corrects spec 06 cross-spec error (swapped with OpenClaw) |\n| Auth method reconciliation notes | §3.7, §7.7 | Resolves spec 06 vs spec 08 auth method naming discrepancies |\n| Per-adapter event mapping tables | §3–12 | Scope describes formats, not specific native event types |\n| Session lifecycle event synthesis | §3–12 | Adapters synthesize session_resume/session_fork from metadata |\n| hermes nix install method | §12.6 | From spec 06 §7.10; extends scope's install union |\n| Prompt delivery via stdin | §3.2 | Implementation detail for long/array prompts |\n| OpenCode ACP events as debug | §8.3 | ACP events not in AgentEvent union; translated to debug |\n\n---\n\n## Implementation Status (2026-04-12)\n\n### Per-adapter session directories\n\nVerified from each adapter's `sessionDir()`:\n\n| Agent | Session directory |\n|---|---|\n| `claude` | `~/.claude/projects` |\n| `codex` | `~/.codex/sessions` |\n| `gemini` | `~/.gemini/sessions` |\n| `copilot` | `~/.config/github-copilot/sessions` |\n| `cursor` | `~/.cursor/sessions` |\n| `opencode` | `~/.local/share/opencode` |\n| `pi` | `~/.pi/agent/sessions` |\n| `omp` | `~/.omp/agent/sessions` |\n| `openclaw` | `~/.openclaw/sessions` |\n| `hermes` | `~/.hermes/sessions` |\n| `agent-mux-remote` | (none — transport-delegated) |\n\nAll 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.\n\n### 13. `agent-mux-remote` (11th built-in adapter)\n\n`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.\n\nKey fields:\n\n| Field | Value |\n|---|---|\n| `agent` | `'agent-mux-remote'` |\n| `displayName` | `agent-mux (remote via invocation mode)` |\n| `cliCommand` | `amux` |\n| `hostEnvSignals` | `[]` |\n| `sessionDir()` | throws (delegated; the remote amux owns sessions) |\n| Auth | `{ type: 'api_key', name: 'Transport' }` — handled by the chosen invocation mode. |\n\nRuntime configuration is supplied via `RunOptions.env`:\n\n- `AMUX_REMOTE_AGENT` — the harness to invoke on the remote side (default `claude`).\n\nStructured JSONL events produced by the nested `amux run` are passed through unchanged.\n",
"documents": []
},
"outgoingEdges": [],
"incomingEdges": []
}