home / skills / vasilyu1983 / ai-agents-public / agents-hooks
This skill automates Claude Code workflows with event-driven hooks, enabling input validation, safe tool use, formatting, auditing, and CI/CD integration.
npx playbooks add skill vasilyu1983/ai-agents-public --skill agents-hooksReview the files below or copy the command above to add this skill to your agents.
---
name: agents-hooks
description: Event-driven hooks for AI coding agents. Use when automating Claude Code or Codex CLI with stdin JSON and decision-control responses.
---
# Claude Code Hooks — Meta Reference
This skill provides the definitive reference for creating Claude Code hooks. Use this when building automation that triggers on Claude Code events.
---
## When to Use This Skill
- Building event-driven automation for Claude Code
- Creating PreToolUse guards to block dangerous commands
- Implementing PostToolUse formatters, linters, or auditors
- Adding Stop hooks for testing or notifications
- Setting up SessionStart/SessionEnd for environment management
- Integrating Claude Code with CI/CD pipelines (headless mode)
---
## Quick Reference
| Event | Trigger | Use Case |
|-------|---------|----------|
| `SessionStart` | Session begins/resumes | Initialize environment |
| `UserPromptSubmit` | User submits prompt | Preprocess/validate input |
| `PreToolUse` | Before tool execution | Validate, block dangerous commands |
| `PermissionRequest` | Permission dialog shown | Auto-allow/deny permissions |
| `PostToolUse` | After tool succeeds | Format, audit, notify |
| `PostToolUseFailure` | After tool fails | Capture failures, add guidance |
| `SubagentStart` | Subagent spawns | Inspect subagent metadata |
| `Stop` | When Claude finishes | Run tests, summarize |
| `SubagentStop` | Subagent finishes | Verify subagent completion |
| `Notification` | On notifications | Alert integrations |
| `PreCompact` | Before context compaction | Preserve critical context |
| `Setup` | `--init`/`--maintenance` | Initialize repo/env |
| `SessionEnd` | Session ends | Cleanup, save state |
## Hook Structure
```text
.claude/hooks/
├── pre-tool-validate.sh
├── post-tool-format.sh
├── post-tool-audit.sh
├── stop-run-tests.sh
└── session-start-init.sh
```
---
## Configuration
### settings.json
```json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/post-tool-format.sh"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/pre-tool-validate.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/stop-run-tests.sh"
}
]
}
]
}
}
```
---
## Execution Model (Jan 2026)
- Hooks receive a JSON payload via stdin (treat it as untrusted input) and run with your user permissions (outside the Bash tool sandbox).
- Default timeout is 60s per hook command; all matching hooks run in parallel; identical commands are deduplicated.
### Hook Input (stdin)
```json
{
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": {
"command": "ls -la"
}
}
```
### Environment Variables (shell)
| Variable | Description |
|----------|-------------|
| `CLAUDE_PROJECT_DIR` | Absolute project root where Claude Code started |
| `CLAUDE_PLUGIN_ROOT` | Plugin root (plugin hooks only) |
| `CLAUDE_CODE_REMOTE` | `"true"` in remote/web environments; empty/local otherwise |
| `CLAUDE_ENV_FILE` | File path to persist `export ...` lines (available in SessionStart; check docs for Setup support) |
---
## Exit Codes
| Code | Meaning | Notes |
|------|---------|------|
| `0` | Success | JSON written to stdout is parsed for structured control |
| `2` | Blocking error | `stderr` becomes the message; JSON in stdout is ignored |
| Other | Non-blocking error | Execution continues; `stderr` is visible in verbose mode |
Stdout injection note: for `UserPromptSubmit`, `SessionStart`, and `Setup`, non-JSON stdout (exit 0) is injected into Claude’s context; most other events show stdout only in verbose mode.
---
## Decision Control + Input Modification (v2.0.10+)
PreToolUse hooks can allow/deny/ask and optionally modify the tool input via `updatedInput`.
### Hook Output Schema
```json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "Reason shown to user (and to Claude on deny)",
"updatedInput": { "command": "echo 'modified'" },
"additionalContext": "Extra context added before tool runs"
}
}
```
Note: older `decision`/`reason` fields are deprecated; prefer the `hookSpecificOutput.*` fields.
See [hook-templates.md](references/hook-templates.md) for full examples: redirect sensitive file edits to `/dev/null` and strip `.env` files from `git add` commands.
---
## Prompt-Based Hooks
For complex decisions, use LLM-evaluated hooks (`type: "prompt"`) instead of bash scripts. They are most useful for `Stop` and `SubagentStop` decisions.
### Configuration
```json
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Evaluate whether Claude should stop. Context JSON: $ARGUMENTS. Return {\"ok\": true} if all tasks are complete, otherwise {\"ok\": false, \"reason\": \"what remains\"}.",
"timeout": 30
}
]
}
]
}
}
```
### Response Schema
- Allow: `{"ok": true}`
- Block: `{"ok": false, "reason": "Explanation shown to Claude"}`
### Combining Command and Prompt Hooks
Use command hooks for fast, deterministic checks. Use prompt hooks for nuanced decisions:
```json
{
"Stop": [
{
"hooks": [
{ "type": "command", "command": ".claude/hooks/quick-check.sh" },
{ "type": "prompt", "prompt": "Verify code quality meets standards" }
]
}
]
}
```
---
## Permission Prompt Fatigue Reduction Pattern
Use this when frequent approval dialogs slow down repeated safe workflows.
### Strategy
1. Identify repetitive, low-risk command prefixes (for example: test runners, read-only diagnostics).
2. Approve narrow prefixes instead of full commands.
3. Keep destructive or broad shells (`rm`, `git reset --hard`, generic interpreters with arbitrary input) out of auto-approval rules.
4. Re-check approved prefixes periodically; remove stale ones.
### Practical Guardrails
- Allow only task-scoped prefixes (example: `npm run test:e2e`), not unrestricted executors.
- Keep separate policy for write-outside-workspace actions.
- Pair allow-rules with deny-rules for dangerous patterns.
### Outcome
This reduces repeated permission interruptions while preserving high-safety boundaries.
## Runtime Preflight Hooks (Mandatory for Tool Reliability)
Add a lightweight runtime preflight hook when workflows depend on specific local tool versions (for example Node for JS REPL, test runners, linters).
### Preflight Responsibilities
- Verify required binaries exist.
- Verify minimum version constraints.
- Emit a clear remediation message when requirements are not met.
- Fail fast before expensive task execution starts.
### Recommended Trigger
- `SessionStart` for general runtime checks.
- `Setup` for repository bootstrap checks.
### Minimal Policy
- Keep checks deterministic and fast (<1s target).
- Do not auto-install dependencies silently in hooks.
- Print exact command the operator should run to remediate.
## Hook Templates
Copy-paste templates for the five most common hook scenarios: PreToolUse validation, PostToolUse formatting, PostToolUse security audit, Stop test runner, and SessionStart environment check.
See [references/hook-templates.md](references/hook-templates.md) for all scripts.
---
## Matchers
Matchers filter which tool triggers the hook:
- Exact match: `Write` matches only the Write tool
- Regex: `Edit|Write` or `Notebook.*`
- Match all: `*` (also works with `""` or omitted matcher)
---
## Security Best Practices
Hooks run with full user permissions outside the Bash tool sandbox. Key rules: validate all stdin input, quote every variable (`"$VAR"`), use absolute paths, never `eval` untrusted data, and set `-euo pipefail`.
See [references/hook-security.md](references/hook-security.md) for the full checklist, command injection prevention, path traversal defense, credential protection, and ShellCheck requirements.
---
## Hook Composition
### Multiple Hooks on Same Event
```json
{
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": ".claude/hooks/format.sh" },
{ "type": "command", "command": ".claude/hooks/audit.sh" },
{ "type": "command", "command": ".claude/hooks/notify.sh" }
]
}
]
}
```
All matching hooks run in parallel. If you need strict ordering (format → lint → test), make one wrapper script that runs them sequentially.
---
## Debugging Hooks
```bash
# Test a PostToolUse hook manually (stdin JSON)
export CLAUDE_PROJECT_DIR="$(pwd)"
echo '{"hook_event_name":"PostToolUse","tool_name":"Edit","tool_input":{"file_path":"'"$(pwd)"'/src/app.ts"}}' \
| bash .claude/hooks/post-tool-format.sh
# Check exit code
echo $?
```
---
## Navigation
### Resources
- [references/hook-templates.md](references/hook-templates.md) — Copy-paste hook scripts
- [references/hook-patterns.md](references/hook-patterns.md) — Common patterns
- [references/hook-security.md](references/hook-security.md) — Security guide
- [references/runtime-preflight-hooks.md](references/runtime-preflight-hooks.md) — Runtime/version preflight patterns for SessionStart and Setup
- [data/sources.json](data/sources.json) — Documentation links
- [assets/template-preflight-runtime-hook.sh](assets/template-preflight-runtime-hook.sh) — Shell hook template for runtime/tool version checks
### Related Skills
- [../agents-subagents/SKILL.md](../agents-subagents/SKILL.md) — Agent creation
- [../agents-skills/SKILL.md](../agents-skills/SKILL.md) — Skill creation
- [../ops-devops-platform/SKILL.md](../ops-devops-platform/SKILL.md) — CI/CD integration
## Fact-Checking
- Use web search/web fetch to verify current external facts, versions, pricing, deadlines, regulations, or platform behavior before final answers.
- Prefer primary sources; report source links and dates for volatile information.
- If web access is unavailable, state the limitation and mark guidance as unverified.
This skill provides event-driven hooks for AI coding agents, focused on automating Claude Code or Codex CLI workflows using stdin JSON and decision-control responses. It defines hook events, input/output schemas, execution rules, and practical templates to guard, modify, or augment tool runs. Use it to enforce safety, run fast checks, and integrate agent runs into CI/CD pipelines.
Hooks are configured in a settings.json mapping events to command or prompt handlers. Each hook receives a JSON payload via stdin and runs as a normal user process with a 60s default timeout; matching hooks run in parallel and identical commands are deduplicated. PreToolUse hooks can return structured decision-control JSON (allow/deny/ask and updatedInput) and prompt hooks allow LLM-evaluated decisions for nuanced cases.
How do hooks communicate decisions back to Claude?
Hooks exit 0 and write structured JSON to stdout under hookSpecificOutput; PreToolUse can return permissionDecision and updatedInput fields to allow/modify the tool run.
What happens if a hook fails or times out?
Exit code 2 blocks the action and shows stderr as the message; non-zero other than 2 is non-blocking and visible in verbose mode. Default timeout is 60s; handle failures with clear diagnostics.