Claude Code Hooks Builder: Auto Format/Lint/Tests After Every Edit
Uses hooks in .claude/settings.json to automatically run formatting, linting, type-checking, or tests at specific Claude Code lifecycle events (PostToolUse after an edit, PreToolUse before running a command, Stop when wrapping up)—producing correct JSON config plus an executable hook script, with exit code 2 hard-blocking dangerous actions.
CLAUDE.md 只是『建議』,模型不一定每次照做;hooks 是『強制』,由 harness 在固定事件確實執行。這支 meta-prompt 幫你產出正確的 .claude/settings.json hook 設定+腳本:Claude 每改完檔自動 prettier+lint,跑 rm -rf 前直接 exit 2 擋下。
[ Log in to see the full prompt ]Sign up free to see the full prompt, copy it, save it, and join the discussion. Free content unlocks on login; Pro content is a separate subscription.
[When to use] When something 'absolutely must happen and can't rely on the model's self-discipline'—for example, formatting must run after every edit, tests must pass before wrapping up, or certain dangerous commands must be blocked outright. The official position is explicit: CLAUDE.md is a 'suggestion' the model tries to follow, with no guarantee of execution; to enforce something at a fixed point, use hooks. [Why it works] (1) It maps each goal to the correct event: PostToolUse (matcher Edit|Write) runs formatting/linting after a file edit, PreToolUse (matcher Bash) is the only place that can use exit 2 to 'block' a tool call, and Stop serves as a final testing gate; (2) it provides the real settings.json structure (hooks→event→matcher→command) and the real stdin fields (tool_name / tool_input / cwd)—a command hook reads JSON from stdin and controls flow via exit code (0 = pass, 2 = block, with stderr returned to Claude as the reason); (3) PostToolUse only touches the specific file recorded in tool_input, not the whole repo. [Tips] Hooks execute with your full permissions automatically, and project-level hooks only take effect after accepting the workspace-trust prompt—so keep scripts minimal, quote your variables, and never eval tool_input directly. To verify: edit a file by hand and check that formatting ran, or deliberately type a forbidden command and confirm it gets blocked with exit 2.
// .claude/settings.json (merged) { "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/format.sh", "timeout": 30 } ] } ], "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/guard.sh", "timeout": 5 } ] } ] } } # .claude/hooks/format.sh #!/usr/bin/env bash set -euo pipefail file=$(jq -r '.tool_input.file_path // empty') [[ "$file" == *.ts || "$file" == *.tsx ]] || exit 0 prettier --write "$file" >/dev/null if ! eslint "$file"; then echo "eslint failed on $file — fix before continuing" >&2; exit 2; fi # .claude/hooks/guard.sh #!/usr/bin/env bash cmd=$(jq -r '.tool_input.command // empty') if echo "$cmd" | grep -Eq 'rm -rf /|git push .*--force'; then echo "Blocked dangerous command: $cmd" >&2; exit 2 fi exit 0
Suno Engineer's Mindset: 4 Steps to a Song That Doesn't Sound Like AI
A studio engineer's breakdown of Suno's fatal weaknesses (fried vocals, high-frequency artifacts), plus a 4-step DAW workflow and a Suno Studio cleanup prompt.
5 Claude Weekly Workflows That Stuck After 6 Months
Proposal generator / meeting processor / content repurposer / Friday review / shutdown reset — out of 40 I tried, only these 5 survived, each saving 30+ minutes per run.