This document provides a comprehensive comparison of all platforms supported by context-mode, including their hook paradigms, capabilities, configuration, and known limitations.
context-mode supports eight platforms across three hook paradigms:
| Paradigm | Platforms |
|---|---|
| JSON stdin/stdout | Claude Code, Gemini CLI, VS Code Copilot, Cursor, Codex CLI |
| TS Plugin | OpenCode |
| MCP-only | Antigravity, Kiro |
The MCP server layer is 100% portable and needs no adapter. Only the hook layer requires platform-specific adapters.
All platforms (except Claude Code plugin install) require a global install:
npm install -g context-modeThis puts the context-mode binary in PATH, which is required for:
- MCP server:
"command": "context-mode"(replaces ephemeralnpx -y context-mode) - Hook dispatcher:
context-mode hook <platform> <event>(replacesnode ./node_modules/...paths) - Utility commands:
context-mode doctor,context-mode upgrade - Persistent upgrades:
ctx-upgradeupdates the global binary in-place
| Feature | Claude Code | Gemini CLI | VS Code Copilot | Cursor | OpenCode | Codex CLI | Antigravity | Kiro |
|---|---|---|---|---|---|---|---|---|
| Paradigm | json-stdio | json-stdio | json-stdio | json-stdio | ts-plugin | json-stdio | mcp-only | mcp-only |
| PreToolUse equivalent | PreToolUse |
BeforeTool |
PreToolUse |
preToolUse |
tool.execute.before |
PreToolUse |
-- | -- |
| PostToolUse equivalent | PostToolUse |
AfterTool |
PostToolUse |
postToolUse |
tool.execute.after |
PostToolUse |
-- | -- |
| PreCompact equivalent | PreCompact |
PreCompress |
PreCompact |
-- | experimental.session.compacting |
-- | -- | -- |
| SessionStart | SessionStart |
SessionStart |
SessionStart |
-- (buggy in Cursor) | -- | SessionStart |
-- | -- |
| Stop equivalent | -- | -- | Stop |
stop |
-- | Stop |
-- | -- |
| Can modify args | Yes | Yes | Yes | Yes | Yes | No | -- | -- |
| Can modify output | Yes | Yes | Yes | No | Yes (caveat) | No | -- | -- |
| Can inject session context | Yes | Yes | Yes | Yes | -- | Yes | -- | -- |
| Can block tools | Yes | Yes | Yes | Yes | Yes (throw) | Yes | -- | -- |
| Config location | ~/.claude/settings.json |
~/.gemini/settings.json |
.github/hooks/*.json |
.cursor/hooks.json or ~/.cursor/hooks.json |
opencode.json |
~/.codex/hooks.json + ~/.codex/config.toml |
~/.gemini/antigravity/mcp_config.json |
~/.kiro/settings/mcp.json |
| Session ID field | session_id |
session_id |
sessionId (camelCase) |
conversation_id |
sessionID (camelCase) |
N/A | N/A | N/A |
| Project dir env | CLAUDE_PROJECT_DIR |
GEMINI_PROJECT_DIR |
CLAUDE_PROJECT_DIR |
stdin workspace_roots |
ctx.directory (plugin init) |
N/A | N/A | N/A |
| MCP tool naming | mcp__server__tool |
mcp__server__tool |
f1e_ prefix |
MCP:<tool> in hook payloads |
mcp__server__tool |
mcp__server__tool |
mcp__server__tool |
mcp__server__tool |
| Hook command format | context-mode hook claude-code <event> |
context-mode hook gemini-cli <event> |
context-mode hook vscode-copilot <event> |
context-mode hook cursor <event> |
TS plugin (no command) | context-mode hook codex <event> |
N/A | N/A |
| Hook registration | settings.json hooks object | settings.json hooks object | .github/hooks/*.json |
hooks.json native hook arrays |
opencode.json plugin array | ~/.codex/hooks.json |
N/A | N/A |
| MCP server command | context-mode (or plugin auto) |
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 |
| Session dir | ~/.claude/context-mode/sessions/ |
~/.gemini/context-mode/sessions/ |
.github/context-mode/sessions/ or ~/.vscode/context-mode/sessions/ |
~/.cursor/context-mode/sessions/ |
~/.config/opencode/context-mode/sessions/ |
~/.codex/context-mode/sessions/ |
~/.gemini/context-mode/sessions/ |
~/.kiro/context-mode/sessions/ |
- Yes = Fully supported
- -- = Not supported
- (caveat) = Supported with known issues
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 executedPostToolUse-- fires after a tool completesPreCompact-- fires before context compactionSessionStart-- fires when a session starts, resumes, or compactsUserPromptSubmit-- fires when user submits a prompt
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:
- UUID from
transcript_pathfield session_idfieldCLAUDE_SESSION_IDenvironment variable- 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.
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 PreToolUseAfterTool-- equivalent to PostToolUsePreCompress-- 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 directoryCLAUDE_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:
PreCompressis advisory only (async, cannot block)- No
decision: "ask"support - Hooks don't fire for subagents yet
Status: Partially supported
Hook Paradigm: TS Plugin
OpenCode uses a TypeScript plugin paradigm instead of JSON stdin/stdout. Hooks are registered via the plugin array in opencode.json.
Hook Names:
tool.execute.before-- equivalent to PreToolUsetool.execute.after-- equivalent to PostToolUseexperimental.session.compacting-- equivalent to PreCompact (experimental)
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
Configuration:
opencode.jsonor.opencode/opencode.json- Plugin registered in the
pluginarray with npm package names
Known Issues / Caveats:
- SessionStart is broken (issue #14808, no hook issue #5409)
- Output modification has TUI rendering bug for bash tool (issue #13575)
experimental.session.compactingis marked experimental and may change- No
canInjectSessionContextcapability
Status: Supported (MCP active, hooks ready — waiting for upstream dispatch)
Hook Paradigm: JSON stdin/stdout
Codex CLI's Rust backend (codex-rs) includes a full hook system with 5 events, using the same JSON stdin/stdout wire protocol as Claude Code. Hooks are configured via hooks.json.
Hook Names:
PreToolUse-- fires before a tool is executedPostToolUse-- fires after a tool completesSessionStart-- fires when a session starts, resumes, or clearsUserPromptSubmit-- fires when user submits a promptStop-- fires when agent turn ends (can continue with followup)
Blocking: permissionDecision: "deny" in hookSpecificOutput, or exit code 2
Arg Modification: NOT supported (updatedInput returns error)
Output Modification: NOT supported (updatedMCPToolOutput returns error)
Context Injection: additionalContext in hookSpecificOutput (PostToolUse, SessionStart only). PreToolUse does NOT support additionalContext — the codex formatter handles this automatically (deny works, context/modify/ask responses are dropped).
Configuration:
- Hook config:
~/.codex/hooks.json(JSON format, same structure as Claude Code) - MCP config:
~/.codex/config.toml(TOML format,[mcp_servers]section)
Hook Commands:
context-mode hook codex pretooluse
context-mode hook codex posttooluse
context-mode hook codex sessionstart
Known Issues / Caveats:
- Hook dispatch is NOT yet active in Codex CLI sessions.
codex_hooksfeature flag isStage::UnderDevelopment— the flag is accepted but hooks don't fire during real sessions (verified v0.118.0 by beta tester). Our hook scripts are ready and will work once Codex enables dispatch. Track: openai/codex#16685. - MCP exec-mode regression (v0.118.0): All MCP tool calls are cancelled in
codex execwith "user cancelled MCP tool call". Caused bytool_call_mcp_elicitationfeature flag going stable — adds approval prompt that exec-mode can't handle. Workaround: pin to Codex ≤0.116.0 for exec-mode MCP. Confirmed by upstream maintainer @etraut-openai. Track: openai/codex#16685. - PreToolUse
additionalContextis unsupported — context injection works via PostToolUse and SessionStart instead. The codex formatter handles this automatically (deny works, context is dropped). Source:codex-rs/hooks/src/engine/output_parser.rs:267. tool_nameis always "Bash" (Codex only has one tool type)- updatedInput and updatedMCPToolOutput are in the schema but NOT implemented
- Default hook timeout: 600 seconds
Status: MCP-only (no hooks)
Hook Paradigm: MCP-only
Google Antigravity is an AI-powered IDE by Google/DeepMind. It shares the ~/.gemini/ directory structure with Gemini CLI but uses a separate config path for MCP servers. Antigravity does not expose a public hook API — only MCP integration is available.
Configuration:
~/.gemini/antigravity/mcp_config.json(JSON format)- MCP servers configured in
mcpServersobject
Detection:
- Auto-detected via MCP protocol handshake (
clientInfo.name: "antigravity-client") - Fallback:
CONTEXT_MODE_PLATFORM=antigravityenvironment variable override
Routing Instructions:
GEMINI.mdauto-written at project root on first MCP server startup- Antigravity reads
GEMINI.mdnatively (same filename as Gemini CLI, different content — no hook references)
Capabilities:
- PreToolUse: --
- PostToolUse: --
- PreCompact: --
- SessionStart: --
- Can modify args: --
- Can modify output: --
- Can inject session context: --
Known Issues / Caveats:
- No hook support — only routing instruction files for enforcement (~60% compliance)
- Shares
~/.gemini/directory with Gemini CLI — session DB uses project hash to prevent collision - No verified Antigravity-specific environment variables exist
Sources:
- Config path: Gemini CLI Issue #16058
- MCP support: Antigravity MCP docs
- clientInfo: Apify MCP Client Capabilities Registry
Status: MCP-only (hooks planned for Phase 2)
Hook Paradigm: MCP-only
Kiro is an AWS agentic IDE and CLI. It supports MCP servers via ~/.kiro/settings/mcp.json using the standard mcpServers JSON format. Hook support for Kiro CLI (JSON stdin + exit code 2 blocking, preToolUse/postToolUse) is verified in the Kiro CLI docs but not yet implemented in context-mode — planned for Phase 2.
Detection:
- Auto-detected via MCP protocol handshake (
clientInfo.name: "Kiro CLI")
Configuration:
- Global:
~/.kiro/settings/mcp.json(JSON format, standardmcpServersobject) - Project:
.kiro/settings/mcp.json
Routing Instructions:
KIRO.mdwritten at project root on first MCP server startup
Hook System (Phase 2 — not yet implemented):
- Kiro CLI supports
preToolUse/postToolUsehooks via JSON stdin - Blocking: exit code 2 (similar to Gemini CLI pattern)
- Hook format verified in Kiro CLI docs but context-mode adapter is not yet built
Built-in Tools:
fs_read/read,fs_write/write,execute_bash/shell,use_aws/aws
Capabilities:
- PreToolUse: --
- PostToolUse: --
- PreCompact: --
- SessionStart: --
- Can modify args: --
- Can modify output: --
- Can inject session context: --
Known Issues / Caveats:
- Hook adapter not yet implemented — Phase 2 work item
- Kiro IDE hooks use a UI-based "Run Command" shell action; stdin format unverified
Sources:
- clientInfo.name: Kiro GitHub Issue #5205
- MCP config: Kiro MCP Configuration docs
- CLI hooks: Kiro CLI Hooks docs
Status: Fully supported (preview)
Hook Paradigm: JSON stdin/stdout
VS Code Copilot uses the same JSON stdin/stdout paradigm as Claude Code with PascalCase hook names. It also provides unique hooks for subagent lifecycle.
Hook Names:
PreToolUse-- fires before a tool is executedPostToolUse-- fires after a tool completesPreCompact-- fires before context compactionSessionStart-- fires when a session startsStop-- fires when agent stops (unique to VS Code)SubagentStart-- fires when a subagent starts (unique to VS Code)SubagentStop-- fires when a subagent stops (unique to VS Code)
Blocking: permissionDecision: "deny" (same as Claude Code)
Arg Modification: updatedInput inside hookSpecificOutput wrapper (NOT flat like Claude Code)
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"updatedInput": { ... }
}
}Output Modification: additionalContext inside hookSpecificOutput, or decision: "block" + reason
MCP Tool Naming: Uses f1e_ prefix (not mcp__server__tool)
Session ID: sessionId (camelCase, not session_id)
Configuration:
- Primary:
.github/hooks/*.json - Also reads:
.claude/settings.json - MCP config:
.vscode/mcp.json
Environment Detection:
VSCODE_PIDenvironment variableTERM_PROGRAM=vscode
Hook Commands:
context-mode hook vscode-copilot pretooluse
context-mode hook vscode-copilot posttooluse
context-mode hook vscode-copilot precompact
context-mode hook vscode-copilot sessionstart
Known Issues / Caveats:
- Preview status -- API may change without notice
- Matchers are parsed but IGNORED (all hooks fire on all tools)
- Tool input property names use camelCase (
filePathnotfile_path) - Response must be wrapped in
hookSpecificOutputwithhookEventName
Status: Supported (native hooks, v1 scope)
Hook Paradigm: JSON stdin/stdout
Cursor uses native lower-camel hook names and flat hook entries in .cursor/hooks.json or ~/.cursor/hooks.json. context-mode treats Cursor as a first-class adapter and does not rely on Claude-compat wrappers for official support.
Hook Names:
preToolUse-- fires before a tool is executedpostToolUse-- fires after a tool completesstop-- fires when agent turn ends (can send followup_message to continue loop)afterAgentResponse-- fires after assistant response (fire-and-forget, receives full response text)sessionStart-- documented but currently rejected by Cursor's validator (forum report)
Blocking: { "permission": "deny", "user_message": "..." }
Arg Modification: not natively supported (Cursor does not have updated_input)
Output Modification: not supported in v1
Session Context Injection: { "additional_context": "..." }
Session ID Extraction Priority:
conversation_id(stdin JSON)CURSOR_TRACE_IDenvironment variable- Parent process ID fallback
Platform Detection Env Vars:
CURSOR_TRACE_ID(MCP server context)CURSOR_CLI(integrated terminal context)~/.cursor/directory fallback (medium confidence)
Configuration:
- Project:
.cursor/hooks.json - User:
~/.cursor/hooks.json - MCP config:
.cursor/mcp.jsonor~/.cursor/mcp.json
Hook Commands:
context-mode hook cursor pretooluse
context-mode hook cursor posttooluse
context-mode hook cursor stop
Known Issues / Caveats:
preCompactis intentionally not shipped in v1stophook receives:conversation_id,status,loop_count,transcript_path; returnsfollowup_messageto continueafterAgentResponseis fire-and-forget (receivestext, no return value expected)- Hook payloads name MCP tools as
MCP:<tool>and need adapter normalization - Claude-compatible Cursor behavior exists, but native Cursor config is the supported path
additional_contextin postToolUse and sessionStart hooks is accepted but NOT surfaced to the model (Cursor upstream bug — forum #155689, forum #156157). Routing enforcement relies on.mdcrules file and MCP tool descriptions instead.
| Capability | Claude Code | Gemini CLI | VS Code Copilot | Cursor | OpenCode | Codex CLI | Antigravity | Kiro |
|---|---|---|---|---|---|---|---|---|
| PreToolUse | Yes | Yes | Yes | Yes | Yes | Yes*** | -- | -- |
| PostToolUse | Yes | Yes | Yes | Yes | Yes | Yes | -- | -- |
| PreCompact | Yes | Yes | Yes | -- | Yes* | -- | -- | -- |
| SessionStart | Yes | Yes | Yes | Yes | -- | Yes | -- | -- |
| Stop | -- | -- | Yes | Yes | -- | Yes | -- | -- |
| Modify Args | Yes | Yes | Yes | Yes | Yes | -- | -- | -- |
| Modify Output | Yes | Yes | Yes | No | Yes** | -- | -- | -- |
| Inject Context | Yes | Yes | Yes | Yes | -- | Yes | -- | -- |
| Block Tools | Yes | Yes | Yes | Yes | Yes | Yes | -- | -- |
| MCP Support | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes |
* OpenCode experimental.session.compacting is experimental
** OpenCode has a TUI rendering bug for bash tool output (#13575)
*** Codex CLI PreToolUse supports deny only (no additionalContext); context injection works via PostToolUse and SessionStart
| Platform | Response Format |
|---|---|
| Claude Code | { "permissionDecision": "deny", "reason": "..." } |
| Gemini CLI | { "decision": "deny", "reason": "..." } |
| VS Code Copilot | { "permissionDecision": "deny", "reason": "..." } |
| Cursor | { "permission": "deny", "user_message": "..." } |
| OpenCode | throw new Error("...") |
| Codex CLI | { "hookSpecificOutput": { "permissionDecision": "deny" } } or exit code 2 |
| Platform | Response Format |
|---|---|
| Claude Code | { "updatedInput": { ... } } |
| Gemini CLI | { "hookSpecificOutput": { "tool_input": { ... } } } |
| VS Code Copilot | { "hookSpecificOutput": { "hookEventName": "PreToolUse", "updatedInput": { ... } } } |
| Cursor | { "updated_input": { ... } } |
| OpenCode | { "args": { ... } } (mutation) |
| Codex CLI | N/A (updatedInput in schema but not implemented) |
| Platform | Response Format |
|---|---|
| Claude Code | { "additionalContext": "..." } |
| Gemini CLI | { "hookSpecificOutput": { "additionalContext": "..." } } |
| VS Code Copilot | { "hookSpecificOutput": { "hookEventName": "PostToolUse", "additionalContext": "..." } } |
| Cursor | { "additional_context": "..." } |
| OpenCode | { "additionalContext": "..." } |
| Codex CLI | { "hookSpecificOutput": { "additionalContext": "..." } } |
All hook-based platforms use the CLI dispatcher pattern instead of direct node paths:
context-mode hook <platform> <event>
The dispatcher resolves the hook script relative to the installed package and dynamically imports it. Stdin/stdout flow through naturally since it runs in the same process.
Advantages over node ./node_modules/... paths:
- Works from any directory (no per-project
npm installneeded) - Single global install serves all projects
context-mode upgradeupdates hooks in-place- Short, portable command strings in settings files
Supported dispatches:
| Platform | Events |
|---|---|
claude-code |
pretooluse, posttooluse, precompact, sessionstart, userpromptsubmit |
gemini-cli |
beforetool, aftertool, precompress, sessionstart |
vscode-copilot |
pretooluse, posttooluse, precompact, sessionstart |
cursor |
pretooluse, posttooluse, stop |
codex |
pretooluse, posttooluse, sessionstart |
† Codex hook dispatches are ready but Codex CLI doesn't fire hooks yet (Stage::UnderDevelopment).
OpenCode uses a TS plugin paradigm (no command dispatcher). Antigravity and Kiro have no hook support.
context-mode automatically selects the best SQLite backend at runtime based on the environment:
| Priority | Condition | Backend | Why |
|---|---|---|---|
| 1 | Bun runtime | bun:sqlite |
Built-in, no native addon |
| 2 | Linux + Node.js >= 22.13 | node:sqlite |
Built-in, avoids SIGSEGV from V8 madvise bug |
| 3 | All other environments | better-sqlite3 |
Mature native addon, prebuilt binaries |
Why node:sqlite on Linux? Node.js's V8 garbage collector can call madvise(MADV_DONTNEED) on memory ranges that overlap better-sqlite3's native addon .got.plt section, corrupting resolved symbol addresses and causing sporadic SIGSEGV crashes (1-4/hour on Node v22-v24). node:sqlite is compiled into the Node.js binary itself — no separate .node file, no dlopen(), no .got.plt to corrupt.
Fallback: If node:sqlite is unavailable (Node < 22.13), context-mode silently falls back to better-sqlite3. No user configuration needed.
Override: Not currently supported — backend selection is automatic. If you need to force a specific backend, open an issue.
All platforms support utility commands via MCP meta-tools:
| Command | What it does |
|---|---|
ctx stats |
Show context savings, call counts, and session statistics |
ctx doctor |
Diagnose installation: runtimes, hooks, FTS5, versions |
ctx upgrade |
Update from GitHub, rebuild, reconfigure hooks |
ctx purge |
Permanently deletes all indexed content from the knowledge base |
How they work: The MCP server exposes stats, doctor, upgrade, and purge tools. The <ctx_commands> section in routing instructions (CLAUDE.md, GEMINI.md, AGENTS.md, copilot-instructions.md) maps natural language triggers to MCP tool calls. The doctor and upgrade tools return shell commands that the LLM executes and formats as a checklist. The purge tool permanently deletes all indexed content from the knowledge base and is the sole reset mechanism.