AgentGuards

Claude Code — Hooks

Run AgentGuards checks as Claude Code hooks to enforce guardrails at the tool-execution boundary. Hooks fire before Claude executes shell commands and before Claude responds to user prompts.

Hook types

HookWhen it firesEnforcement
PreToolUse (Bash)Before any shell command executesHard block — command never runs
UserPromptSubmitAfter user submits a promptSoft block — Claude Code won't respond

Note: UserPromptSubmit hooks cannot intercept the LLM call to Anthropic — they only prevent Claude from showing a response. For message-level interception, use the proxy integration.

Setup

1. Install the hook script

bash
cp scripts/agentguards_hook.py ~/.claude/agentguards_hook.py

On Windows: copy scripts\agentguards_hook.py %USERPROFILE%\.claude\agentguards_hook.py

2. Configure hooks in ~/.claude/settings.json

~/.claude/settings.json
{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "AGENTGUARDS_URL=https://prod.agentguards.co AGENTGUARDS_API_KEY=ag_YOUR_TOKEN python3 ~/.claude/agentguards_hook.py UserPromptSubmit"
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "AGENTGUARDS_URL=https://prod.agentguards.co AGENTGUARDS_API_KEY=ag_YOUR_TOKEN python3 ~/.claude/agentguards_hook.py PreToolUse"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash|WebFetch|WebSearch|Write|Edit|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "AGENTGUARDS_URL=https://prod.agentguards.co AGENTGUARDS_API_KEY=ag_YOUR_TOKEN python3 ~/.claude/agentguards_hook.py PostToolUse"
          }
        ]
      }
    ]
  }
}

Recommended: set the env vars in your shell profile so the API key is not visible in process listings.

~/.zshrc
# ~/.zshrc or ~/.bashrc
export AGENTGUARDS_URL=https://prod.agentguards.co
export AGENTGUARDS_API_KEY=ag_YOUR_TOKEN

Then the settings become:

~/.claude/settings.json
{
  "hooks": {
    "UserPromptSubmit": [
      { "hooks": [{ "type": "command", "command": "python3 ~/.claude/agentguards_hook.py UserPromptSubmit" }] }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [{ "type": "command", "command": "python3 ~/.claude/agentguards_hook.py PreToolUse" }]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Bash|WebFetch|WebSearch|Write|Edit|MultiEdit",
        "hooks": [{ "type": "command", "command": "python3 ~/.claude/agentguards_hook.py PostToolUse" }]
      }
    ]
  }
}

3. Verify

Run a Claude Code session and try a blocked command. The hook calls POST /v1/actions/authorize and blocks the command before it executes.

test
User: Run rm -rf /

Understanding hook behaviour

Want a plain-language explanation of what each hook does, which commands are approved or blocked, and what the decisions mean?

How hooks work →

Combining with other integrations

Proxy + Hooks together cover both conversation-level and action-level threats — the recommended setup for API key users. For Claude Pro / Max subscribers (no proxy available), hooks are the primary enforcement mechanism for tool execution.

Fail-open behaviour

The hook script is designed to fail open: if the AgentGuards service is unreachable (network issue, timeout), the hook exits 0 and allows the action. This prevents the guardrail service from becoming a hard dependency that blocks your work.

To change this to fail-closed, edit the _allow() calls in the except blocks of agentguards_hook.py.