Repository navigation
feat(agent-guard): add Grok PreToolUse integration - #1516
Conversation
|
Hi @potiuk, I’ve opened the next piece of #1416 for the Grok integration. This PR adds native Grok I’ve intentionally kept full Grok Would appreciate your review when you get a chance. |
potiuk
left a comment
There was a problem hiding this comment.
The adapter is tidy and mirrors the Gemini / Kiro shape, but every assumption it makes about Grok's hook API — camelCase toolName / toolInput, the run_terminal_command tool name, {"decision": …} plus exit 2 — is unsourced, and any mismatch fails open silently, so a wrong guess means the guard never fires. Please cite Grok's hook documentation and test against a captured real payload before this can count as a guard (inline on __init__.py:946).
Smaller observations
tools/spec-loop/specs/agent-isolation-sandbox.mdlists the agent-guard harness adapters (Claude Code, OpenCode,--gemini) and isn't updated for--grok;AGENTS.mdasks that "the affected specs reflect what actually shipped".- The install / upgrade / uninstall steps cover only the snapshot path (
$GROK_WORKSPACE_ROOT/.apache-magpie/tools/...). Marketplace installs — the preferred method — have no.apache-magpie/snapshot; please say how they get the hook. - If
GROK_WORKSPACE_ROOTis unset,python3 "<missing>/…"exits 2 — please say what Grok does with that (block every shell call, or pass silently), once its exit-code semantics are sourced. FRAMEWORK_FINGERPRINTinisolated_fingerprint.pyis also changed by #1507; whichever lands second needs to regenerate it.- The failing
prekcheck is auvsegfault in thesymlink-lintruff step, unrelated to this diff; a re-run should clear it.
This review was drafted by an AI-assisted tool and
confirmed by an Apache Magpie maintainer. After you've
addressed the points above and pushed an update, an Apache Magpie
maintainer — a real person — will take the next look
at the PR. The findings cite the project's review criteria;
if you think one of them is mis-applied, please reply on the
PR and a maintainer will weigh in.More on how Apache Magpie handles maintainer review:
CONTRIBUTING.md.
b501aeb to
59eab13
Compare
|
@potiuk Thanks for the review — I’ve pushed the follow-up changes in The Grok guard is now based on the documented and observed hook contract rather than assumptions:
I also tested it live in Grok:
The full local |
potiuk
left a comment
There was a problem hiding this comment.
Thanks, @KatalKavya96. This is the follow-up I asked for: the contract is now sourced from xAI's hooks docs, the fixture is a verbatim capture from Grok Build 1.0.46, and the deny shape ({"decision": "deny", ...} plus exit 2) matches the documented contract. The project-hook path looks right.
Two claims in docs/adapters/grok.md are still unverified, and both are about the guard failing silently, which is the failure this adapter has to rule out.
Major — the marketplace path probably never reaches grok_main()
The doc says the existing magpie-agent-guard plugin works under Grok as-is, because the no-argument dispatcher sees GROK_HOOK_EVENT. But that plugin's hook command is python3 "${CLAUDE_PLUGIN_ROOT}/tools/agent-guard/src/agent_guard/__init__.py" (plugins/magpie-agent-guard/.claude-plugin/plugin.json), and xAI's plugin docs only say plugin hooks receive GROK_PLUGIN_ROOT and GROK_PLUGIN_DATA. If Grok does not also set CLAUDE_PLUGIN_ROOT, the path becomes /tools/agent-guard/..., python3 exits 2 with "can't open file", and the guard never runs. Please either verify the marketplace install live on Grok 1.0.46 (a known denial, not just an allow) and say so in the doc, or make the plugin command fall back, for example ${CLAUDE_PLUGIN_ROOT:-$GROK_PLUGIN_ROOT}.
Major — "a broken launcher fails open" needs evidence
python3 exits 2 for a missing script, and xAI's hooks page says "exit code 2 denies". So a broken launcher (unset GROK_WORKSPACE_ROOT, a moved snapshot, the plugin-root case above) may not fail open as the doc states. It may block every shell command instead. The same page also says "only an explicit deny blocks". Either way, please check what 1.0.46 actually does with a bare exit 2 and no JSON, and document the observed behaviour instead of the assumed one. (This was the open question from my last review.)
Smaller observations
- Grok also reads enabled Claude Code plugins, and this repo's
.claude/settings.jsonenablesmagpie-agent-guard. So in this checkout, Grok runs the guard twice (plugin plus.grok/hooks/magpie-agent-guard.json), which contradicts the "exactly one hook" check in Verify. Please say which one this repo should keep, or document the overlap. - The branch conflicts with
maininisolated_fingerprint.py(the #1507 overlap I mentioned) and needs a rebase, then a regeneratedFRAMEWORK_FINGERPRINT.
This review was drafted by an AI-assisted tool and
confirmed by an Apache Magpie maintainer. After you've
addressed the points above and pushed an update, an Apache Magpie
maintainer — a real person — will take the next look
at the PR. The findings cite the project's review criteria;
if you think one of them is mis-applied, please reply on the
PR and a maintainer will weigh in.More on how Apache Magpie handles maintainer review:
Contributing guide.
59eab13 to
e3b07f7
Compare
|
@potiuk Addressed the remaining review concerns. For the marketplace/plugin path, magpie-agent-guard now registers through hooks/hooks.json and packages the guard runtime as real files inside the plugin instead of relying on the escaping symlink. I verified this on Grok Build 1.0.50: the plugin reports provides.hooks: true, the installed runtime resolves correctly, /hooks shows the active hook, and git commit --no-verify --dry-run is blocked by the actual Magpie agent-guard[no-verify] policy. I also rechecked the failure semantics. A bare PreToolUse hook that exits 2 with no JSON blocks the shell tool call on Grok 1.0.50, and a missing Python hook target that exits 2 is blocked as well. The docs now distinguish that from malformed/unrelated input handled inside grok_main(), which deliberately returns 0 and remains fail-open. I kept the original payload provenance separate: the captured run_terminal_command payload is from Grok Build 1.0.46, while marketplace loading, packaged-runtime execution, real policy denial, and exit-2 behavior were verified on 1.0.50. Full prek run --all-files is green after the changes. |
potiuk
left a comment
There was a problem hiding this comment.
Thanks, @KatalKavya96 — this round closes the two major points. The plugin hook now falls back to GROK_PLUGIN_ROOT, the marketplace path is verified with a real agent-guard[no-verify] denial on Grok 1.0.50, and the exit-2 behaviour is now observed and documented rather than assumed: a broken launcher blocks, while malformed input stays fail-open inside grok_main(). Packaging the guard as real files, byte-checked against tools/agent-guard by check-family-plugins.py, is a sound way around the escaping symlink.
Two things are left before this can be approved.
- Two Magpie hooks in this repository. This repo enables
magpie-agent-guardin.claude/settings.json, which Grok also reads, and also commits.grok/hooks/magpie-agent-guard.json. So a Grok session here runs the guard twice — the overlap your own Verify step tells operators to warn about. Please either drop one of the two for this repo, or document why this repo keeps both. (The open thread ondocs/adapters/grok.md.) - Claude Code is now on the new hook too. The plugin's hook moved from the manifest to
hooks/hooks.json, and its command now goes through${GROK_PLUGIN_ROOT:-${CLAUDE_PLUGIN_ROOT}}. That changes the path every Claude Code user takes. Please confirm one live denial on Claude Code with the rebuilt plugin, as you did for Grok.
Not blocking:
- Adapter selection by environment variable. With no flag,
cli()routes togrok_main()wheneverGROK_HOOK_EVENTis set, and the plugin's hook command prefersGROK_PLUGIN_ROOT. If either variable is ever inherited into a Claude Code hook process, the guard either silently allows everything (grok_main()ignores Claude'sBashpayload) or blocks every call (an unreachable path exits 2). Selecting the adapter from the payload's shape (toolNamein Grok's event,tool_name: "Bash"in Claude's) would remove that dependency. - Nits in
docs/adapters/grok.md: "supported in this PR" won't read right once merged, and the SPDX comment appears twice.
This review was drafted by an AI-assisted tool and
confirmed by an Apache Magpie maintainer. After you've
addressed the points above and pushed an update, an Apache Magpie
maintainer — a real person — will take the next look
at the PR. The findings cite the project's review criteria;
if you think one of them is mis-applied, please reply on the
PR and a maintainer will weigh in.More on how Apache Magpie handles maintainer review:
Contributing guide.
a26a3f9 to
5bff83a
Compare
|
@potiuk Addressed the remaining review items in 5bff83a.
Full |
Add a native Grok hook adapter that translates PreToolUse events into the shared agent-guard dispatcher. Wire the project hook and snapshot setup lifecycle without modifying Grok trust state or unrelated configuration. Register Grok in harness metadata and vendor-neutrality reporting, with end-to-end coverage for the committed hook. Refs apache#1416
… main main changed tools/agent-guard (the mention guard's target-repository parsing), so the copy the magpie-agent-guard plugin ships was out of sync. Regenerated with `check-family-plugins.py --fix`; the copy is byte-identical to tools/agent-guard again. Generated-by: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01GTPsZ5aEE5bUVYqp47Dpvv
77f049c to
a9f7d02
Compare
potiuk
left a comment
There was a problem hiding this comment.
LGTM — the last round's points are all addressed: this repository now has a single active Magpie hook (the project-hook shape survives only as an inactive setup template), the rebuilt plugin is verified with a live agent-guard[no-verify] denial on Claude Code as well as Grok, the no-argument path routes by payload shape instead of GROK_HOOK_EVENT (with a regression test for an inherited variable), and the doc nits are fixed.
The branch had fallen behind main, where the agent-guard mention guard changed today. I rebased it onto main (your four commits unchanged apart from the regenerated FRAMEWORK_FINGERPRINT at each step), and added a9f7d02, which regenerates the packaged agent-guard copy with check-family-plugins.py --fix, so the plugin ships the current guard. prek run --all-files passes on the result.
One small thing for the record: the PR description still lists a run_terminal_cmd alias, which the adapter (rightly) no longer handles — only the verified run_terminal_command is guarded.
This review was drafted by an AI-assisted tool and
confirmed by an Apache Magpie maintainer. The maintainer
approving this PR has read the findings and signed off. If
something feels off, please reply on the PR and a maintainer
will follow up.More on how Apache Magpie handles maintainer review:
Contributing guide.
Summary
Adds native Grok
PreToolUsesupport totools/agent-guardwhile keeping the guard engine harness-neutral.The Grok adapter translates the observed Grok hook payload into the existing shared
dispatch(command, cwd)path and enforces Magpie policy before shell execution.Refs #1416
What changed
--groksupport toagent-guardgrok_main()as the Grok adapter around the shared guard dispatcherPreToolUsepayload captured on Grok Build 1.0.46run_terminal_command0for allow{"decision": "deny", "reason": "..."}plus exit2for denyGROK_HOOK_EVENTcwdforwarding--grokroutingGROK_HOOK_EVENTnot misrouting a Claude Code payloadMarketplace and project-hook wiring
magpie-agent-guardregisters its shared hook through:The plugin command resolves the runtime with:
The packaged plugin contains real copies of the agent-guard runtime instead of relying on an escaping symlink.
check-family-plugins.pyverifies the packaged runtime remains synchronized withtools/agent-guard.This Magpie repository does not keep an active:
because
.claude/settings.jsonalready enablesmagpie-agent-guard, and Grok reads enabled Claude-compatible plugins. Keeping both would run the same guard twice.The source/snapshot project-hook shape is retained as the inactive setup template:
Setup can install that template as:
for adopters using project-hook wiring instead of the marketplace plugin.
Runtime verification
Grok Build
The
PreToolUsepayload contract was captured on:Marketplace/plugin behavior and failure semantics were additionally verified on:
Verified behavior includes:
provides.hooks: truegrok inspect --jsonreports the pluginhooks/hooks.jsongit commit --no-verify --dry-runis denied byagent-guard[no-verify]2without JSON blocks the shell tool call2also blocksIn the Magpie checkout,
grok inspect --jsonreports a single active Magpie action-guard hook from the enabled plugin.Claude Code
The rebuilt shared plugin hook was also verified live on:
With
magpie-agent-guardinstalled from this checkout:was blocked during
PreToolUse:Bashby:before Git executed.
Failure semantics
Malformed or irrelevant input handled inside
grok_main()deliberately returns0and remains fail-open.Hook-process failure is different: Grok Build 1.0.50 was observed to block on exit
2, including both a bareexit 2hook and a missing Python hook target.Setup lifecycle
Added Grok action-guard handling to setup install, upgrade, verify, worktree, and uninstall flows.
The lifecycle distinguishes:
When project-hook wiring is selected, Magpie owns only:
The lifecycle intentionally does not modify:
.grok/hooks/*.grok/config.tomlHook trust remains an explicit operator decision.
Metadata and documentation
agent-guardharness metadatadocs/adapters/grok.mdwith the sourced and observed hook contractreviewer backend onlytoreviewer backend + action guardThis PR intentionally does not add full Grok
spec-loop/ headless harness support. That remains separate work under #1416.Validation
Validated with:
check-family-plugins.pyTMPDIR=/tmp prek run --all-filesThe final branch was also rebased onto current
main, and the packaged agent-guard runtime was regenerated so the plugin ships the current guard implementation.AI assistance
AI assistance was used for implementation planning, repository analysis, patch review, and test/debug iteration.
All changes were reviewed and validated locally before submission.