Development
Hook
Hooks
What claude-code-config runs automatically, and when. A hook is a command Claude Code fires at a fixed moment, without you asking for it.
Where it lives
- hooks/enforce-package-manager.shGitHub
Read the script
#!/bin/bash set -euo pipefail # EXAMPLE: PreToolUse hook — blocks npm in projects that use pnpm. # Adapt for any "use X not Y" convention (e.g., yarn vs npm, uv vs pip). CMD=$(jq -r '.tool_input.command // empty') [[ -z "$CMD" ]] && exit 0 # Only enforce if this project uses pnpm [[ ! -f "${CLAUDE_PROJECT_DIR}/pnpm-lock.yaml" ]] && exit 0 if echo "$CMD" | grep -qE '^npm\s'; then echo "BLOCKED: This project uses pnpm, not npm. Use pnpm instead." >&2 exit 2 fi exit 0 - hooks/log-gam.shGitHub
Read the script
#!/bin/bash set -euo pipefail # EXAMPLE: PostToolUse hook — logs GAM (Google Apps Manager) write operations # to JSONL. Adapt the verb patterns for any CLI tool where you want an audit # trail of mutations. See README.md for wiring instructions. INPUT=$(cat) COMMAND=$(echo "${INPUT}" | jq -r '.tool_input.command // empty') [[ -z "${COMMAND}" ]] && exit 0 [[ "${COMMAND}" != *'gam7/gam '* ]] && exit 0 # Verb lists verified against GamCommands.txt v7.33.00 READ_PATTERN='(print|show|info|get|list|report|check|version|help)' WRITE_PATTERN='(create|add|update|delete|remove|suspend|unsuspend|wipe|sync|move|transfer|trash|purge|enable|disable|deprovision)' GAM_ARGS="${COMMAND#*gam7/gam }" FIRST_WORD="${GAM_ARGS%% *}" # Skip read operations echo "${FIRST_WORD}" | grep -qiE "^${READ_PATTERN}$" && exit 0 # Match write verb ACTION=$(echo "${GAM_ARGS}" | grep -oiE "(^|[[:space:]])${WRITE_PATTERN}([[:space:]]|$)" \ | head -1 | tr -d ' ' || true) [[ -z "${ACTION}" ]] && exit 0 # Log the mutation EXIT_CODE=$(echo "${INPUT}" | jq -r '.tool_result.exit_code // 0') [[ "${EXIT_CODE}" == "0" ]] && STATUS="success" || STATUS="failed" LOG_FILE="${CLAUDE_PROJECT_DIR}/google/.changelog-raw.jsonl" mkdir -p "$(dirname "${LOG_FILE}")" jq -nc \ --arg ts "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \ --arg action "${ACTION}" \ --arg command "${COMMAND}" \ --arg status "${STATUS}" \ '{timestamp: $ts, action: $action, command: $command, status: $status}' \ >> "${LOG_FILE}" # Remind the operator if [[ "${STATUS}" == "success" ]]; then echo "GAM MUTATION: ${ACTION} — logged to ${LOG_FILE}" fi exit 0
Read the script before you install anything that runs on your machine. This is the one part of a plugin that acts without being asked.
Ships withclaude-code-config
Opinionated defaults, documentation, and workflows for Claude Code at Trail of Bits. Covers sandboxing, permissions, hooks, skills, MCP servers, and usage patterns we've found effective across security audits, development, and research.
Get the whole plugin

