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
| Hook | When it fires | Enforcement |
|---|---|---|
| PreToolUse (Bash) | Before any shell command executes | Hard block — command never runs |
| UserPromptSubmit | After user submits a prompt | Soft 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
cp scripts/agentguards_hook.py ~/.claude/agentguards_hook.pyOn Windows: copy scripts\agentguards_hook.py %USERPROFILE%\.claude\agentguards_hook.py
2. Configure hooks in ~/.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 or ~/.bashrc
export AGENTGUARDS_URL=https://prod.agentguards.co
export AGENTGUARDS_API_KEY=ag_YOUR_TOKENThen the settings become:
{
"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.
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
Intercepts prompts before they reach Anthropic — message-level enforcement.
MCP
Exposes guardrail tools Claude can call cooperatively from its reasoning.
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.