{ "_comment": [ "Every entry is a `command` hook, including the 13 passive recorders. That is not a style", "choice: an `http` hook cannot reach this daemon by any route. Grok Build's http runner", "(xai-grok-hooks/src/runner/http.rs, `validate_hook_url`) rejects every scheme but https,", "then resolves the host and refuses the resolved address if it is private, link-local or", "CGNAT - so plain http on loopback is out, and so is the tailnet, because *.ts.net resolves", "into 100.64/10 (and fd7a::/48, inside the blocked fc00::/7). Pointing a hook at the public", "https origin therefore fails upstream, before a request is ever sent. The runner also sends", "no request header but Content-Type, so such a hook could not authenticate itself even if it", "could connect.", "", "A command hook has none of those problems: it is a local process, so there is no URL to", "validate, no proxy in the path, and it reads the shared secret out of $GLANCE_HOME itself.", "It costs one Node start (~40ms) per event. Nothing here is secret, and nothing here is", "derived from config.json - the scripts read that themselves - so this file is plain,", "committed, and edited by hand.", "", "SessionStart boots the daemon. PreToolUse is wired twice on purpose: one entry records", "every call for the timeline, and a second, narrowly matched entry runs the approval gate,", "because PreToolUse is the only blocking event and only a command hook can return a deny.", "", "The gate's 125s timeout is the ceiling for the whole approval round trip. The daemon caps", "approval.timeoutMs at 90s against it, so the script always outlives its own wait and gets", "to fail open. Changing the number here means changing APPROVAL_HOOK_TIMEOUT_SECS in", "bin/glance-lib.mjs and APPROVAL_MAX_WAIT_MS in server/src/config.ts to match." ], "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-up.mjs\"", "timeout": 20 } ] } ], "PreToolUse": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] }, { "matcher": "^(Bash|Write|Edit|MultiEdit|NotebookEdit)$", "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-approve.mjs\"", "timeout": 125 } ] } ], "PostToolUse": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "PostToolUseFailure": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "PermissionDenied": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "Notification": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "StopFailure": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "SubagentStart": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "SubagentStop": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "PreCompact": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "PostCompact": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ], "SessionEnd": [ { "hooks": [ { "type": "command", "command": "node \"$GROK_PLUGIN_ROOT/bin/glance-record.mjs\"", "timeout": 5 } ] } ] } }