
Claude Codeããåæã«ãã£ãŠããããèšå®è¡ â hooksèªååãã³ãã¬ãŒã5éž
Claude Codeã§ã³ãŒããæžããŠããã£ãåŸãæ¯åãã£ãŠããããšã
lintãèµ°ãããããã©ãŒããã¿ãŒããããã
ã.envã«å€ãªå€æŽå
¥ã£ãŠãªãããããšç®èŠãã§ãã¯ããã
AIãæžããŠãããã³ãŒãã«å¯ŸããŠã人éãæåã§å質ãã§ãã¯ããããŠããã
䟿å©ãªãã ãã©ãããã®äœæ¥ãèªååã§ããªãããªããšæã£ãããšããã人ã¯å€ãã¯ãã§ãã
ã§ããŸãã
Claude Codeã®hooksãšããæ©èœã䜿ãã°ãããã¡ã€ã«ãä¿åãããèªåã§ãã©ãŒããããããã.envãè§Šãããšããããããã¯ããããäœæ¥ãçµãã£ããéç¥ããããšãã£ãåŠçããèšå®ãã¡ã€ã«1ã€ã§å®çŸã§ããŸãã
ããã°ã©ãã³ã°ã®ç¥èã¯æå°éã§å€§äžå€«ã§ãã
JSONã®æžãæ¹ããããã°åãããŸãã
ãã®èšäºã§ã¯ãå®éã«æ¥åã§äœ¿ã£ãŠããhooksèšå®ãã³ãã¬ãŒãã5ã€ããã®ãŸãŸæž¡ããŸãã
ã³ããããŠé
眮ããã ãã§äœ¿ããŸãã
å ããŠãããªãããæžãã®ããã®èšèšæå³ã解説ããã®ã§ãèªåã§æ°ããhooksãäœããããã«ããªããŸãã
ãã®èšäºã§æã«å ¥ããã®
ãã³ãã¬ãŒãäžåŒïŒzipïŒ
ã³ãŒãå質ã¬ãŒãïŒä¿åæã«èªålint + formatïŒ
æ©å¯ãã¡ã€ã«ä¿è·ïŒ.envçãžã®å€æŽãããã¯ïŒ
äœæ¥ãã°ïŒã³ãã³ãå®è¡ã®èšé²ïŒ
å®äºéç¥ïŒäœæ¥çµäºæã«ãã¹ã¯ãããéç¥ïŒ
ã³ãããåãã§ãã¯ïŒã³ãããã¡ãã»ãŒãžã®å質確èªïŒ
èšèšè§£èª¬
åhooksã®èšèšæå³ãšåäœã®ä»çµã¿
ã«ã¹ã¿ãã€ãºã®ã³ã
èªåã§hooksãäœããšãã®èãæ¹
hooks ãšã¯äœã
ç¥ã£ãŠãã人ã¯é£ã°ããŠãã ããã
hooksã¯ãClaude Codeã®åäœã®ãéäžãã«ãããªããæ±ºããåŠçãæã¿èŸŒãæ©èœã§ãã
ããšãã°:
ãã¡ã€ã«ãæžã蟌ãã çŽåŸã« â ãã©ãŒããã¿ãŒãèªåå®è¡
ã³ãã³ããå®è¡ããçŽåã« â å±éºãªæäœããããã¯
å šãŠã®äœæ¥ãçµãã£ãæã« â éç¥ãé£ã°ã
ãã€ã³ãã¯ãAIã®å€æã«é Œããªãããšããã§ãã
CLAUDE.mdã«ããã©ãŒãããããŠãããšæžããŠããå¿ããããšããããŸãã
hooksãªã確å®ã«å®è¡ãããŸãã
èšå®ãã¡ã€ã«ã«æžããã«ãŒã«ã¯ã100%å®ãããã
skillsãšã®éã
ååã®èšäºã§ç޹ä»ããskillsã¯ãåŒã³åºããšåããã®ãã
èªåã§ `/meeting-summary` ãšæã£ãŠåããŠåããŸãã
hooksã¯ãåæã«åããã®ãã
ãã¡ã€ã«ä¿åãã³ãã³ãå®è¡ãšãã£ãã€ãã³ããããªã¬ãŒã«ãèªåã§å®è¡ãããŸãã
skills â èªåã§åŒã¶ïŒèœåçïŒ
hooks â åæã«åãïŒèªåçïŒè£å®é¢ä¿ã«ãããŸããäž¡æ¹äœ¿ããšåŒ·ãã
èšå®å Žæ
`settings.json` ã«æžããŸããé çœ®å Žæã¯2ã€ã
å šãããžã§ã¯ãå ±éïŒèªåçšïŒ
~/.claude/settings.jsonWindows ã®å Žå㯠`%USERPROFILE%.claude\settings.json` ã§ãã
ç¹å®ãããžã§ã¯ãã ãïŒããŒã å ±æåãïŒ
ãããžã§ã¯ã/.claude/settings.jsonåæç¥è
hooksã§ã¯ãããŒã¿ã®ããåãã«JSON圢åŒã䜿ããŸãã
ãã³ãã¬ãŒãå
ã§ç»å Žãã `jq` ã¯ãã³ãã³ãã©ã€ã³ã§JSONãåŠçããããã®ããŒã«ã§ãã
å€ãã®ç°å¢ã«ããªã€ã³ã¹ããŒã«ãããŠããŸããããªããã° `brew install jq`ïŒmacOSïŒã `sudo apt install jq`ïŒLinuxïŒã§ã€ã³ã¹ããŒã«ã§ããŸããWindowsã®å Žå㯠`choco install jq` ããå
¬åŒãµã€ãããããŠã³ããŒãããŠãã ããã
ãã³ãã¬ãŒã2ãš5ã¯Pythonã§æžããŠããã®ã§ãjqããªããŠãåããŸãã
hooksãåãã¿ã€ãã³ã°ïŒã€ãã³ãäžèЧïŒ
hooksã¯ããã€åããããæå®ã§ããŸããäž»ãªã€ãã³ãã¯ãã®6ã€ã
PreToolUse â ããŒã«å®è¡ã®çŽå
ãã¡ã€ã«æžã蟌ã¿ãã³ãã³ãå®è¡ãWebæ€çŽ¢ãªã©ãClaude CodeãããŒã«ã䜿ãçŽåã«åããŸããexit code 2ãè¿ããšãããã¯ã§ããã®ã§ããããã«ã¯è§Šãããªãããšããã¬ãŒãã«äœ¿ããŸãã
PostToolUse â ããŒã«å®è¡ã®çŽåŸ
ãã¡ã€ã«ã®ä¿ååŸã«ãã©ãŒããã¿ãŒãèµ°ããããã³ãã³ãå®è¡åŸã«ãã°ãåãããšãã£ããåŸåŠçãã«äœ¿ããŸããäžçªäœ¿çšé »åºŠãé«ãã€ãã³ãã§ãã
Stop â äœæ¥å®äºæ
Claude Codeãåçãçµããã¿ã€ãã³ã°ã§åããŸãããçµãã£ãããã®éç¥ãé£ã°ãã®ã«äŸ¿å©ã§ãã
Notification â éç¥çºçæ
Claude Codeãå
¥åãåŸ
ã£ãŠãããšãïŒèš±å¯ã®ç¢ºèªãªã©ïŒã«åããŸããåžãå€ããŠãããšãã§ãæ°ã¥ããããã«éç¥ãèšå®ã§ããŸãã
UserPromptSubmit â ããã³ããéä¿¡æ
ããªããã¡ãã»ãŒãžãéã£ãçŽåŸãClaudeãåŠçãå§ããåã«åããŸããå
¥åã®ååŠçã«äœ¿ããŸãã
SessionStart â ã»ãã·ã§ã³éå§æ
Claude Codeãèµ·åãããšãããŸãã¯æ¢åã»ãã·ã§ã³ãåéãããšãã«åããŸããç°å¢ãã§ãã¯ãåæååŠçã«äœ¿ããŸãã
ã©ããªäººã«åããŠããã
ãã§ã«Claude Codeã䜿ã£ãŠãã人
æ¯åæåã§lint/formatãèµ°ãããŠãã
ã.envã倿ŽãããŠå°ã£ããçµéšããã
ããŒã ã§éçºåè³ªãæšæºåããã
Claude Codeããã£ãšæŽ»çšããã人
skillsã¯èšå®ãããæ¬¡ã®ã¹ããããæ¢ããŠãã
CLAUDE.mdã®ããé¡ããã§ã¯ãªãã匷å¶ããããã«ãŒã«ããã
äœæ¥ãã°ãæ®ããŠã³ã³ãã©ã€ã¢ã³ã¹å¯Ÿå¿ããã
ããããã¯å®éã®ãã³ãã¬ãŒããšãèšèšæå³ãã«ã¹ã¿ãã€ãºã®ãã€ã³ãã解説ããŸãã
ãã³ãã¬ãŒãã®ããŠã³ããŒã
以äžããzipãã¡ã€ã«ãããŠã³ããŒãããŠãã ããã
äžèº«ã®æ§æ
hooks-automation-pack/
âââ README.md â äœ¿ãæ¹ããã¥ã¢ã«
âââ settings-all.json â å
šãã³ãã¬ãŒãçµ±åç
âââ settings-quality.json â ãã³ãã¬ãŒã1ã®ã¿
âââ settings-protection.json â ãã³ãã¬ãŒã2ã®ã¿
âââ settings-logging.json â ãã³ãã¬ãŒã3ã®ã¿
âââ settings-notification.json â ãã³ãã¬ãŒã4ã®ã¿
âââ settings-commit.json â ãã³ãã¬ãŒã5ã®ã¿
âââ hooks/
âââ file_protector.py â æ©å¯ãã¡ã€ã«ä¿è·ã¹ã¯ãªãã
âââ commit_checker.py â ã³ãããã¡ãã»ãŒãžãã§ãã¯ã¹ã¯ãªãã
âââ format_runner.sh â ãã©ãŒããã¿ãŒå®è¡ã¹ã¯ãªããèšçœ®æ¹æ³
zipãè§£å
䜿ããããã³ãã¬ãŒãã®JSONã®äžèº«ããèªåã® `settings.json` ã«ã³ããŒ
ã¹ã¯ãªãããå¿ èŠãªãã³ãã¬ãŒã㯠`hooks/` ãã©ã«ãããããžã§ã¯ãã® `.claude/hooks/` ã«ã³ããŒ
# å
šãããžã§ã¯ãå
±éã§äœ¿ãå Žå
# ~/.claude/settings.json ã«çµ±åçã®å
容ãã³ããŒ
# ç¹å®ãããžã§ã¯ãã ãã§äœ¿ãå Žå
mkdir -p .claude/hooks
cp hooks-automation-pack/hooks/* .claude/hooks/
# .claude/settings.json ã«ãã³ãã¬ãŒãã®å
容ãã³ããŒå šéšäœ¿ãå¿ èŠã¯ãããŸãããå¿ èŠãªãã®ã ãéžãã§ãã ããã
ãã³ãã¬ãŒã1: ã³ãŒãå質ã¬ãŒã
ãã¡ã€ã«ãä¿åãããã³ã«ãèªåã§ãã©ãŒããã¿ãŒãšlinterãå®è¡ããŸãã
äœãèµ·ããã
Claude Codeããã¡ã€ã«ãæžã蟌ã â çŽåŸã«ãã©ãŒããã¿ãŒãèµ°ã â ã€ã³ãã³ããäœåãªç©ºçœãèªåä¿®æ£ããã
æåã§ `prettier` ã `ruff` ãèµ°ãããå¿ èŠããªããªããŸãã
èšå®
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/format_runner.sh"
}
]
}
]
}
}ãã©ãŒããã¿ãŒã¹ã¯ãªããïŒformat_runner.shïŒ
#!/bin/bash
# ä¿åããããã¡ã€ã«ã®æ¡åŒµåã«å¿ããŠãã©ãŒããã¿ãŒãå®è¡
# stdin ãã JSON ãåãåãïŒClaude Code hooks ã®æšæºä»æ§ïŒ
FILE_PATH=$(jq -r '.tool_input.file_path // empty')
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
exit 0
fi
EXT="${FILE_PATH##*.}"
case "$EXT" in
ts|tsx|js|jsx)
if command -v npx &> /dev/null; then
npx prettier --write "$FILE_PATH" 2>/dev/null
fi
;;
py)
if command -v ruff &> /dev/null; then
ruff format "$FILE_PATH" 2>/dev/null
ruff check --fix "$FILE_PATH" 2>/dev/null
fi
;;
go)
if command -v gofmt &> /dev/null; then
gofmt -w "$FILE_PATH" 2>/dev/null
fi
;;
css|scss|json|md)
if command -v npx &> /dev/null; then
npx prettier --write "$FILE_PATH" 2>/dev/null
fi
;;
esacèšèšæå³
ãªã PostToolUse + Edit|Write ã
ãã¡ã€ã«ã倿ŽããããçŽåŸãã«èµ°ããããã®ã§ PostToolUseã
matcher ã« `Edit|Write` ãæå®ããããšã§ããã¡ã€ã«æäœã®ãšãã ãçºç«ããŸãã
Webæ€çŽ¢ãBashã³ãã³ãã®ãšãã«ã¯åããªãã
ãªãã¹ã¯ãªããã«åãåºãã
settings.json ã«çŽæ¥ã³ãã³ããæžãããšãã§ããŸãããããžãã¯ãè€éã«ãªããšJSONãšã¹ã±ãŒããå°çã«ãªããŸããã¹ã¯ãªããã«åãåºãã°ããã¹ããããããã
ãªã `command -v` ã§ãã§ãã¯ããã
ãã©ãŒããã¿ãŒãã€ã³ã¹ããŒã«ãããŠããªãç°å¢ã§ãšã©ãŒã«ããªãã
ããŒã ã¡ã³ããŒã®ç°å¢å·®ãåžåã§ããŸãã
ã«ã¹ã¿ãã€ãº
Rust ã远å ããã â `rs` ã®ã±ãŒã¹ã§ `rustfmt` ãåŒã¶
ç¹å®ãã£ã¬ã¯ããªã ã察象ã«ããã â `FILE_PATH` ã®ãã¬ãã£ãã¯ã¹ã§æ¡ä»¶åå²
ãã©ãŒãããã ãã§ãªããã¹ããèµ°ãããã â ã¹ã¯ãªããã« `pytest` çã远å ïŒãã ãé ããªãã®ã§æ³šæïŒ
ãã³ãã¬ãŒã2: æ©å¯ãã¡ã€ã«ä¿è·
`.env`ã`credentials.json`ã`package-lock.json` ãªã©ãè§Šãããããªããã¡ã€ã«ãžã®å€æŽããããã¯ããŸãã
äœãèµ·ããã
Claude Codeãä¿è·å¯Ÿè±¡ãã¡ã€ã«ãç·šéããããšãã â ãããã¯ããã â Claude Codeã«ããã®ãã¡ã€ã«ã¯ç·šéã§ããŸããããšãã£ãŒãããã¯ããã
èšå®
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/file_protector.py"
}
]
}
]
}
}ä¿è·ã¹ã¯ãªããïŒfile_protector.pyïŒ
#!/usr/bin/env python3
"""æ©å¯ãã¡ã€ã«ãžã®ç·šéããããã¯ããhooksã¹ã¯ãªãã"""
import json
import sys
# ä¿è·å¯Ÿè±¡ã®ãã¿ãŒã³ïŒå¿
èŠã«å¿ããŠç·šéïŒ
PROTECTED_PATTERNS = [
'.env',
'.env.local',
'.env.production',
'credentials.json',
'secrets.yaml',
'package-lock.json',
'pnpm-lock.yaml',
'yarn.lock',
'.git/',
]
try:
data = json.load(sys.stdin)
file_path = data.get('tool_input', {}).get('file_path', '')
for pattern in PROTECTED_PATTERNS:
if pattern in file_path:
# exit code 2 = ãããã¯ïŒClaude Codeã«çç±ãäŒããïŒ
print(f"BLOCKED: '{file_path}' is a protected file. "
f"Matched pattern: '{pattern}'. "
f"Edit this file manually if needed.")
sys.exit(2)
# exit code 0 = èš±å¯
sys.exit(0)
except Exception as e:
# ãšã©ãŒæã¯å®å
šåŽã«åãïŒèš±å¯ïŒ
print(f"Warning: file_protector error: {e}", file=sys.stderr)
sys.exit(0)èšèšæå³
ãªã PreToolUse ã
ãç·šéãããåãã«ãããã¯ããããããPostToolUse ã ãšæ¢ã«æžãæããåŸã«ãªã£ãŠããŸããŸããããŒã«ã®å®è¡ãæ¢ããããã®ã¯ PreToolUse ã ãã
ãªã exit code 2 ã
exit codeïŒçµäºã³ãŒãïŒã¯ããã°ã©ã ããã©ãçµãã£ããããæ°åã§è¿ãä»çµã¿ã§ããClaude Code hooks ã§ã¯ä»¥äžã®æå³ã«ãªããŸãã
exit code 0 â èš±å¯ïŒæ£åžžã«çµäºãåé¡ãªãïŒ
exit code 2 â ãããã¯ïŒç»é¢ã«åºåããå 容ãClaude Codeã«ãã£ãŒãããã¯ãããããªããããã¯ãããããäŒããïŒ
ããä»¥å€ â ãšã©ãŒïŒããã¯èªäœã®åé¡ãšããŠæ±ãããïŒ
ãªãããšã©ãŒæã¯èš±å¯ãã
hooks ã®ãã°ã§ä»äºãæ¢ãŸãã®ãäžçªå°ããŸããä¿è·ã¹ã¯ãªãããå£ãããšãã¯ããã©ãŒã«ããã¯ãšããŠèš±å¯åŽã«åãããã°ã§èŠåãåºããŠãåŸããæ°ã¥ããããã«ããŠãããŸãã
ã«ã¹ã¿ãã€ãº
Dockerfile ãä¿è·ããã â `PROTECTED_PATTERNS` ã« `'Dockerfile'` ã远å
`src/config/` 以äžãäžžããšä¿è· â `'src/config/'` ã远å
ããã¯ãã¡ã€ã«ã®ä¿è·ã¯äžèŠ â `package-lock.json` çãåé€
ãã³ãã¬ãŒã3: äœæ¥ãã°
Claude Codeãå®è¡ããã³ãã³ããç·šéãããã¡ã€ã«ããã¹ãŠãã°ã«èšé²ããŸãã
äœãèµ·ããã
Bashã³ãã³ãã®å®è¡ããã¡ã€ã«ã®ç·šé â ãã°ãã¡ã€ã«ã«èªåèšé² â åŸãããäœããã£ãããã確èªã§ãã
èšå®
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\"[\" + (now | strftime(\"%Y-%m-%d %H:%M:%S\")) + \"] CMD: \" + .tool_input.command + \" -- \" + (.tool_input.description // \"no description\")' >> .claude/activity.log"
}
]
},
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '\"[\" + (now | strftime(\"%Y-%m-%d %H:%M:%S\")) + \"] EDIT: \" + .tool_input.file_path' >> .claude/activity.log"
}
]
}
]
}
}ãã°ã®åºåäŸ
[2026-02-16 14:32:15] CMD: npm run build -- Build the project
[2026-02-16 14:32:18] EDIT: src/components/Button.tsx
[2026-02-16 14:33:01] CMD: npm run test -- Run tests
[2026-02-16 14:33:45] EDIT: src/utils/helpers.tsèšèšæå³
ãªã jq ãçŽæ¥æžãã
ãã°èšé²ã¯åŠçãã·ã³ãã«ãªã®ã§ãã¹ã¯ãªããã«åãåºãã»ã©ã§ã¯ãããŸãããjq ã®ã¯ã³ã©ã€ããŒã§ååããã ããjq ãã€ã³ã¹ããŒã«ãããŠããåæã§ãã
ãªã PreToolUse ã
ãäœãå®è¡ãããããäºåã«èšé²ããŠããããšã§ãã³ãã³ãã倱æããå Žåã§ãèšé²ãæ®ããŸããPostToolUse ã ãšã³ãã³ããéäžã§ã¯ã©ãã·ã¥ãããšãã«ãã°ãåããªãã
ãªã description ãèšé²ããã
`npm run build` ã ãã ãšåŸããèŠããšãã«æèãããããªãããšããããŸããClaude Codeãä»ããdescriptionãäžç·ã«æ®ããŠãããšãããªããã®ã³ãã³ããå®è¡ããããããããã
ã«ã¹ã¿ãã€ãº
ãã°ã®ä¿åå ãå€ããã â `>> .claude/activity.log` ã®éšåã倿Ž
æ¥æ¬¡ã§ãã°ãåããã â ãã¡ã€ã«åã«æ¥ä»ãå ¥ããïŒ`activity-$(date +%Y-%m-%d).log`ïŒ
Webæ€çŽ¢ããã°ã«åããã â matcher ã« `WebSearch` ã远å
ãã³ãã¬ãŒã4: å®äºéç¥
Claude Codeãäœæ¥ãçµãããšãããã¹ã¯ãããéç¥ãé£ã°ããŸãã
äœãèµ·ããã
Claude Codeã®åŠçãå®äº â ãã¹ã¯ãããéç¥ã衚瀺ããã â å¥ã®äœæ¥ãããŠããŠãæ°ã¥ãã
èšå®ïŒOSå¥ïŒ
macOS:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Codeã®äœæ¥ãå®äºããŸãã\" with title \"Claude Code\"'"
}
]
}
],
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"å
¥åãåŸ
ã£ãŠããŸã\" with title \"Claude Code\"'"
}
]
}
]
}
}WindowsïŒPowerShellïŒ:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "powershell -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); [System.Windows.Forms.MessageBox]::Show('Claude Codeã®äœæ¥ãå®äºããŸãã', 'Claude Code')\""
}
]
}
]
}
}Linux:
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'äœæ¥ãå®äºããŸãã'"
}
]
}
]
}
}èšèšæå³
ãªã Stop ãš Notification ã®äž¡æ¹ã
Stop ã¯ãäœæ¥ãå®äºãããšãããNotification ã¯ãå ¥åãåŸ ã£ãŠãããšããïŒèš±å¯ã®ç¢ºèªãªã©ïŒãäž¡æ¹èšå®ããŠãããšãåžãå€ããŠããŠãéèŠãªã¿ã€ãã³ã°ãéããŸããã
ãªã matcher ã空ã
éç¥ç³»ã®ããã¯ã¯ããã¹ãŠã®ã±ãŒã¹ã§çºç«ããããããšãå€ããç¹å®ã®ããŒã«ã«çµãå¿ èŠããªãã®ã§ã空æåã«ããŠãã£ã«ã¿ãªãã«ããŠããŸãã
ã«ã¹ã¿ãã€ãº
Slack ã«éç¥ããã â `command` ã `curl` ã§ã® Webhook åŒã³åºãã«å€æŽ
é³ã鳎ãããã â macOS ãªã `afplay /System/Library/Sounds/Glass.aiff` ã远å
é·æéã¿ã¹ã¯ã®ãšãã ãéç¥ â ã¹ã¯ãªããã«åãåºããŠçµéæéããã§ãã¯
ãã³ãã¬ãŒã5: ã³ãããåãã§ãã¯
Bashã§git commitãå®è¡ããããšããã³ãããã¡ãã»ãŒãžã®å質ãèªåãã§ãã¯ããŸãã
äœãèµ·ããã
Claude Codeã `git commit` ãå®è¡ããããšãã â ã³ãããã¡ãã»ãŒãžããã§ã㯠â åé¡ãããã°ãããã¯ããŠãã£ãŒãããã¯
èšå®
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/commit_checker.py"
}
]
}
]
}
}ãã§ãã¯ã¹ã¯ãªããïŒcommit_checker.pyïŒ
#!/usr/bin/env python3
"""git commitã®ã³ãããã¡ãã»ãŒãžå質ããã§ãã¯ããhooksã¹ã¯ãªãã"""
import json
import sys
import re
# ãã§ãã¯ã«ãŒã«ïŒå¿
èŠã«å¿ããŠç·šéïŒ
MAX_SUBJECT_LENGTH = 72
REQUIRED_PREFIX = False # True ã«ãããš prefix å¿
é
VALID_PREFIXES = ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore']
try:
data = json.load(sys.stdin)
command = data.get('tool_input', {}).get('command', '')
# git commit 以å€ã¯ç¡èŠ
if 'git commit' not in command:
sys.exit(0)
# ã³ãããã¡ãã»ãŒãžãæœåº
msg_match = re.search(r'-m\s+["\'](.+?)["\']', command)
if not msg_match:
# -m ãªãã® commitïŒãšãã£ã¿ãéããã¿ãŒã³ïŒã¯éã
sys.exit(0)
message = msg_match.group(1)
subject = message.split('\n')[0]
issues = []
# ãã§ãã¯1: ä»¶åã®é·ã
if len(subject) > MAX_SUBJECT_LENGTH:
issues.append(
f"Subject is {len(subject)} chars "
f"(max {MAX_SUBJECT_LENGTH})")
# ãã§ãã¯2: ä»¶åã空ã§ãªãã
if not subject.strip():
issues.append("Subject is empty")
# ãã§ãã¯3: prefix ãã§ãã¯ïŒæå¹æã®ã¿ïŒ
if REQUIRED_PREFIX:
has_prefix = any(
subject.lower().startswith(f"{p}:")
or subject.lower().startswith(f"{p}(")
for p in VALID_PREFIXES)
if not has_prefix:
issues.append(
f"Missing prefix. Use one of: "
f"{', '.join(VALID_PREFIXES)}")
if issues:
feedback = "Commit message issues:\n"
for issue in issues:
feedback += f" - {issue}\n"
feedback += f"\nCurrent message: \"{subject}\""
print(feedback)
sys.exit(2)
sys.exit(0)
except Exception as e:
# ãšã©ãŒæã¯èš±å¯åŽã«åã
sys.exit(0)èšèšæå³
ãªã Bash ã® PreToolUse ã
git commit 㯠Bash ããŒã«çµç±ã§å®è¡ãããŸãã`Edit` ã `Write` ã®matcher ã§ã¯ãã£ããã§ããŸãããBash ã® PreToolUse ã§ãã³ãã³ãæååã« `git commit` ãå«ãŸããããã§ãã¯ããŠããŸãã
ãªã prefix ãã§ãã¯ããªãã·ã§ã³ã«ããŠããã
Conventional CommitsïŒ`feat:`, `fix:` çïŒã匷å¶ããã人ãããã°ãäžèŠãªäººãããŸãã`REQUIRED_PREFIX = False` ãããã©ã«ãã«ããŠãå¿ èŠãªäººã ã `True` ã«å€ããããããã«ããŠããŸãã
ãªãæ£èŠè¡šçŸã§ `-m` ãæ¢ãã
`git commit -m "message"` ã®åœ¢åŒãè§£æããŠããŸãããšãã£ã¿ãéããã¿ãŒã³ïŒ`-m` ãªãïŒã¯ã¡ãã»ãŒãžãè§£æã§ããªãã®ã§éããŠããŸãã
ã«ã¹ã¿ãã€ãº
Conventional Commits ã匷å¶ããã â `REQUIRED_PREFIX = True` ã«å€æŽ
prefix ã®çš®é¡ãå€ããã â `VALID_PREFIXES` ãç·šé
æ¥æ¬èªã³ãããã¡ãã»ãŒãžããããã¯ããã â ASCII ãã§ãã¯ã远å
Co-Authored-By ã®åŒ·å¶ â message ã« `Co-Authored-By` ãå«ãŸããããã§ãã¯
ãã³ãã¬ãŒããçµã¿åããã
5ã€ã®ãã³ãã¬ãŒãã¯ç¬ç«ããŠåããŸããåæã«äœ¿ãããšãã§ããŸãã
`settings-all.json` ã«ã¯å šãã³ãã¬ãŒããçµ±åããèšå®ãå ¥ããŠãããŸãããã®ãŸãŸã³ããŒããã°å šéšæå¹ã«ãªããŸãããå šéšèŒãããšéããªãã±ãŒã¹ããããŸãããŸãã¯1ã€è©ŠããŠãå¿ èŠã«å¿ããŠè¿œå ããŠããã®ãããããã§ãã
çµã¿åããã®åªå 床
ã³ãŒãå質ã¬ãŒãïŒãã³ãã¬ãŒã1ïŒâ æåã«å ¥ããã¹ããæ¯åã®ãã©ãŒããããäžèŠã«ãªãã ãã§äœæãå€ãã
æ©å¯ãã¡ã€ã«ä¿è·ïŒãã³ãã¬ãŒã2ïŒâ ããŒã éçºã§ã¯å¿ é ãäºæ 鲿¢
å®äºéç¥ïŒãã³ãã¬ãŒã4ïŒâ é·ãåŠçãåŸ ã€ããšãå€ã人ã«
äœæ¥ãã°ïŒãã³ãã¬ãŒã3ïŒâ ã³ã³ãã©ã€ã¢ã³ã¹ãæ¯ãè¿ããå¿ èŠãªå Žå
ã³ãããåãã§ãã¯ïŒãã³ãã¬ãŒã5ïŒâ ã³ãããèŠçŽãããå Žå
èªåã§hooksãäœããšãã®ã³ã
1. matcher ã¯å ·äœçã«æžã
"matcher": "Edit|Write"
"matcher": "Bash"
"matcher": "*"`*` ã¯å šããŒã«ã«ãããããŸãããäžèŠãªã¿ã€ãã³ã°ã§ãçºç«ããã®ã§é ããªããŸããå¿ èŠãªããŒã«ã ãæå®ããŠãã ããã
2. exit code ãæ£ãã䜿ã
`0` â æ£åžžçµäºïŒèš±å¯ïŒ
`2` â ãããã¯ïŒstdoutãClaude Codeã«ãã£ãŒãããã¯ãããïŒ
ãã®ä» â ãšã©ãŒæ±ã
PreToolUse ã§ exit code 2 ãè¿ããšããã®ããŒã«åŒã³åºãããã£ã³ã»ã«ãããŸããstdout ã«çç±ãæžããšãClaude Codeãããªããããã¯ããããããçè§£ããŠãå¥ã®æ¹æ³ã詊ããŠãããŸãã
3. ãšã©ãŒæã¯å®å šåŽã«åã
hooks ã®ãã°ã§ä»äºãæ¢ãŸãã®ãææªã®ãã¿ãŒã³ã§ããäŸå€åŠçã§ã¯ `sys.exit(0)`ïŒèš±å¯ïŒã«ããŠããããã°ã§èŠåãåºãã
4. éãåŠçã¯é¿ãã
hooks ã¯ããŒã«å®è¡ã®ãã³ã«åããŸãã1åã®hookã«5ç§ããããšã10åã®ãã¡ã€ã«ç·šéã§50ç§ã®åŸ ã¡æéãçºçããŸãããã©ãŒããã¿ãŒã®å®è¡ããããªãåé¡ãããŸãããããã¹ãã¹ã€ãŒãå šäœãèµ°ãããã®ã¯é¿ããã»ããããã
ãã©ãã«ã·ã¥ãŒãã£ã³ã°
Q. hookãåããªã
settings.json ã®æ§æã確èªããŠãã ãããJSON ã®ã«ã³ãå¿ããæ¬åŒ§ã®éãå¿ããå€ãåå ã§ãã
# JSON ã®æ§æãã§ãã¯
cat ~/.claude/settings.json | jq .ãšã©ãŒãåºãããJSONãã©ãŒããã¿ãŒã§æŽåœ¢ãçŽããŠãã ããã
Q. hookããããã¯ãããã
matcher ãåºãããå¯èœæ§ããããŸãã`*` ã䜿ã£ãŠããããå ·äœçãªããŒã«åã«çµã£ãŠã¿ãŠãã ããã
Q. ã¹ã¯ãªãããèŠã€ãããªã
ãã¹ã確èªããŠãã ãããsettings.json ã«æžããã¹ã¯ãClaude Codeã®äœæ¥ãã£ã¬ã¯ããªããã®çžå¯Ÿãã¹ã§ãã
à hooks/file_protector.py
â .claude/hooks/file_protector.pyQ. Windows ã§åããªã
ã·ã§ã«ã¹ã¯ãªããïŒ.shïŒã¯Windowsã§ãã®ãŸãŸã§ã¯åããŸãããPowerShellçã䜿ãããPython ã¹ã¯ãªããã䜿ã£ãŠãã ãããä»åã®ãã³ãã¬ãŒãã§ã¯ãããžãã¯ãå¿ èŠãªãã®ã¯Pythonã§æžããŠããã®ã§ãPythonãã€ã³ã¹ããŒã«ãããŠããã°åããŸãã
ãŸãšã
hooksã¯Claude Codeã®åäœã«ã確å®ã«å®è¡ããããåŠçãæã¿èŸŒãæ©èœ
settings.json ã«èšå®ãæžãã ãã§åã
5ã€ã®ãã³ãã¬ãŒãã§ããã©ãŒãããèªååã»ãã¡ã€ã«ä¿è·ã»ãã°ã»éç¥ã»ã³ããããã§ãã¯ãã«ããŒ
ãŸãã¯ã³ãŒãå質ã¬ãŒãïŒãã³ãã¬ãŒã1ïŒãã詊ããŠã¿ãŠãã ãã