BUILD / use-grok-build-hooks

Build

Use Grok Build hooks for lifecycle automation

Use Grok Build hooks for lifecycle automation

A hook is a shell command or HTTP endpoint Grok calls when a lifecycle event fires. Official Build hooks docs cover blocking a dangerous command before it runs, logging tool use, formatting after edits, and notifying when a turn ends.

Where hooks live

Hooks are JSON files:

  • Personal: ~/.grok/hooks/*.json
  • Project: .grok/hooks/*.json in the repo

Grok also reads Claude Code (.claude/settings.json) and Cursor (.cursor/hooks.json) hook files, including Cursor camelCase event names.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "bin/safety-check.sh", "timeout": 10 }]
      }
    ]
  }
}

matcher is a regex on the tool name (Claude names such as Bash, Read, and Edit map to Grok’s). Omit matcher to match every tool. type is "command" or "http" (with a url to POST). timeout is seconds; default 5. Inspect loaded hooks in the /hooks tab of the extensions modal.

Project hooks need trust before they run. Grant it with /hooks-trust or launch with --trust. The choice is stored in ~/.grok/trusted_folders.toml and also covers project MCP and LSP servers.

Events

Event Fires when
SessionStart, SessionEnd Session starts or ends
UserPromptSubmit You submit a prompt
PreToolUse A tool is about to run — the only blocking event
PostToolUse, PostToolUseFailure A tool completes or fails
PermissionDenied Permission system denies a tool call
Stop, StopFailure A turn ends, or ends with an API error
Notification The agent sends a notification
SubagentStart, SubagentStop A subagent starts or finishes
PreCompact, PostCompact Conversation compaction runs

Script contract

The event arrives as JSON on stdin (hookEventName, sessionId, cwd, workspaceRoot; tool events also include toolName and toolInput). Env vars include GROK_HOOK_EVENT, GROK_HOOK_NAME, GROK_SESSION_ID, and GROK_WORKSPACE_ROOT.

A PreToolUse hook decides by writing JSON to stdout:

{ "decision": "deny", "reason": "Unsafe command detected" }

Exit 0 allows; exit 2 denies. Timeouts, crashes, and malformed output are fail-open: the failure is recorded, and the tool still runs. Only an explicit deny blocks. For passive events, stdout is ignored; exit 0 on success.

Pitfalls