Hooks Reference
** PARITY GAP**: Grok One-Shot does not currently implement the hooks system described in this document. This is a comprehensive Claude Code feature planned for future implementation.
Status in Grok One-Shot
Current Status: Not Implemented Planned: Q2 2026 (Sprint 18-20) Priority: P2 - Workflow automation
What Hooks Enable (in Claude Code):
- Deterministic workflow automation
- Pre/post tool execution control
- Custom notifications and integrations
- Code formatting automation
- Permission management
- Session lifecycle hooks
Alternative Approaches: Until hooks are implemented, use:
- Shell scripts in your repository
- Git hooks for pre-commit automation
- MCP servers for external integrations
- Manual workflow documentation in
.agent/docs/
This document provides reference documentation for implementing hooks in Claude Code. For Grok One-Shot context on how this might work in the future, see the adaptations below.
For a quickstart guide with examples, see Get started with Grok One-Shot hooks.
Configuration
Grok One-Shot hooks would be configured in your settings files:
~/.grok/settings.json- User settings.grok/settings.json- Project settings.grok/settings.local.json- Local project settings (not committed)- Enterprise managed policy settings
Structure
Hooks are organized by matchers, where each matcher can have multiple hooks:
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "your-command-here"
}
]
}
]
}
}
- matcher: Pattern to match tool names, case-sensitive (only applicable for
PreToolUseandPostToolUse) - Simple strings match exactly:
Writematches only the Write tool - Supports regex:
Edit|WriteorNotebook.* - Use
*to match all tools. You can also use empty string ("") or leavematcherblank. - hooks: Array of hooks to execute when the pattern matches
type: Hook execution type -"command"for bash commands or"prompt"for LLM-based evaluationcommand: (Fortype: "command") The bash command to execute (can use$GROK_PROJECT_DIRenvironment variable)prompt: (Fortype: "prompt") The prompt to send to the LLM for evaluationtimeout: (Optional) How long a hook should run, in seconds, before canceling that specific hook
For events like UserPromptSubmit, Notification, Stop, and SubagentStop
that don't use matchers, you can omit the matcher field:
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "/path/to/prompt-validator.py"
}
]
}
]
}
}
Project-Specific Hook Scripts
You can use the environment variable GROK_PROJECT_DIR (only available when
Grok One-Shot spawns the hook command) to reference scripts stored in your project,
ensuring they work regardless of Grok's current directory:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$GROK_PROJECT_DIR\"/.grok/hooks/check-style.sh"
}
]
}
]
}
}
Plugin hooks
Plugins can provide hooks that integrate seamlessly with your user and project hooks. Plugin hooks are automatically merged with your configuration when plugins are enabled.
Note: Plugins are not yet implemented in Grok One-Shot. See Plugin System for details.
How plugin hooks work:
- Plugin hooks are defined in the plugin's
hooks/hooks.jsonfile or in a file given by a custom path to thehooksfield. - When a plugin is enabled, its hooks are merged with user and project hooks
- Multiple hooks from different sources can respond to the same event
- Plugin hooks use the
${GROK_PLUGIN_ROOT}environment variable to reference plugin files
Example plugin hook configuration:
{
"description": "Automatic code formatting",
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${GROK_PLUGIN_ROOT}/scripts/format.sh",
"timeout": 30
}
]
}
]
}
}
Plugin hooks use the same format as regular hooks with an optional description field to explain the hook's purpose.
Plugin hooks run alongside your custom hooks. If multiple hooks match an event, they all execute in parallel.
Environment variables for plugins:
${GROK_PLUGIN_ROOT}: Absolute path to the plugin directory${GROK_PROJECT_DIR}: Project root directory (same as for project hooks)- All standard environment variables are available
See the plugin components reference for details on creating plugin hooks.
Prompt-Based Hooks
In addition to bash command hooks (type: "command"), Grok One-Shot would support prompt-based hooks (type: "prompt") that use an LLM to evaluate whether to allow or block an action. Prompt-based hooks would be supported for Stop and SubagentStop hooks, where they enable intelligent, context-aware decisions.
How prompt-based hooks work
Instead of executing a bash command, prompt-based hooks:
- Send the hook input and your prompt to a fast LLM (Grok-beta)
- The LLM responds with structured JSON containing a decision
- Grok One-Shot processes the decision automatically
Configuration
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Evaluate if Grok should stop: $ARGUMENTS. Check if all tasks are complete."
}
]
}
]
}
}
Fields:
type: Must be"prompt"prompt: The prompt text to send to the LLM- Use
$ARGUMENTSas a placeholder for the hook input JSON - If
$ARGUMENTSis not present, input JSON is appended to the prompt timeout: (Optional) Timeout in seconds (default: 30 seconds)
Response schema
The LLM must respond with JSON containing:
{
"decision": "approve" | "block",
"reason": "Explanation for the decision",
"continue": false, // Optional: stops Grok entirely
"stopReason": "Message shown to user", // Optional: custom stop message
"systemMessage": "Warning or context" // Optional: shown to user
}
Response fields:
decision:"approve"allows the action,"block"prevents itreason: Explanation shown to Grok when decision is"block"continue: (Optional) Iffalse, stops Grok's execution entirelystopReason: (Optional) Message shown whencontinueis falsesystemMessage: (Optional) Additional message shown to the user
Supported hook events
Prompt-based hooks work with any hook event, but are most useful for:
- Stop: Intelligently decide if Grok should continue working
- SubagentStop: Evaluate if a subagent has completed its task
- UserPromptSubmit: Validate user prompts with LLM assistance
- PreToolUse: Make context-aware permission decisions
Example: Intelligent Stop hook
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "You are evaluating whether Grok should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"decision\": \"approve\" or \"block\", \"reason\": \"your explanation\"}",
"timeout": 30
}
]
}
]
}
}
Example: SubagentStop with custom logic
{
"hooks": {
"SubagentStop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Evaluate if this subagent should stop. Input: $ARGUMENTS\n\nCheck if:\n- The subagent completed its assigned task\n- Any errors occurred that need fixing\n- Additional context gathering is needed\n\nReturn: {\"decision\": \"approve\" or \"block\", \"reason\": \"explanation\"}"
}
]
}
]
}
}
Comparison with bash command hooks
| Feature | Bash Command Hooks | Prompt-Based Hooks |
|---|---|---|
| Execution | Runs bash script | Queries LLM |
| Decision logic | You implement in code | LLM evaluates context |
| Setup complexity | Requires script file | Just configure prompt |
| Context awareness | Limited to script logic | Natural language understanding |
| Performance | Fast (local execution) | Slower (API call) |
| Use case | Deterministic rules | Context-aware decisions |
Best practices
- Be specific in prompts: Clearly state what you want the LLM to evaluate
- Include decision criteria: List the factors the LLM should consider
- Test your prompts: Verify the LLM makes correct decisions for your use cases
- Set appropriate timeouts: Default is 30 seconds, adjust if needed
- Use for complex decisions: Bash hooks are better for simple, deterministic rules
See the plugin components reference for details on creating plugin hooks.
Hook Events
PreToolUse
Runs after Grok creates tool parameters and before processing the tool call.
Common matchers:
Task- Subagent tasks (see subagents documentation)Bash- Shell commandsGlob- File pattern matchingGrep- Content searchRead- File readingEdit- File editingWrite- File writingWebFetch,WebSearch- Web operations
PostToolUse
Runs immediately after a tool completes successfully.
Recognizes the same matcher values as PreToolUse.
Notification
Runs when Grok One-Shot sends notifications. Notifications are sent when:
- Grok needs your permission to use a tool. Example: "Grok needs your permission to use Bash"
- The prompt input has been idle for at least 60 seconds. "Grok is waiting for your input"
UserPromptSubmit
Runs when the user submits a prompt, before Grok processes it. This allows you to add additional context based on the prompt/conversation, validate prompts, or block certain types of prompts.
Stop
Runs when the main Grok One-Shot agent has finished responding. Does not run if the stoppage occurred due to a user interrupt.
SubagentStop
Runs when a Grok One-Shot subagent (Task tool call) has finished responding.
PreCompact
Runs before Grok One-Shot is about to run a compact operation.
Matchers:
manual- Invoked from/compactauto- Invoked from auto-compact (due to full context window)
SessionStart
Runs when Grok One-Shot starts a new session or resumes an existing session (which currently does start a new session under the hood). Useful for loading in development context like existing issues or recent changes to your codebase, installing dependencies, or setting up environment variables.
Matchers:
startup- Invoked from startupresume- Invoked from--resume,--continue, or/resumeclear- Invoked from/clearcompact- Invoked from auto or manual compact.
Persisting environment variables
SessionStart hooks have access to the GROK_ENV_FILE environment variable, which provides a file path where you can persist environment variables for subsequent bash commands.
Example: Setting individual environment variables
#!/bin/bash
if [ -n "$GROK_ENV_FILE" ]; then
echo 'export NODE_ENV=production' >> "$GROK_ENV_FILE"
echo 'export API_KEY=your-api-key' >> "$GROK_ENV_FILE"
echo 'export PATH="$PATH:./node_modules/.bin"' >> "$GROK_ENV_FILE"
fi
exit 0
Example: Persisting all environment changes from the hook
When your setup modifies the environment (e.g., nvm use), capture and persist all changes by diffing the environment:
#!/bin/bash
ENV_BEFORE=$(export -p | sort)
# Run your setup commands that modify the environment
source ~/.nvm/nvm.sh
nvm use 20
if [ -n "$GROK_ENV_FILE" ]; then
ENV_AFTER=$(export -p | sort)
comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$GROK_ENV_FILE"
fi
exit 0
Any variables written to this file will be available in all subsequent bash commands that Grok One-Shot executes during the session.
GROK_ENV_FILE is only available for SessionStart hooks. Other hook types do not have access to this variable.
SessionEnd
Runs when a Grok One-Shot session ends. Useful for cleanup tasks, logging session statistics, or saving session state.
The reason field in the hook input will be one of:
clear- Session cleared with /clear commandlogout- User logged outprompt_input_exit- User exited while prompt input was visibleother- Other exit reasons
Hook Input
Hooks receive JSON data via stdin containing session information and event-specific data:
{
// Common fields
session_id: string
transcript_path: string // Path to conversation JSON
cwd: string // The current working directory when the hook is invoked
permission_mode: string // Current permission mode: "default", "plan", "acceptEdits", or "bypassPermissions"
// Event-specific fields
hook_event_name: string
...
}
PreToolUse Input
The exact schema for tool_input depends on the tool.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.grok/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PreToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
}
}
PostToolUse Input
The exact schema for tool_input and tool_response depends on the tool.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.grok/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "PostToolUse",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
},
"tool_response": {
"filePath": "/path/to/file.txt",
"success": true
}
}
Notification Input
{
"session_id": "abc123",
"transcript_path": "/Users/.../.grok/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "Notification",
"message": "Task completed successfully"
}
UserPromptSubmit Input
{
"session_id": "abc123",
"transcript_path": "/Users/.../.grok/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "UserPromptSubmit",
"prompt": "Write a function to calculate the factorial of a number"
}
Stop and SubagentStop Input
stop_hook_active is true when Grok One-Shot is already continuing as a result of
a stop hook. Check this value or process the transcript to prevent Grok One-Shot
from running indefinitely.
{
"session_id": "abc123",
"transcript_path": "~/.grok/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"permission_mode": "default",
"hook_event_name": "Stop",
"stop_hook_active": true
}
PreCompact Input
For manual, custom_instructions comes from what the user passes into
/compact. For auto, custom_instructions is empty.
{
"session_id": "abc123",
"transcript_path": "~/.grok/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"permission_mode": "default",
"hook_event_name": "PreCompact",
"trigger": "manual",
"custom_instructions": ""
}
SessionStart Input
{
"session_id": "abc123",
"transcript_path": "~/.grok/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"permission_mode": "default",
"hook_event_name": "SessionStart",
"source": "startup"
}
SessionEnd Input
{
"session_id": "abc123",
"transcript_path": "~/.grok/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "SessionEnd",
"reason": "exit"
}
Hook Output
There are two ways for hooks to return output back to Grok One-Shot. The output communicates whether to block and any feedback that should be shown to Grok and the user.
Simple: Exit Code
Hooks communicate status through exit codes, stdout, and stderr:
- Exit code 0: Success.
stdoutis shown to the user in transcript mode (CTRL-R), except forUserPromptSubmitandSessionStart, where stdout is added to the context. - Exit code 2: Blocking error.
stderris fed back to Grok to process automatically. See per-hook-event behavior below. - Other exit codes: Non-blocking error.
stderris shown to the user and execution continues.
Reminder: Grok One-Shot does not see stdout if the exit code is 0, except for
the UserPromptSubmit hook where stdout is injected as context.
Exit Code 2 Behavior
| Hook Event | Behavior |
|---|---|
PreToolUse | Blocks the tool call, shows stderr to Grok |
PostToolUse | Shows stderr to Grok (tool already ran) |
Notification | N/A, shows stderr to user only |
UserPromptSubmit | Blocks prompt processing, erases prompt, shows stderr to user only |
Stop | Blocks stoppage, shows stderr to Grok |
SubagentStop | Blocks stoppage, shows stderr to Grok subagent |
PreCompact | N/A, shows stderr to user only |
SessionStart | N/A, shows stderr to user only |
SessionEnd | N/A, shows stderr to user only |
Advanced: JSON Output
Hooks can return structured JSON in stdout for more sophisticated control:
Common JSON Fields
All hook types can include these optional fields:
{
"continue": true, // Whether Grok should continue after hook execution (default: true)
"stopReason": "string", // Message shown when continue is false
"suppressOutput": true, // Hide stdout from transcript mode (default: false)
"systemMessage": "string" // Optional warning message shown to the user
}
If continue is false, Grok stops processing after the hooks run.
- For
PreToolUse, this is different from"permissionDecision": "deny", which only blocks a specific tool call and provides automatic feedback to Grok. - For
PostToolUse, this is different from"decision": "block", which provides automated feedback to Grok. - For
UserPromptSubmit, this prevents the prompt from being processed. - For
StopandSubagentStop, this takes precedence over any"decision": "block"output. - In all cases,
"continue" = falsetakes precedence over any"decision": "block"output.
stopReason accompanies continue with a reason shown to the user, not shown
to Grok.
PreToolUse Decision Control
PreToolUse hooks can control whether a tool call proceeds.
"allow"bypasses the permission system.permissionDecisionReasonis shown to the user but not to Grok."deny"prevents the tool call from executing.permissionDecisionReasonis shown to Grok."ask"asks the user to confirm the tool call in the UI.permissionDecisionReasonis shown to the user but not to Grok.
Additionally, hooks can modify tool inputs before execution using updatedInput:
updatedInputallows you to modify the tool's input parameters before the tool executes. This is aRecord<string, unknown>object containing the fields you want to change or add.- This is most useful with
"permissionDecision": "allow"to modify and approve tool calls.
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow"
"permissionDecisionReason": "My reason here",
"updatedInput": {
"field_to_modify": "new value"
}
}
}
The decision and reason fields are deprecated for PreToolUse hooks.
Use hookSpecificOutput.permissionDecision and
hookSpecificOutput.permissionDecisionReason instead. The deprecated fields
"approve" and "block" map to "allow" and "deny" respectively.
PostToolUse Decision Control
PostToolUse hooks can provide feedback to Grok after tool execution.
"block"automatically prompts Grok withreason.undefineddoes nothing.reasonis ignored."hookSpecificOutput.additionalContext"adds context for Grok to consider.
{
"decision": "block" | undefined,
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "Additional information for Grok"
}
}
UserPromptSubmit Decision Control
UserPromptSubmit hooks can control whether a user prompt is processed.
"block"prevents the prompt from being processed. The submitted prompt is erased from context."reason"is shown to the user but not added to context.undefinedallows the prompt to proceed normally."reason"is ignored."hookSpecificOutput.additionalContext"adds the string to the context if not blocked.
{
"decision": "block" | undefined,
"reason": "Explanation for decision",
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "My additional context here"
}
}
Stop/SubagentStop Decision Control
Stop and SubagentStop hooks can control whether Grok must continue.
"block"prevents Grok from stopping. You must populatereasonfor Grok to know how to proceed.undefinedallows Grok to stop.reasonis ignored.
{
"decision": "block" | undefined,
"reason": "Must be provided when Grok is blocked from stopping"
}
SessionStart Decision Control
SessionStart hooks allow you to load in context at the start of a session.
"hookSpecificOutput.additionalContext"adds the string to the context.- Multiple hooks'
additionalContextvalues are concatenated.
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "My additional context here"
}
}
SessionEnd Decision Control
SessionEnd hooks run when a session ends. They cannot block session termination
but can perform cleanup tasks.
Exit Code Example: Bash Command Validation
#!/usr/bin/env python3
import json
import re
import sys
# Define validation rules as a list of (regex pattern, message) tuples
VALIDATION_RULES = [
(
r"\bgrep\b(?!.*\|)",
"Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
),
(
r"\bfind\s+\S+\s+-name\b",
"Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
),
]
def validate_command(command: str) -> list[str]:
issues = []
for pattern, message in VALIDATION_RULES:
if re.search(pattern, command):
issues.append(message)
return issues
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")
if tool_name != "Bash" or not command:
sys.exit(1)
# Validate the command
issues = validate_command(command)
if issues:
for message in issues:
print(f"• {message}", file=sys.stderr)
# Exit code 2 blocks tool call and shows stderr to Grok
sys.exit(2)
JSON Output Example: UserPromptSubmit to Add Context and Validation
For UserPromptSubmit hooks, you can inject context using either method:
- Exit code 0 with stdout: Grok sees the context (special case for
UserPromptSubmit) - JSON output: Provides more control over the behavior
#!/usr/bin/env python3
import json
import sys
import re
import datetime
# Load input from stdin
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
prompt = input_data.get("prompt", "")
# Check for sensitive patterns
sensitive_patterns = [
(r"(?i)\b(password|secret|key|token)\s*[:=]", "Prompt contains potential secrets"),
]
for pattern, message in sensitive_patterns:
if re.search(pattern, prompt):
# Use JSON output to block with a specific reason
output = {
"decision": "block",
"reason": f"Security policy violation: {message}. Please rephrase your request without sensitive information."
}
print(json.dumps(output))
sys.exit(0)
# Add current time to context
context = f"Current time: {datetime.datetime.now()}"
print(context)
"""
The following is also equivalent:
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": context,
},
}))
"""
# Allow the prompt to proceed with the additional context
sys.exit(0)
JSON Output Example: PreToolUse with Approval
#!/usr/bin/env python3
import json
import sys
# Load input from stdin
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
# Example: Auto-approve file reads for documentation files
if tool_name == "Read":
file_path = tool_input.get("file_path", "")
if file_path.endswith((".md", ".mdx", ".txt", ".json")):
# Use JSON output to auto-approve the tool call
output = {
"decision": "approve",
"reason": "Documentation file auto-approved",
"suppressOutput": True # Don't show in transcript mode
}
print(json.dumps(output))
sys.exit(0)
# For other cases, let the normal permission flow proceed
sys.exit(0)
Working with MCP Tools
Grok One-Shot hooks would work seamlessly with Model Context Protocol (MCP) tools. When MCP servers provide tools, they appear with a special naming pattern that you can match in your hooks.
MCP Tool Naming
MCP tools follow the pattern mcp__<server>__<tool>, for example:
mcp__memory__create_entities- Memory server's create entities toolmcp__filesystem__read_file- Filesystem server's read file toolmcp__github__search_repositories- GitHub server's search tool
Configuring Hooks for MCP Tools
You can target specific MCP tools or entire MCP servers:
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__memory__.*",
"hooks": [
{
"type": "command",
"command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
}
]
},
{
"matcher": "mcp__.*__write.*",
"hooks": [
{
"type": "command",
"command": "/home/user/scripts/validate-mcp-write.py"
}
]
}
]
}
}
Examples
For practical examples including code formatting, notifications, and file protection, see More Examples in the get started guide.
Security Considerations
Disclaimer
USE AT YOUR OWN RISK: Grok One-Shot hooks execute arbitrary shell commands on your system automatically. By using hooks, you acknowledge that:
- You are solely responsible for the commands you configure
- Hooks can modify, delete, or access any files your user account can access
- Malicious or poorly written hooks can cause data loss or system damage
- xAI provides no warranty and assumes no liability for any damages resulting from hook usage
- You should thoroughly test hooks in a safe environment before production use
Always review and understand any hook commands before adding them to your configuration.
Security Best Practices
Here are some key practices for writing more secure hooks:
- Validate and sanitize inputs - Never trust input data blindly
- Always quote shell variables - Use
"$VAR"not$VAR - Block path traversal - Check for
..in file paths - Use absolute paths - Specify full paths for scripts (use "$GROK_PROJECT_DIR" for the project path)
- Skip sensitive files - Avoid
.env,.git/, keys, etc.
Configuration Safety
Direct edits to hooks in settings files don't take effect immediately. Grok One-Shot:
- Captures a snapshot of hooks at startup
- Uses this snapshot throughout the session
- Warns if hooks are modified externally
- Requires review in
/hooksmenu for changes to apply
This prevents malicious hook modifications from affecting your current session.
Hook Execution Details
- Timeout: 60-second execution limit by default, configurable per command.
- A timeout for an individual command does not affect the other commands.
- Parallelization: All matching hooks run in parallel
- Deduplication: Multiple identical hook commands are deduplicated automatically
- Environment: Runs in current directory with Grok One-Shot's environment
- The
GROK_PROJECT_DIRenvironment variable is available and contains the absolute path to the project root directory (where Grok One-Shot was started) - The
GROK_CODE_REMOTEenvironment variable indicates whether the hook is running in a remote (web) environment ("true") or local CLI environment (not set or empty). Use this to run different logic based on execution context. - Input: JSON via stdin
- Output:
- PreToolUse/PostToolUse/Stop/SubagentStop: Progress shown in transcript (Ctrl-R)
- Notification/SessionEnd: Logged to debug only (
--debug) - UserPromptSubmit/SessionStart: stdout added as context for Grok
Debugging
Basic Troubleshooting
If your hooks aren't working:
- Check configuration - Run
/hooksto see if your hook is registered - Verify syntax - Ensure your JSON settings are valid
- Test commands - Run hook commands manually first
- Check permissions - Make sure scripts are executable
- Review logs - Use
grok --debugto see hook execution details
Common issues:
- Quotes not escaped - Use
\"inside JSON strings - Wrong matcher - Check tool names match exactly (case-sensitive)
- Command not found - Use full paths for scripts
Advanced Debugging
For complex hook issues:
- Inspect hook execution - Use
grok --debugto see detailed hook execution - Validate JSON schemas - Test hook input/output with external tools
- Check environment variables - Verify Grok One-Shot's environment is correct
- Test edge cases - Try hooks with unusual file paths or inputs
- Monitor system resources - Check for resource exhaustion during hook execution
- Use structured logging - Implement logging in your hook scripts
Debug Output Example
Use grok --debug to see hook execution details:
[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>
Progress messages appear in transcript mode (Ctrl-R) showing:
- Which hook is running
- Command being executed
- Success/failure status
- Output or error messages
See Also
- Hooks Guide - Getting started with hooks
- Skills - Agent Skills documentation
- Plugin System - Plugin system overview
- MCP Integration - Model Context Protocol
Status: This feature is planned but not yet implemented in Grok One-Shot. Last Updated: 2025-11-07