grok-hooks-valid¶
.grok/hooks/*.json must use Grok's hook events, handler types and fields
| Severity | error (auto) |
| Autofix | - |
| Since | v0.20.0 |
| Repo Types | grok-project |
| Category | Grok Build |
Why¶
.grok/hooks/*.json allows you to automate shell commands and HTTP requests
during Grok Build agent lifecycle events — such as right before a tool runs,
when a session begins, or when the agent completes its work. Because hooks are
committed to the repository, they provide a reliable, shared mechanism for
running checks and automations across your team.
Grok Build reads all *.json files directly inside .grok/hooks/ and merges
their hook definitions. If a hook file has syntax or structural issues, Grok
may skip the file or individual handlers quietly during headless sessions.
This rule verifies your .grok/hooks/*.json files against Grok's supported
events, handler types, and options so that your automations run reliably.
Command execution patterns are also scanned for security by
hooks-dangerous and can be inventoried against an
explicit allowlist with hooks-prohibited.
Severity¶
Severity reflects how much of the hook configuration is affected by an issue:
Errors — issues that prevent Grok Build from loading the hooks file:
- Invalid JSON syntax, non-finite numbers (
NaN,Infinity,-Infinity), or a file starting with a UTF-8 Byte Order Mark (BOM). - Missing top-level
hooksobject, or an object that is not a dictionary. - Recognized event values that are not arrays, matcher groups that are not objects, or
matcher groups missing their
hooksarray. - Handlers missing a
typefield. - A
matcherthat is not a string. - Handler fields with incompatible data types:
type,command, andurlmust be strings;timeoutmust be a non-negative integer; andenvmust be an object with string values.
Warnings — the file loads, but specific events or handlers may not run:
- Unrecognized hook event names. Grok skips their values before decoding
groups or handlers, so their descendants do not produce shape errors.
Declare a newer event in
extra-eventsto enable its strict shape checks. - A regex
matcherthat does not compile under Rust's regex engine. Rust's regex syntax supports Unicode property classes (\p{...}) and set operations (&&,--,~~), but does not support lookarounds, backreferences, or conditional groups. Matchers longer than 1,000 characters are skipped to keep checks responsive. - A
commandhandler missing acommandstring, or anhttphandler missing aurlstring. - Handlers specifying an unsupported
type(supported types arecommandandhttp). - An empty
hooksobject or empty event array (valid JSON, but configures no actions).
Info — helpful configuration tips:
- Environment variables in
envthat are automatically provided by Grok's hook runner (such asGROK_HOOK_EVENT,GROK_SESSION_ID, orGROK_WORKSPACE_ROOT), as the runner's values take precedence. - Defining a
matcheron events likeStoporUserPromptSubmitwhere matchers are not evaluated by Grok.
Event names¶
Grok accepts several spellings of each event and normalizes them, making it easy to share hooks across tools like Claude Code or Cursor. Accepted variations include:
- Standard Grok event names:
SessionStart,SessionEnd,UserPromptSubmit,PreToolUse,PostToolUse,PostToolUseFailure,PermissionDenied,Stop,StopFailure,StopCancelled,Notification,SubagentStart,SubagentStop,PreCompact,PostCompact. - Documented aliases:
SubagentEnd(alias forSubagentStop). - The
snake_caserepresentation passed toGROK_HOOK_EVENT. - Cased variants, with the note that
userPromptSubmitshould be written asUserPromptSubmit,user_prompt_submit, or Cursor'sbeforeSubmitPrompt. - Cursor lifecycle events:
beforeShellExecution,beforeMCPExecution, andbeforeReadFilemap toPreToolUse;afterShellExecution,afterMCPExecution,afterFileEdit,afterAgentResponse, andafterAgentThoughtmap toPostToolUse.
Examples¶
Bad — a string timeout prevents the file from loading:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{ "type": "command", "command": "./scripts/version.sh", "timeout": "10" }
]
}
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "make lint" }] }
]
}
}
Good — well-formed matcher groups and appropriate handler options:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|run_terminal_command",
"hooks": [
{ "type": "command", "command": "./scripts/audit-command.sh", "timeout": 5 }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "make lint", "timeout": 600 },
{ "type": "http", "url": "https://hooks.example.com/turn-ended", "timeout": 10 }
]
}
]
}
}
How to fix¶
- Specify
timeoutas a non-negative integer of seconds (30, rather than30.0or"30"). For longer tasks like test suites inStophooks, generous timeouts (such as 600 seconds) work well. - Provide each handler with
"type": "command"and acommandstring, or"type": "http"and aurlstring. - Keep
envvalues as strings. Variables provided by Grok's runner do not need to be repeated inenv. - Use standard Grok event names or supported aliases.
If Grok introduces newer event names, you can allow them in .skillsaw.yaml:
Matcher check limits¶
Matcher validation is conservative: it translates Rust inline flags and
braced hexadecimal escapes only for syntax checking. For example,
Bash|(?i)Write, (?-u:\w+), (?U).*, \x{42}ash, \u{42}ash and
\U{42}ash are accepted.
Unclosed groups/classes and unsupported look-around/backreferences are still
reported in the checked subset. Extended-mode (x) patterns are left
unresolved because comments change tokenization. No finding is a complete
Rust regex validation guarantee.
Numeric timeouts¶
Write a timeout as an unsigned integer token, such as 0 or 30. Grok
rejects literal -0, decimal/exponent forms such as 0.0 and 0e0, and
integers above 18446744073709551615. A wrong timeout type prevents the
whole hooks file from loading.
Configuration¶
| Parameter | Description | Default |
|---|---|---|
extra-events |
Additional hook event names to accept, for events newer than this skillsaw release | [] |
Run skillsaw explain grok-hooks-valid to see this documentation and the rule's effective configuration in your terminal.