# Platform Support Matrix This document provides a comprehensive comparison of all platforms supported by context-mode, including their hook paradigms, capabilities, configuration, and known limitations. ## Overview context-mode supports 17 client platforms, plus the OpenClaw gateway integration, across three hook paradigms: | Paradigm | Platforms | |----------|-----------| | **JSON stdin/stdout** | Claude Code, Gemini CLI, VS Code Copilot, JetBrains Copilot, GitHub Copilot CLI, Cursor, Codex CLI, Qwen Code, Kimi Code, Antigravity CLI (`agy`), Kiro | | **TS Plugin** | OpenCode, KiloCode, OpenClaw | | **MCP-only** | Antigravity, Zed, Pi, OMP (Oh My Pi) | The MCP server layer is 100% portable and needs no adapter. Only the hook layer requires platform-specific adapters. ## Prerequisites All platforms (except Claude Code plugin install) require a global install: ```bash npm install -g context-mode ``` This puts the `context-mode` binary in PATH, which is required for: - **MCP server:** `"command": "context-mode"` (replaces ephemeral `npx -y context-mode`) - **Hook dispatcher:** `context-mode hook ` (replaces `node ./node_modules/...` paths) - **Utility commands:** `context-mode doctor`, `context-mode upgrade` - **Persistent upgrades:** `ctx-upgrade` updates the global binary in-place --- ## Main Comparison Table | Feature | Claude Code | Qwen Code | Gemini CLI | VS Code Copilot | JetBrains Copilot | GitHub Copilot CLI | Cursor | OpenCode | KiloCode | OpenClaw | Codex CLI | Kimi Code | Antigravity | Antigravity CLI (`agy`) | Kiro | Zed | Pi | OMP | |---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| | **Paradigm** | json-stdio | json-stdio | json-stdio | json-stdio | json-stdio | json-stdio | json-stdio | ts-plugin | ts-plugin | ts-plugin | json-stdio | json-stdio | mcp-only | json-stdio | json-stdio | mcp-only | mcp-only | mcp-only | | **PreToolUse equivalent** | `PreToolUse` | `PreToolUse` | `BeforeTool` | `PreToolUse` | `PreToolUse` | `preToolUse` | `preToolUse` | `tool.execute.before` | `tool.execute.before` | `tool_call:before` | `PreToolUse` | `PreToolUse` | -- | `PreToolUse` (bounded) | `preToolUse` | -- | -- | -- | | **PostToolUse equivalent** | `PostToolUse` | `PostToolUse` | `AfterTool` | `PostToolUse` | `PostToolUse` | `postToolUse` | `postToolUse` | `tool.execute.after` | `tool.execute.after` | `tool_call:after` | `PostToolUse` | `PostToolUse` | -- | `PostToolUse` (capture-only) | `postToolUse` | -- | -- | -- | | **PreCompact equivalent** | `PreCompact` | `PreCompact` | `PreCompress` | `PreCompact` | `PreCompact` | `preCompact` | -- | `experimental.session.compacting` | `experimental.session.compacting` | `registerContextEngine` | -- | `PreCompact` | -- | -- | -- | -- | -- | -- | | **SessionStart** | `SessionStart` | `SessionStart` | `SessionStart` | `SessionStart` | `SessionStart` | `sessionStart` | -- (buggy in Cursor) | -- | -- | `command:new` | `SessionStart` | `SessionStart` | -- | -- | -- | -- | -- | -- | | **Stop equivalent** | -- | -- | -- | `Stop` | `Stop` | `agentStop` | `stop` | -- | -- | -- | `Stop` | `Stop` | -- | `Stop` (best-effort, unverified on agy 1.0.6) | -- | -- | -- | -- | | **Can modify args** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | No | Yes | -- | -- | -- | -- | -- | -- | | **Can modify output** | Yes | Yes | Yes | Yes | Yes | No | No | Yes (caveat) | Yes (caveat) | No | No | Yes | -- | -- | -- | -- | -- | -- | | **Can inject session context** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | -- | -- | Yes | Yes | Yes | -- | -- | -- | -- | -- | -- | | **Can block tools** | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes (throw) | Yes (throw) | Yes | Yes | Yes | -- | Bounded | Yes | -- | -- | -- | | **Config location** | `~/.claude/settings.json` | `~/.qwen/settings.json` | `~/.gemini/settings.json` | `.github/hooks/*.json` | `.github/hooks/*.json` | `~/.copilot/hooks/context-mode.json` + `~/.copilot/mcp-config.json` | `.cursor/hooks.json` or `~/.cursor/hooks.json` | `opencode.json` | `kilo.json` | `openclaw.json` | `~/.codex/hooks.json` + `~/.codex/config.toml` | `~/.kimi-code/config.toml` | `~/.gemini/antigravity/mcp_config.json` | `~/.gemini/config/mcp_config.json` + `~/.gemini/config/hooks.json` | `~/.kiro/settings/mcp.json` | `~/.config/zed/settings.json` | `~/.pi/settings.json` | `~/.omp/agent/mcp_config.json` | | **Session ID field** | `session_id` | `session_id` | `session_id` | `sessionId` (camelCase) | `sessionId` (camelCase) | `session_id` (snake_case; `sessionId` defensive fallback) | `conversation_id` | `sessionID` (camelCase) | `sessionID` (camelCase) | `pid-${ppid}` fallback | N/A | `session_id` | N/A | `conversationId` (unverified) | `pid-${ppid}` fallback | N/A | N/A | N/A | | **Project dir env** | `CLAUDE_PROJECT_DIR` | `QWEN_PROJECT_DIR` | `GEMINI_PROJECT_DIR` | `CLAUDE_PROJECT_DIR` | `CLAUDE_PROJECT_DIR` | stdin `cwd` | stdin `workspace_roots` | `ctx.directory` (plugin init) | `ctx.directory` (plugin init) | `process.cwd()` | N/A | stdin `cwd` | N/A | stdin `workspace.current_dir` (refs-backed; `workspacePaths[0]` fallback) | stdin `cwd` | N/A | N/A | `OMP_PROCESSING_AGENT_DIR` | | **MCP/tool naming** | `mcp__server__tool` | `mcp__server__tool` | `mcp__server__tool` | `f1e_` prefix | `f1e_` prefix | `mcp__server__tool` | `MCP:` in hook payloads | native `ctx_*` plugin tools | native `ctx_*` plugin tools | native `ctx_*` plugin tools | `mcp__server__tool` | `mcp__context-mode__tool` | `mcp__server__tool` | `context-mode/` | `mcp__server__tool` | `mcp__server__tool` | `mcp__server__tool` | `mcp__server__tool` | | **Hook command format** | `context-mode hook claude-code ` | `context-mode hook qwen-code ` | `context-mode hook gemini-cli ` | `context-mode hook vscode-copilot ` | `context-mode hook jetbrains-copilot ` | `context-mode hook copilot-cli ` | `context-mode hook cursor ` | TS plugin (no command) | TS plugin (no command) | TS plugin (no command) | `context-mode hook codex ` | `context-mode hook kimi ` | N/A | `context-mode hook antigravity-cli ` | `context-mode hook kiro ` | N/A | N/A | N/A | | **Hook registration** | settings.json hooks object | settings.json hooks object | settings.json hooks object | `.github/hooks/*.json` | `.github/hooks/*.json` | `~/.copilot/hooks/context-mode.json` (`version: 1`) | `hooks.json` native hook arrays | opencode.json plugin array | kilo.json plugin array | openclaw.json `plugins.entries` | `~/.codex/hooks.json` | `config.toml` hooks array | N/A | plugin root `hooks.json` (`PreToolUse`, `PostToolUse`, `Stop`; bundle mirrors `hooks/hooks.json` for agy validate/install) | Kiro CLI hooks (JSON stdin) | N/A | N/A | N/A | | **MCP server command** | `context-mode` (or plugin auto) | `context-mode` | `context-mode` | `context-mode` | `context-mode` | `context-mode` | `context-mode` | N/A (native plugin tools) | N/A (native plugin tools) | N/A (native plugin tools) | `context-mode` | `context-mode` | `context-mode` | `context-mode` | `context-mode` | `context-mode` | `context-mode` | `context-mode` | | **Plugin distribution** | Claude plugin registry | npm global | npm global | npm global | npm global | npm global | npm global | npm global | npm global | npm global | npm global | npm global | npm global | agy plugin (npm global) | npm global | npm global | npm global | npm global | | **Session dir** | `~/.claude/context-mode/sessions/` | `~/.qwen/context-mode/sessions/` | `~/.gemini/context-mode/sessions/` | `.github/context-mode/sessions/` or `~/.vscode/context-mode/sessions/` | `.github/context-mode/sessions/` | `~/.copilot/context-mode/sessions/` | `~/.cursor/context-mode/sessions/` | `~/.config/opencode/context-mode/sessions/` | `~/.config/kilo/context-mode/sessions/` | `~/.openclaw/context-mode/sessions/` | `~/.codex/context-mode/sessions/` | `~/.kimi-code/context-mode/sessions/` | `~/.gemini/context-mode/sessions/` | `~/.gemini/context-mode/sessions/` | `~/.kiro/context-mode/sessions/` | `~/.config/zed/context-mode/sessions/` | `~/.pi/context-mode/sessions/` | `~/.omp/context-mode/sessions/` | ### Legend - Yes = Fully supported - -- = Not supported - (caveat) = Supported with known issues --- ## Platform Details ### Claude Code **Status:** Fully supported (primary platform) **Hook Paradigm:** JSON stdin/stdout Claude Code is the primary platform for context-mode. All hooks communicate via JSON on stdin/stdout. The adapter reads raw JSON input, normalizes it into platform-agnostic events, and formats responses back into Claude Code's expected output format. **Hook Names:** - `PreToolUse` -- fires before a tool is executed - `PostToolUse` -- fires after a tool completes - `PreCompact` -- fires before context compaction - `SessionStart` -- fires when a session starts, resumes, or compacts - `UserPromptSubmit` -- fires when user submits a prompt - `Stop` -- fires when the assistant turn is about to end **Blocking:** `permissionDecision: "deny"` in response JSON **Arg Modification:** `updatedInput` field at top level of response **Output Modification:** `updatedMCPToolOutput` for MCP tools, `additionalContext` for appending **Session ID Extraction Priority:** 1. UUID from `transcript_path` field 2. `session_id` field 3. `CLAUDE_SESSION_ID` environment variable 4. Parent process ID fallback **Hook Commands:** ``` context-mode hook claude-code pretooluse context-mode hook claude-code posttooluse context-mode hook claude-code precompact context-mode hook claude-code sessionstart context-mode hook claude-code userpromptsubmit ``` **Known Issues:** None significant. --- ### Gemini CLI **Status:** Fully supported **Hook Paradigm:** JSON stdin/stdout Gemini CLI uses the same JSON stdin/stdout paradigm as Claude Code but with different hook names and response format. **Hook Names:** - `BeforeTool` -- equivalent to PreToolUse - `AfterTool` -- equivalent to PostToolUse - `PreCompress` -- equivalent to PreCompact (advisory only, async, cannot block) - `SessionStart` -- fires when a session starts **Blocking:** `decision: "deny"` in response (NOT `permissionDecision`) **Arg Modification:** `hookSpecificOutput.tool_input` (merged with original, not `updatedInput`) **Output Modification:** `decision: "deny"` + `reason` replaces output; `hookSpecificOutput.additionalContext` appends **Environment Variables:** - `GEMINI_PROJECT_DIR` -- primary project directory - `CLAUDE_PROJECT_DIR` -- alias (also works) **Hook Commands:** ``` context-mode hook gemini-cli beforetool context-mode hook gemini-cli aftertool context-mode hook gemini-cli precompress context-mode hook gemini-cli sessionstart ``` **Known Issues / Caveats:** - `PreCompress` is advisory only (async, cannot block) - No `decision: "ask"` support - Hooks don't fire for subagents yet --- ### OpenCode **Status:** Fully supported **Hook Paradigm:** TS Plugin OpenCode uses a TypeScript plugin paradigm instead of JSON stdin/stdout. Hooks and the 11 `ctx_*` tools are registered via the `plugin` array in `opencode.json`; no separate `mcp` block or stdio MCP child is required. **Hook Names:** - `tool.execute.before` -- equivalent to PreToolUse - `tool.execute.after` -- equivalent to PostToolUse - `experimental.session.compacting` -- equivalent to PreCompact (experimental) - `experimental.chat.system.transform` -- SessionStart-equivalent (cross-session resume injection) **Blocking:** `throw Error` in `tool.execute.before` handler **Arg Modification:** `output.args` mutation **Output Modification:** `output.output` mutation (TUI bug for bash, see issue #13575) **Session ID:** `input.sessionID` (camelCase, note the uppercase `ID`) **Project Directory:** Available via `ctx.directory` in plugin init, not via environment variable **Desktop markers:** OpenCode desktop shells also export `OPENCODE_CLIENT=desktop` and `OPENCODE_TERMINAL=1`; context-mode treats those as OpenCode identity signals when the CLI markers are absent. **Configuration:** - `opencode.json` or `.opencode/opencode.json` - Plugin registered in the `plugin` array with npm package names - `ctx_*` tools are native plugin tools, not `mcp__server__tool` calls - KiloCode uses the same plugin path via `kilo.json`; `context-mode upgrade` removes stale `mcp.context-mode` entries for both hosts while preserving other MCP servers **Cross-session resume:** When OpenCode triggers `experimental.session.compacting` (auto on context overflow OR manual `/compact`), context-mode saves a snapshot to its per-project SQLite store. The NEXT new session in the same project — typically after `Ctrl+D` then re-running `opencode`, or starting a fresh chat — claims that snapshot via `experimental.chat.system.transform` and prepends it to `system[1]` (preserves OpenCode's `[header, body]` cache fold). The current session never claims its OWN snapshot back (self-injection guard, v1.0.106). To verify the injection landed, run with `OPENCODE_DEBUG=1` and grep for `