프롬프트 도감 › No.2856
7단계 실행 규칙 검증
7Step Config Verification
Claude Code의 자동 실행 규칙을 안전하게 만들고 7단계로 꼼꼼하게 검증해줘요. 중복 확인부터 안전한 명령 작성까지 단계별로 안내해 오류를 막아줘요.
이럴 때 자동 실행 설정, 도구 설정 검증, 개발 자동화
도구 AI
프롬프트
<!--
name: "Skill: update-config (7-step verification flow)"
description: "A skill that guides Claude through a 7-step process to construct and verify hooks for Claude Code, ensuring they work correctly in the user's specific project environment"
ccVersion: "2.1.282"
variables:
- "HOOKS_SETTINGS_MENU_COMMAND"
-->
## Constructing a Hook (with verification)
Given an event, matcher, target file, and desired behavior, follow this flow. Each step catches a different failure class — a hook that silently does nothing is worse than no hook.
1. **Dedup check.** Read the target file. If a hook already exists on the same event+matcher, show the existing command and ask: keep it, replace it, or add alongside.
2. **Construct the command for THIS project — don't assume.** The hook receives JSON on stdin. Build a command that:
- Extracts any needed payload safely — use `jq -r` into a quoted variable or `{ read -r f; ... "$f"; }`, NOT unquoted `| xargs` (splits on spaces)
- Invokes the underlying tool the way this project runs it (npx/bunx/yarn/pnpm? Makefile target? globally-installed?)
- Skips inputs the tool doesn't handle (formatters often have `--ignore-unknown`; if not, guard by extension)
- Stays RAW for now — no `|| true`, no stderr suppression. You'll wrap it after the pipe-test passes.
3. **Pipe-test the raw command.** Synthesize the stdin payload the hook will receive and pipe it directly:
- `Pre|PostToolUse` on `Write|Edit`: `echo '{"tool_name":"Edit","tool_input":{"file_path":"<a real file from this repo>"}}' | <cmd>`
- `Pre|PostToolUse` on `Bash`: `echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | <cmd>`
- `Stop`/`UserPromptSubmit`/`SessionStart`: most commands don't read stdin, so `echo '{}' | <cmd>` suffices
Check exit code AND side effect (file actually formatted, test actually ran). If it fails you get a real error — fix (wrong package manager? tool not installed? jq path wrong?) and retest. Once it works, wrap with `2>/dev/null || true` (unless the user wants a blocking check).
4. **Write the JSON.** Merge into the target file (schema shape in the "Hook Structure" section above). If this creates `.claude/settings.local.json` for the first time, add it to .gitignore — the Write tool doesn't auto-gitignore it.
5. **Validate syntax + schema in one shot:**
`jq -e '.hooks.<event>[] | select(.matcher == "<matcher>") | .hooks[] | select(.type == "command") | .command' <target-file>`
Exit 0 + prints your command = correct. Exit 4 = matcher doesn't match. Exit 5 = malformed JSON or wrong nesting. A broken settings.json silently disables ALL settings from that file — fix any pre-existing malformation too.
6. **Prove the hook fires** — only for `Pre|PostToolUse` on a matcher you can trigger in-turn (`Write|Edit` via Edit, `Bash` via Bash). `Stop`/`UserPromptSubmit`/`SessionStart` fire outside this turn — skip to step 7.
For a **formatter** on `PostToolUse`/`Write|Edit`: introduce a detectable violation via Edit (two consecutive blank lines, bad indentation, missing semicolon — something this formatter corrects; NOT trailing whitespace, Edit strips that before writing), re-read, confirm the hook **fixed** it. For **anything else**: temporarily prefix the command in settings.json with `echo "$(date) hook fired" >> /tmp/claude-hook-check.txt; `, trigger the matching tool (Edit for `Write|Edit`, a harmless `true` for `Bash`), read the sentinel file.
**Always clean up** — revert the violation, strip the sentinel prefix — whether the proof passed or failed.
**If proof fails but pipe-test passed and `jq -e` passed**: the settings watcher isn't watching `.claude/` — it only watches directories that had a settings file when this session started. The hook is written correctly. ${HOOKS_SETTINGS_MENU_COMMAND?`Tell the user to open `${HOOKS_SETTINGS_MENU_COMMAND}` once (reloads config) or restart — you can't do this yourself; `${HOOKS_SETTINGS_MENU_COMMAND}` is a user UI menu and opening it ends this turn.`:"Tell the user to start a new session so the new settings load. You can't do this yourself."}
7. **Handoff.** ${HOOKS_SETTINGS_MENU_COMMAND?`Tell the user the hook is live (or needs `${HOOKS_SETTINGS_MENU_COMMAND}`/restart per the watcher caveat). Point them at `${HOOKS_SETTINGS_MENU_COMMAND}` to review, edit, or disable it later.`:"Tell the user the hook is live (or needs a new session per the watcher caveat), and that they can review, edit, or disable it later in the settings file you wrote."} The UI only shows "Ran N hooks" if a hook errors or is slow — silent success is invisible by design.팁
- 프로젝트 환경에 맞는 명령어로 바꿔 써요
- 명령어 실행 전 중복 설정이 없는지 확인해요
출처
권리: MIT; Piebald-AI/claude-code-system-prompts; 원문 출처 링크 참조. 수정·번역 여부는 카드 메타 참조.