openclaw/docs/tools/pre-exec-hooks.md
saurabh 9be2180b04 docs: add pre-exec hooks documentation
Covers hook discovery, protocol, writing hooks, and example usage.
2026-01-29 20:20:13 +07:00

3.1 KiB

Pre-Exec Hooks

Pre-exec hooks let workspace-level scripts intercept and approve/deny shell commands before they run. This provides a safety net for AI agent operations — preventing pushes to protected branches, writes to production databases, or dangerous file operations.

How It Works

Agent runs: git push origin develop
         ↓
Clawdbot exec tool → runs pre-exec hooks
         ↓
~/.clawdbot/hooks/safe-git.sh → receives command as JSON
         ↓
Hook outputs: {"decision": "deny", "reason": "🚫 Protected branch"}
         ↓
Exec tool throws error instead of running command

Hook Discovery

Hooks are discovered from these directories (in order):

  1. <workspace>/.clawdbot/hooks/ (preferred)
  2. <workspace>/hooks/ (fallback)

Any executable shell script in these directories is treated as a hook.

Hook Protocol

Input (JSON on stdin)

{
  "tool_name": "exec",
  "tool_input": {
    "command": "git push origin main",
    "workdir": "/path/to/workspace",
    "env": {}
  }
}

Output (JSON on stdout)

{
  "decision": "approve",
  "reason": "optional message"
}

Or to deny:

{
  "decision": "deny", 
  "reason": "🚫 Pushing to protected branches is blocked."
}

Writing a Hook

Create an executable script in .clawdbot/hooks/:

#!/bin/bash
# .clawdbot/hooks/block-sudo.sh

INPUT=$(cat)
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

if echo "$COMMAND" | grep -qE '(^|\s)sudo\s'; then
  echo '{"decision": "deny", "reason": "🚫 sudo is not allowed."}'
  exit 0
fi

echo '{"decision": "approve"}'

Make it executable:

chmod +x .clawdbot/hooks/block-sudo.sh

Example Hooks

Clawdbot includes example hooks in examples/pre-exec-hooks/:

safe-git.sh

Blocks:

  • Force pushes (--force, -f)
  • Pushes to protected branches (main, develop, staging, production)
  • Remote modifications (git remote add/remove/set-url)

safe-db.sh

Blocks:

  • Non-SELECT operations on remote databases
  • Migrations/seeds targeting staging/production environments

safe-rm.sh

Blocks:

  • rm -rf /
  • rm on home/system directories
  • rm -rf * (wildcard deletion)

Behavior

  • Sequential execution: Hooks run in alphabetical order
  • Short-circuit: First "deny" stops execution
  • Fail-open: Timeouts and errors default to "approve"
  • Timeout: 10 seconds per hook (configurable)

Environment Variables

Hooks receive these environment variables:

Variable Description
CLAWDBOT_HOOK_NAME Name of the current hook
CLAWDBOT_TOOL_NAME Tool being invoked (exec or Bash)

Tips

  1. Use jq for parsing JSON input
  2. Keep hooks fast — they run on every command
  3. Log to stderr — only stdout is parsed
  4. Test locally before deploying
# Test a hook manually
echo '{"tool_name":"exec","tool_input":{"command":"git push origin main"}}' | .clawdbot/hooks/safe-git.sh