Update (2026-09-19): a working Grok bridge, tested live, is in this comment. It includes the full source, the real Grok payload keys, and a hook log. Fix checklist:
Summary
Grok Build CLI (xAI's grok, v1.0.34) already picks up the RuvNet Brain Claude Code plugin, because it reads ~/.claude/plugins/installed_plugins.json. I tested it live:
- ✅
search_ruvnet works in Grok. It's called as ruvnet-brain__search_ruvnet and returns real cited source.
- ✅ All 9 skills load (
/rvbc, /brain-build, /brain-score, …).
- ❌ None of the lifecycle hooks run.
grok inspect finds hooks/hooks.json, but /hooks-list in a live session doesn't show any RuvNet hooks.
- ⚠️ Even once they load, two contract gaps would bite. Grok drops
additionalContext from UserPromptSubmit and SessionStart, and it sends hook input with camelCase keys.
So Grok users get the tool and the skills, but not the proactive grounding. A small grok host adapter would probably close most of the gap. Details below.
Environment
- macOS (Darwin 27), Node on PATH
- ruvnet-brain 4.3.26, installed with
npx ruvnet-brain for Claude Code and Codex. The installer printed "Grok was not wired".
- Grok Build
grok 1.0.34 (3736acbc8658) [stable]
Live test results in Grok
1. MCP search: works
Prompt: Call the ruvnet-brain MCP tool search_ruvnet with query "RuVector RVF file format" and k=3…
Tool name: ruvnet-brain__search_ruvnet
Succeeded: yes
Source paths:
1. ruvector/crates/rvf/rvf-wire/Cargo.toml
2. ruvector/npm/packages/rvf/src/index.ts
3. ruvector/crates/rvf/rvf-manifest/Cargo.toml
2. Hooks: discovered but not loaded
grok inspect --json lists the plugin with "hooks": true and a hook entry pointing at …/ruvnet-brain/4.3.26/hooks/hooks.json. But /hooks-list in the same session shows only my own 4 statusline hooks:
Loaded hooks (4):
global/statusline-compact:pre_compact[0] ... ~/.grok/statusline/compact-hook.zsh
global/settings:pre_compact[0] ... ~/.claude/statusline/compact-hook.zsh
global/statusline-compact:post_compact[0] ... ~/.grok/statusline/compact-hook.zsh
global/settings:post_compact[0] ... ~/.claude/statusline/compact-hook.zsh
Grok does load hooks from ~/.claude/settings.json (the global/settings rows), and [compat.claude] hooks is on. So Claude hook compat isn't disabled. It's specifically the plugin's hooks.json that isn't being activated.
Likely cause: grok plugin list prints "No plugins installed". Grok only discovered RuvNet as a Claude-compat plugin; it isn't a native Grok install. Grok's plugin docs say "Enabled plugins require trust to load skills, commands, hooks, MCP servers", and only plugins under ~/.grok/plugins/ are trusted automatically. In practice the compat plugin's skills and MCP load but its hooks don't. grok plugin validate <plugin dir> reports "Plugin manifest is valid", so the manifest isn't the problem.
What works around it: hooks placed in ~/.grok/hooks/*.json are always trusted. So the installer could write a ~/.grok/hooks/ruvnet-brain.json that points at a stable grok-hook.mjs wrapper, the same way Codex uses ~/.cache/ruvnet-brain/codex-hook.mjs. That wrapper is also the natural place to handle the key-name differences below.
Hook contract differences to plan for (from ~/.grok/docs/user-guide/10-hooks.md)
-
UserPromptSubmit can't inject context. The docs say: "an allowing hook's stdout / additionalContext is discarded rather than added as context." So ground-ruvnet's "ground before you assert" directive never reaches Grok's model. It can still block, with exit 2 or {"decision":"block"}.
-
SessionStart is passive. Its output doesn't reach the model, so the "RuvNet Brain vX active / grounding PROVEN" banner is lost.
-
Hook input uses camelCase keys. Grok sends toolName, toolInput, stopHookActive, lastAssistantMessage. Only hook_event_name gets a snake_case copy. These scripts read the Claude spelling:
scripts/decision-gate.mjs:222-223 reads tool_name / tool_input
scripts/continuation-gate.mjs:265 reads stop_hook_active
scripts/grounding-turn-gate.mjs:116 reads stop_hook_active
The stop_hook_active ones matter most. Under Grok, that loop guard would never trip, and only Grok's built-in cap of 8 continuations per turn would stop the gate. Normalizing keys in hook-shim.mjs (camelCase → snake_case) would fix all three in one place.
-
Extra Stop events at session end. Grok fires Stop again with reason: "channel_closed" or "shutdown". Counters and gates should act only when reason == "end_turn".
-
What already matches: Stop decision:block / additionalContext (keeps the agent working), PreToolUse permissionDecision / deny, and PostToolUse additionalContext. CLAUDE_PLUGIN_ROOT / CLAUDE_PLUGIN_DATA / CLAUDE_PROJECT_DIR are all set. Grok's MCP tool names (server__tool) already match your ^(?:.*__)?search_ruvnet$ matcher, and Grok maps Claude tool names in matchers (e.g. Edit also matches search_replace).
Suggested changes
- Add a
host-adapters/grok.json that detects ~/.grok/bin/grok, so the installer and --doctor report "Grok: search + skills via Claude-plugin compat; hooks " instead of "not wired". It shouldn't add a second [mcp_servers.ruvnet-brain] to ~/.grok/config.toml, since Grok already loads the plugin's .mcp.json.
- Host detection.
session-start-core.mjs:136 branches on RUVNET_HOOK_HOST === 'codex'. Grok sets GROK_AGENT (plus GROK_PLUGIN_ROOT and GROK_WORKSPACE_ROOT) in the hook environment, so the shim could set RUVNET_HOOK_HOST=grok from those.
- Normalize hook input keys in
hook-shim.mjs, per item 3 above.
- Grounding fallback for Grok. Since prompt-time injection isn't possible, lean on the Stop
grounding-turn-gate, which Grok honors, and on the ruvnet-brain skill body. Or suggest adding a one-line rule to ~/.grok/AGENTS.md.
- Docs.
explainer/llms-full.txt lists Claude Code and Codex as the hosts. A line on Grok support and its limits would help.
Unrelated, but hit on the same machine: embedder download
On first install, the ONNX weights for Xenova/bge-base-en-v1.5 and the ms-marco-MiniLM-L-6-v2 reranker (onnx/model_quantized.onnx) never finished downloading. Only the tokenizer and config files landed. On this connection, the huggingface.co redirect alone took about 3.7s, close to the worker's 5s reachability timeout. search_ruvnet then failed everywhere with "cannot reach the embedding-model host … This environment looks network-restricted (sandbox/container?)", which was misleading because the network was fine.
Downloading the two files by hand into the pinned revision folders fixed it (105 MB + 22 MB, about 2 minutes on the same network). --doctor then said "Grounding PROVEN" in 16.8s. A longer timeout or a resumable download at install time would avoid this. --doctor still shows "Codex MCP is registered but degraded" with the old warmup error, which looks like a cached status from before the fix.
Not verified
- Why the plugin's hooks don't activate in Grok (trust, a compat gap, or a Grok bug).
- Whether Grok also sends snake_case copies of
tool_name and the other keys. The docs only mention hook_event_name.
- Whether
decision-gate's matcher catches Grok's file-write tools.
Happy to test a branch on Grok if that helps. Thanks for building this, Stu!
Summary
Grok Build CLI (xAI's
grok, v1.0.34) already picks up the RuvNet Brain Claude Code plugin, because it reads~/.claude/plugins/installed_plugins.json. I tested it live:search_ruvnetworks in Grok. It's called asruvnet-brain__search_ruvnetand returns real cited source./rvbc,/brain-build,/brain-score, …).grok inspectfindshooks/hooks.json, but/hooks-listin a live session doesn't show any RuvNet hooks.additionalContextfrom UserPromptSubmit and SessionStart, and it sends hook input with camelCase keys.So Grok users get the tool and the skills, but not the proactive grounding. A small
grokhost adapter would probably close most of the gap. Details below.Environment
npx ruvnet-brainfor Claude Code and Codex. The installer printed "Grok was not wired".grok 1.0.34 (3736acbc8658) [stable]Live test results in Grok
1. MCP search: works
Prompt: Call the ruvnet-brain MCP tool search_ruvnet with query "RuVector RVF file format" and k=3…
2. Hooks: discovered but not loaded
grok inspect --jsonlists the plugin with"hooks": trueand a hook entry pointing at…/ruvnet-brain/4.3.26/hooks/hooks.json. But/hooks-listin the same session shows only my own 4 statusline hooks:Grok does load hooks from
~/.claude/settings.json(theglobal/settingsrows), and[compat.claude] hooksis on. So Claude hook compat isn't disabled. It's specifically the plugin'shooks.jsonthat isn't being activated.Likely cause:
grok plugin listprints "No plugins installed". Grok only discovered RuvNet as a Claude-compat plugin; it isn't a native Grok install. Grok's plugin docs say "Enabled plugins require trust to load skills, commands, hooks, MCP servers", and only plugins under~/.grok/plugins/are trusted automatically. In practice the compat plugin's skills and MCP load but its hooks don't.grok plugin validate <plugin dir>reports "Plugin manifest is valid", so the manifest isn't the problem.What works around it: hooks placed in
~/.grok/hooks/*.jsonare always trusted. So the installer could write a~/.grok/hooks/ruvnet-brain.jsonthat points at a stablegrok-hook.mjswrapper, the same way Codex uses~/.cache/ruvnet-brain/codex-hook.mjs. That wrapper is also the natural place to handle the key-name differences below.Hook contract differences to plan for (from
~/.grok/docs/user-guide/10-hooks.md)UserPromptSubmit can't inject context. The docs say: "an allowing hook's stdout /
additionalContextis discarded rather than added as context." Soground-ruvnet's "ground before you assert" directive never reaches Grok's model. It can still block, with exit 2 or{"decision":"block"}.SessionStart is passive. Its output doesn't reach the model, so the "RuvNet Brain vX active / grounding PROVEN" banner is lost.
Hook input uses camelCase keys. Grok sends
toolName,toolInput,stopHookActive,lastAssistantMessage. Onlyhook_event_namegets a snake_case copy. These scripts read the Claude spelling:scripts/decision-gate.mjs:222-223readstool_name/tool_inputscripts/continuation-gate.mjs:265readsstop_hook_activescripts/grounding-turn-gate.mjs:116readsstop_hook_activeThe
stop_hook_activeones matter most. Under Grok, that loop guard would never trip, and only Grok's built-in cap of 8 continuations per turn would stop the gate. Normalizing keys inhook-shim.mjs(camelCase → snake_case) would fix all three in one place.Extra Stop events at session end. Grok fires Stop again with
reason: "channel_closed"or"shutdown". Counters and gates should act only whenreason == "end_turn".What already matches: Stop
decision:block/additionalContext(keeps the agent working), PreToolUsepermissionDecision/deny, and PostToolUseadditionalContext.CLAUDE_PLUGIN_ROOT/CLAUDE_PLUGIN_DATA/CLAUDE_PROJECT_DIRare all set. Grok's MCP tool names (server__tool) already match your^(?:.*__)?search_ruvnet$matcher, and Grok maps Claude tool names in matchers (e.g.Editalso matchessearch_replace).Suggested changes
host-adapters/grok.jsonthat detects~/.grok/bin/grok, so the installer and--doctorreport "Grok: search + skills via Claude-plugin compat; hooks " instead of "not wired". It shouldn't add a second[mcp_servers.ruvnet-brain]to~/.grok/config.toml, since Grok already loads the plugin's.mcp.json.session-start-core.mjs:136branches onRUVNET_HOOK_HOST === 'codex'. Grok setsGROK_AGENT(plusGROK_PLUGIN_ROOTandGROK_WORKSPACE_ROOT) in the hook environment, so the shim could setRUVNET_HOOK_HOST=grokfrom those.hook-shim.mjs, per item 3 above.grounding-turn-gate, which Grok honors, and on theruvnet-brainskill body. Or suggest adding a one-line rule to~/.grok/AGENTS.md.explainer/llms-full.txtlists Claude Code and Codex as the hosts. A line on Grok support and its limits would help.Unrelated, but hit on the same machine: embedder download
On first install, the ONNX weights for
Xenova/bge-base-en-v1.5and thems-marco-MiniLM-L-6-v2reranker (onnx/model_quantized.onnx) never finished downloading. Only the tokenizer and config files landed. On this connection, the huggingface.co redirect alone took about 3.7s, close to the worker's 5s reachability timeout.search_ruvnetthen failed everywhere with "cannot reach the embedding-model host … This environment looks network-restricted (sandbox/container?)", which was misleading because the network was fine.Downloading the two files by hand into the pinned revision folders fixed it (105 MB + 22 MB, about 2 minutes on the same network).
--doctorthen said "Grounding PROVEN" in 16.8s. A longer timeout or a resumable download at install time would avoid this.--doctorstill shows "Codex MCP is registered but degraded" with the old warmup error, which looks like a cached status from before the fix.Not verified
tool_nameand the other keys. The docs only mentionhook_event_name.decision-gate's matcher catches Grok's file-write tools.Happy to test a branch on Grok if that helps. Thanks for building this, Stu!