hook-script-library
Security-hardened hook script implementations — ready-to-paste templates for security-guard, auto-format, inject-context, session-init, on-stop, and lessons-learned-capture
What this skill does
# Hook Script Library
Six production-ready hook scripts with security hardening. Copy to `.claude/hooks/` and register in `.claude/settings.json`.
## Security Principles Applied
All scripts follow these rules:
- `set -euo pipefail` at the top
- `jq` for JSON (never string concatenation)
- `realpath` for path validation (prevents traversal)
- `flock` for atomic file writes (prevents interleaved concurrent writes)
- Reject filenames starting with `-` (flag injection prevention)
- Hardcoded blocklists only (never source from external files)
- `printf '%s'` for untrusted data, not `echo`
---
## 1. security-guard.sh
Registered on: `PreToolUse` with matcher `Bash`
Blocks hardcoded dangerous commands before Claude executes them. This is defense-in-depth only — use `settings.json` deny list as the primary control.
```bash
#!/usr/bin/env bash
set -euo pipefail
INPUT=$(head -c 65536)
if ! printf '%s' "$INPUT" | jq -e . >/dev/null 2>&1; then
echo '{"decision": "approve"}'
exit 0
fi
TOOL_INPUT=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""')
# Hardcoded blocklist — do NOT source from external files
BLOCKED_PATTERNS=(
"rm -rf /"
"sudo rm"
"mkfs"
"dd if="
"> /dev/sd"
"chmod -R 777"
"curl.*| sh"
"curl.*| bash"
"wget.*| sh"
"wget.*| bash"
)
for pattern in "${BLOCKED_PATTERNS[@]}"; do
if printf '%s' "$TOOL_INPUT" | grep -qF "$pattern"; then
jq -n --arg p "$pattern" '{"decision":"block","reason":("Blocked dangerous command: "+$p)}'
exit 0
fi
done
echo '{"decision": "approve"}'
```
---
## 2. auto-format.sh
Registered on: `PostToolUse` with matcher `Write|Edit`
Runs the appropriate formatter immediately after Claude writes a file. Includes path traversal protection.
```bash
#!/usr/bin/env bash
set -euo pipefail
INPUT=$(head -c 65536)
FILE=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
# Validate: file must exist, be a regular file, be inside project
if [ -z "$FILE" ] || [ ! -f "$FILE" ]; then
echo '{"decision": "approve"}'
exit 0
fi
REAL=$(realpath "$FILE" 2>/dev/null) || { echo '{"decision": "approve"}'; exit 0; }
WORKDIR=$(realpath "$PWD")
# Reject paths outside project root (path traversal guard)
if [[ "$REAL" != "$WORKDIR"/* ]]; then
echo '{"decision": "approve"}'
exit 0
fi
# Reject filenames starting with dash (flag injection guard)
BASENAME=$(basename "$REAL")
if [[ "$BASENAME" == -* ]]; then
echo '{"decision": "approve"}'
exit 0
fi
# Format based on extension
case "$REAL" in
*.ts|*.tsx|*.js|*.jsx|*.json|*.css|*.scss|*.md)
npx prettier --write "$REAL" 2>/dev/null || true ;;
*.py)
black "$REAL" 2>/dev/null || ruff format "$REAL" 2>/dev/null || true ;;
*.rs)
rustfmt "$REAL" 2>/dev/null || true ;;
*.go)
gofmt -w "$REAL" 2>/dev/null || true ;;
*.sh)
shfmt -w "$REAL" 2>/dev/null || true ;;
esac
echo '{"decision": "approve"}'
```
---
## 3. inject-context.sh
Registered on: `UserPromptSubmit`
Injects dynamic context (date, branch, uncommitted file count) on every prompt. Claude receives this as additional context before processing.
```bash
#!/usr/bin/env bash
set -euo pipefail
# Inject dynamic context — stdout is added to Claude's context
DATE=$(date '+%Y-%m-%d %H:%M')
BRANCH=$(git branch --show-current 2>/dev/null || echo "no-git")
UNCOMMITTED=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
LAST_COMMIT=$(git log --oneline -1 2>/dev/null || echo "no commits")
echo "[Session Context] Date: $DATE | Branch: $BRANCH | Uncommitted: $UNCOMMITTED files | Last commit: $LAST_COMMIT"
echo '{"decision": "approve"}'
```
**How it works:** On `UserPromptSubmit`, stdout is prepended to the user's message as context. Use this for date injection, active branch, workspace state — anything Claude should know before processing each turn.
---
## 4. session-init.sh
Registered on: `SessionStart`
Fires when a session begins or resumes. Outputs status information to stderr (shown as system messages) and checks for stale memory files.
```bash
#!/usr/bin/env bash
set -euo pipefail
echo "Session started: $(date '+%Y-%m-%d %H:%M')" >&2
echo "Branch: $(git branch --show-current 2>/dev/null || echo 'no-git')" >&2
echo "Last commit: $(git log --oneline -1 2>/dev/null || echo 'no commits')" >&2
# Warn about stale memory rotation
LESSONS=".claude/rules/lessons-learned.md"
if [ -f "$LESSONS" ]; then
LINES=$(wc -l < "$LESSONS")
if [ "$LINES" -gt 200 ]; then
echo "WARNING: lessons-learned.md has $LINES lines — run /cc-memory --rotate to prune resolved entries" >&2
fi
fi
echo '{"decision": "approve"}'
```
---
## 5. on-stop.sh
Registered on: `Stop`
Fires when Claude finishes a response turn. Use for reminders, notifications, or light cleanup.
```bash
#!/usr/bin/env bash
set -euo pipefail
# Remind about uncommitted work at end of each turn
UNCOMMITTED=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
if [ "$UNCOMMITTED" -gt 0 ]; then
echo "Reminder: $UNCOMMITTED uncommitted files" >&2
fi
echo '{"decision": "approve"}'
```
---
## 6. lessons-learned-capture.sh
Registered on: `PostToolUseFailure`
The most important hook. Auto-captures every tool failure to `.claude/rules/lessons-learned.md` for the self-healing loop. Uses `flock` for atomic writes and sanitizes inputs to prevent injection.
```bash
#!/usr/bin/env bash
set -euo pipefail
INPUT=$(head -c 65536)
if ! printf '%s' "$INPUT" | jq -e . >/dev/null 2>&1; then
echo '{"decision": "approve"}'
exit 0
fi
TOOL=$(printf '%s' "$INPUT" | jq -r '.tool_name // ""')
ERROR=$(printf '%s' "$INPUT" | jq -r '.error // ""')
if [ -z "$ERROR" ] || [ "$ERROR" = "null" ]; then
echo '{"decision": "approve"}'
exit 0
fi
# Sanitize: strip shell metacharacters to prevent injection
SAFE_TOOL=$(printf '%s' "$TOOL" | head -c 50 | tr -d '`$()\\!"'"'"'')
SAFE_ERROR=$(printf '%s' "$ERROR" | head -c 200 | tr -d '`$()\\!"'"'"'')
TIMESTAMP=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
LESSONS=".claude/rules/lessons-learned.md"
# flock ensures atomic append — prevents interleaved writes if hooks run concurrently
(
flock -x 200
printf '\n### Error: %s failure (%s)\n- **Tool:** %s\n- **Error:** %s\n- **Status:** NEEDS_FIX - Claude should document the fix here after resolving\n' \
"$SAFE_TOOL" "$TIMESTAMP" "$SAFE_TOOL" "$SAFE_ERROR" \
>> "$LESSONS"
) 200>/tmp/lessons-learned.lock
echo '{"decision": "approve"}'
```
---
## settings.json — Register All Six
```json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/security-guard.sh" }]
}
],
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/auto-format.sh" }]
}
],
"PostToolUseFailure": [
{
"matcher": "*",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/lessons-learned-capture.sh" }]
}
],
"Stop": [
{
"matcher": "",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/on-stop.sh" }]
}
],
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/inject-context.sh" }]
}
],
"SessionStart": [
{
"matcher": "",
"hooks": [{ "type": "command", "command": "bash .claude/hooks/session-init.sh" }]
}
]
}
}
```
---
## Quick Deploy
```bash
# Create hooks directory
mkdir -p .claude/hooks
# Make all hooks executable after writing
chmod +x .claude/hooks/*.sh
# Verify hook syntax before registering
bash -n .claude/hooks/security-guard.sh && echo "OK"
bash -n .claude/hooks/lessons-learned-capture.sh && echo "OK"
```
## Stack-Specific Additional Hooks
| Detected Stack | Hook | Event | Matcher | Action |
|----------------|------|-------|---------|--------|
| TypeScript | `auto-typecheck.sh` | PostToolUse | `Write\|Edit` | `tsc --noEmit` |
| ESLint | `aRelated in Security
mac-ops
IncludedComprehensive macOS workstation operations — diagnose kernel panics, identify failing drives, audit launchd startup items, decode wake reasons, triage TCC permission denials, manage APFS snapshots, recover from no-boot. Use for: Mac is slow, slow bootup, won't boot, kernel panic, kernel_task hot, mds_stores CPU, photoanalysisd, cloudd, login loop, gray screen, sleep wake failure, drive failing, IO errors, APFS snapshots eating space, Time Machine local snapshots, Spotlight indexing, launchd, LaunchAgent, LaunchDaemon, login items, TCC permissions, Full Disk Access, Screen Recording denied, Gatekeeper, quarantine, com.apple.quarantine, app is damaged, helper tool, /Library/PrivilegedHelperTools, pmset, wake reasons, dark wake, sysdiagnose, panic.ips, DiagnosticReports, configuration profile, MDM profile, remote diagnostics over SSH.
a11y-audit
IncludedRun accessibility audits on web projects combining automated scanning (axe-core, Lighthouse) with WCAG 2.1 AA compliance mapping, manual check guidance, and structured reporting. Output is configurable: markdown report only, markdown plus machine-readable JSON, or markdown plus issue tracker integration. Use this skill whenever the user mentions "accessibility audit", "a11y audit", "WCAG audit", "accessibility check", "compliance scan", or asks to check a web project for accessibility issues. Also trigger when the user wants to verify WCAG conformance or map findings to a specific standard (CAN-ASC-6.2, EN 301 549, ADA/AODA).
erpclaw
IncludedAI-native ERP system with self-extending OS. Full accounting, invoicing, inventory, purchasing, tax, billing, HR, payroll, advanced accounting (ASC 606/842, intercompany, consolidation), and financial reporting. 413 actions across 14 domains, 43 expansion modules. Constitutional guardrails, adversarial audit, schema migration. Double-entry GL, immutable audit trail, US GAAP.
assess
IncludedAssesses and rates quality 0-10 across multiple dimensions (correctness, maintainability, security, performance, testability, simplicity) with pros/cons analysis. Compares against project conventions and prior decisions from memory. Produces structured evaluation reports with actionable improvement suggestions. Use when evaluating code, designs, architectures, or comparing alternative approaches.
spring-boot-security-jwt
IncludedProvides JWT authentication and authorization patterns for Spring Boot 3.5.x covering token generation with JJWT, Bearer/cookie authentication, database/OAuth2 integration, and RBAC/permission-based access control using Spring Security 6.x. Use when implementing authentication or authorization in Spring Boot applications.
code-hardcode-audit
IncludedDetect hardcoded values, magic numbers, and leaked secrets. TRIGGERS - hardcode audit, magic numbers, PLR2004, secret scanning.