ð 5åææããŠãçŽããªãã£ã && ã Stop hook ã§æ°žä¹ å°å°ãã
倧åŠçã®ããæ10äžã®å¯æ¥ããå§ããŠãæãæã¡ã§æ60äžãŸã§äŒžã°ãããäŒç€Ÿéœåã§è§£éãããŠäžææãŒãã«ãªã£ãããã©ãå幎ã§Claude Codeã®èªåŸç°å¢ãæŽããŠä»ã¯æå120äžããã®çµéšã§äžçªåŒ·ãæãã®ã¯ãåããã¹ãå£é ã§çŽãç¶ããã®ã¯æéã®æµªè²»ã ããšããããšã§ãã
ãªããã®ä»çµã¿ãå¹ãã®ã
å£é ææãå¹ããªãæ¬åœã®çç±
Claude Codeã«ã! ãã³ããªãã§ && ã䜿ããªãã§ããšèšãèãããŠãçŽããŸããã§ããã2026幎7æ16æ¥ãŸã§ã«5åä»¥äžææããŠããŸããæ¯åãããããŸããããšè¿ã£ãŠãããã§ã次ã®ã»ãã·ã§ã³ã§ã¯åãã³ãã³ããåºãŠããŸãã
ãã㯠Claude ã®æ æ ¢ã§ã¯ãªããã¢ãŒããã¯ãã£ã®åé¡ã§ãã
Claude Codeã®ã»ãã·ã§ã³ã¯äŒè©±ããšã«ç¬ç«ããŠããŸããåã®ã»ãã·ã§ã³ã§ãããã¯ãã¡ããšæããå 容ã¯ã次ã®ã»ãã·ã§ã³èµ·åæç¹ã§ã¯ååšããªããCLAUDE.md ã«æžãã°åžžææ³šå ¥ããããšã¯ããããã®éã®ã«ãŒã«ãèªãã§ããäžã§äžè¡ã®æ³šææžãã確å®ã«æ©èœããããšãããšãå®éã®ã³ãŒãåºåãèŠãã°ããããŸãââæ©èœããŸããã§ããã
å£é ææã§çŽããªãçç±ã¯ã·ã³ãã«ã§ããææã¯ã³ã³ããã¹ãã«ä¹ããã³ã³ããã¹ãã¯ã»ãã·ã§ã³ãšå ±ã«æ¶ããã
ããããã³ã°ã³ãã³ãé£éã§äœãèµ·ããã
Claude Codeã® ! ã³ãã³ãã¯ã·ã§ã«ãèµ·åããŠã³ãã³ããå®è¡ããŸãããã®ãšã --auth ãªãã·ã§ã³ä»ãã®ãµãŒããŒèµ·åãªã©ãããã»ã¹ãå æããããããã³ã°ç³»ã®ã³ãã³ãã && ã§é£éããããšãæåã®ã³ãã³ããå®äºãè¿ããªããŸãŸåŸ
æ©ç¶æ
ã«å
¥ããåŸç¶ã®ã³ãã³ãã¯æ°žé ã«å®è¡ãããŸãããã»ãã·ã§ã³å
šäœãåºãŸããŸãã
æ£ããã®ã¯ &ïŒããã¯ã°ã©ãŠã³ãå®è¡ïŒã䜿ã£ãŠæ¬¡ã®ã³ãã³ãã«å¶åŸ¡ãæž¡ãããšã§ãã&& ã¯ãåã®ã³ãã³ããæ£åžžçµäºãããæ¬¡ãå®è¡ããšãã鿬¡å®è¡ãªã®ã§ãããããã³ã°ããã»ã¹ã®åŸã§ã¯çµ¶å¯Ÿã«æ©èœããªãã
# å£ããåïŒã»ãã·ã§ã³ãåºãŸãïŒ
! npx wrangler dev --local && open http://localhost:8787
# æ£ããåïŒããã¯ã°ã©ãŠã³ãã§èµ·åããŠããæ¬¡ãžïŒ
! npx wrangler dev --local & sleep 2 && open http://localhost:8787
ãã®å·®ã¯å°ããèŠããŠããããã°ã³ã¹ãã¯å·šå€§ã§ããåºãŸã£ããšæ°ã¥ããŸã§æ°ååŸ ã€ã匷å¶çµäºãããå床詊ã¿ãââãããæ¯åçºçããŠããŸããã
ãäœæ¥ãã§ã¯ãªããç°å¢ããå€ãã
å£é ã§5åçŽããŠããããªãã£ãããªãã°ç©ççã«äžå¯èœã«ãããããªãã
Claude Codeã«ã¯ Stop hook ãšããæ©èœããããŸããClaude ãå¿çãè¿ãçŽåã«ä»»æã®ã·ã§ã«ã¹ã¯ãªãããå®è¡ã§ããŸãããã®ã¹ã¯ãªããã exit 2 ãè¿ããšãClaude ã®å¿çã¯ãŠãŒã¶ãŒã«å±ãåã«ãããã¯ããããšã©ãŒã¡ãã»ãŒãžã衚瀺ãããŸãã
ããã¯ã«ãŒã«ã§ã¯ãããŸãããã³ãŒãã§ããã³ãŒãã¯æ¬¡ã®ã»ãã·ã§ã³ã«ãªã£ãŠãæ¶ããªããã»ãã·ã§ã³ããŸããã§ãæ¶ããªããClaude ãã©ãã ãããã³ããªãã³ãã³ãã§ãããšããã©ãã«ãä»ããããšãã&& ãå«ãŸããŠããã°ç©ççã«ééã§ããŸããã
åé¡ããææâä¿®æ£ãã®ç¹°ãè¿ããããç°å¢èšèšãã«å€ããç¬éãåã倱æã¯äºåºŠãšèµ·ããªããªããŸããã
ãããå人éçºã§èªååãç©ã¿äžãããšãã®åºæ¬ææ³ã§ããèªåãåçŸæ§ã®ããæé ãèžãã§ãããªãããããã³ãŒãã«ãããClaudeãç¹°ãè¿ããã¹ããããªãããã®ãã¹ãç©ççã«å°ããç°å¢ãäœãã
èªè ã®ããªããåãçµéšãããŠããã¯ãã§ãããåã«ãèšã£ãã®ã«ããããã£ããšèšã£ãã®ã«ãããªããŸãåãããšããââãã®æèŠã¯æ£ãããåé¡ã¯ã³ãã¥ãã±ãŒã·ã§ã³ã§ã¯ãªããèšèšã§ãã
å šäœã®æµã
ã·ã¹ãã æ§æã®æŠèŠ
Stop hook 㯠Claude Code ã®èšå®ãã¡ã€ã«ïŒ.claude/settings.json ãŸã㯠~/.claude/settings.jsonïŒã«ç»é²ããŸããClaude ãå¿çãçæãçµããã¿ã€ãã³ã°ã§ãç»é²ããã¹ã¯ãªãããèµ·åããŸããã¹ã¯ãªããã«ã¯ JSON ã§ãã©ã³ã¹ã¯ãªããã®ãã¹ãæž¡ãããŸãã
ä»åã® bang_handoff_amp_guard.sh ã¯46è¡ã®ã¹ã¯ãªããã§ããããããšã¯äžã€ââæåŸã® assistant ã¡ãã»ãŒãžãèªãã§ã! ã§å§ãŸãè¡ã« && ãå«ãŸããŠããããããã¯ããã
Claude ãå¿çãçæ
â
âŒ
Stop hook ãèµ·å
stdin ã« JSONïŒtranscript_path ãå«ãïŒãæž¡ããã
â
âŒ
transcript_path ãåãåºã
â
âââ ãã¹ç¡ã / ãã¡ã€ã«ç¡ã â exit 0ïŒãã§ã€ã«ãªãŒãã³ã»ééïŒ
â
âŒ
transcript JSONL ã Python ã§ããŒã¹
å
š assistant ã¡ãã»ãŒãžãåé
â
âŒ
æåŸã® assistant ã¡ãã»ãŒãžã ãåãåºã
â
âŒ
è¡ããšã«ã³ãŒããã§ã³ã¹ïŒ```ïŒã»ããã¯ã¯ã©ãŒããé€å»
â
âŒ
æ£èŠè¡šçŸãã§ãã¯: ^!\s ã〠&& ãå«ãè¡ãããã
â
âââ ãã â stderr ã«ãšã©ãŒåºå â exit 2ïŒãããã¯ïŒ
âââ ãªã â exit 0ïŒééã»Claude ã®å¿çããŠãŒã¶ãŒãžå±ãïŒ
å®ã³ãŒãã®æ§æãšåããŒãã®æå³
ã¹ã¯ãªããå šäœã3ã€ã®ãããã¯ã«åããŠèŠãŠãããŸãã
ãããã¯1: ãã©ã³ã¹ã¯ãªãããã¹ã®ååŸãšãã§ã€ã«ãªãŒãã³
input=$(cat)
tpath=$(printf '%s' "$input" | /usr/bin/python3 -c \
"import sys,json;print(json.load(sys.stdin).get('transcript_path',''))" 2>/dev/null)
[ -n "$tpath" ] && [ -f "$tpath" ] || exit 0
Stop hook ã® stdin ã«ã¯ Claude Code ãã JSON ãæµããŠããŸããtranscript_path ããŒã«ãã©ã³ã¹ã¯ãªãããã¡ã€ã«ã®çµ¶å¯Ÿãã¹ãå
¥ã£ãŠããŸããPython ã§ãããåãåºãããã¹ã空ãŸãã¯ãã¡ã€ã«ãååšããªãå Žå㯠exit 0 ã§çŽ éãããŸãã
ããããã§ã€ã«ãªãŒãã³èšèšã§ããã¹ã¯ãªãããäœããã®çç±ã§ãã©ã³ã¹ã¯ãªãããèªããªããŠããClaude ã®å¿çã¯ééããŸãã誀ãããã¯ã«ããäœæ¥åæ¢ã¯ã&& ã«ããåºãŸãããé¥ãã«ã³ã¹ããé«ããã ãããèªããªããã°é»ã£ãŠéãããååã«ããŠããŸãã
ãããã¯2: ãã©ã³ã¹ã¯ãªããã®ããŒã¹ãšæåŸã®ã¡ãã»ãŒãžæœåº
msgs = []
try:
for line in open(sys.argv[1], encoding="utf-8"):
line = line.strip()
if not line:
continue
try:
o = json.loads(line)
except Exception:
continue
if o.get("type") == "assistant" or o.get("role") == "assistant":
m = o.get("message", o)
c = m.get("content")
if isinstance(c, list):
for b in c:
if isinstance(b, dict) and b.get("type") == "text":
msgs.append(b.get("text", ""))
elif isinstance(c, str):
msgs.append(c)
except Exception:
pass
last = msgs[-1] if msgs else ""
Claude Code ã®ãã©ã³ã¹ã¯ãªãã㯠JSONL 圢åŒã§ãïŒ1è¡1JSONãªããžã§ã¯ãïŒãåè¡ã json.loads() ã§ããŒã¹ããtype ãŸã㯠role ã "assistant" ã®ãšã³ããªãæŸããŸããcontent ã¯ãªã¹ã圢åŒïŒè€æ°ãããã¯ïŒãšæåå圢åŒã®äž¡æ¹ãããã®ã§äž¡ãã¿ãŒã³ãåŠçããŠããŸãã
å
š assistant ã¡ãã»ãŒãžã msgs ãªã¹ãã«ç©ã¿ãæåŸã®äžã€ã ã last ã«åãåºããŸããéå»ã®äŒè©±å±¥æŽã¯é¢ä¿ãªãââä»åã®å¿çã ããæ€æ»ããŸãã
ãããã¯3: æ€åºãã¿ãŒã³ãšåºå
bt = chr(96) # backtick ãã³ãŒãå
ã§çŽæ¥æžããªã
for ln in last.splitlines():
s = ln.strip().strip(bt).strip() # ã³ãŒããã§ã³ã¹/ããã¯ã¯ã©ãŒãé€å»
if re.match(r'^!\s', s) and '&&' in s:
print(s)
break
echo "ð« ! ãã³ããªãã« && ã䜿ã£ã(æ¬äººã5åä»¥äžæææž)ãClaude Codeã® ! ã»ãã·ã§ã³ã§ã¯ \
&& ã§ããããã³ã°ç³»(--authç)ãé£éãããšåºãŸã£ãŠéããªãã\
>> && ãåäž & ã«çŽããŠåºãçŽã <<ã該åœè¡: ${bad}" >&2
exit 2
æ€åºããžãã¯ã¯2段éã§ãã
ãŸãåè¡ããã³ãŒããã§ã³ã¹ïŒããã¯ã¯ã©ãŒãïŒãå¥ãããŸããClaude ã¯ã³ãŒããããã¯ã®äžã«ã³ãã³ããæžãããšããããŸãã``` ã§å²ãŸããŠããŠãããã®äžèº«ãå®éã®ã³ãã³ãã§ããå Žåã¯æ€åºå¯Ÿè±¡ã«ããå¿
èŠããããŸããããã§ bt = chr(96) ãšããããªãã¯ãåºãŠããŸãââã¹ã¯ãªããèªäœãã·ã§ã«ãã eval ãããããšããããããã¹ã¯ãªããå
ã«ããã¯ã¯ã©ãŒããçŽæ¥æžããšèªå·±ããŒã¹ãšã©ãŒãçºçããŸããchr(96) ã§ããã¯ã¯ã©ãŒãã®æåãåçã«çæããŠåé¿ããŠããŸãã
å¥ãããåŸãæ£èŠè¡šçŸ ^!\s ã§è¡ã®å
é ã ! ïŒæå笊ïŒã¹ããŒã¹ïŒã§ããããšã確èªããããã« && ãå«ãŸããŠãããããã§ãã¯ããŸããäž¡æ¹ã true ã®ãšãããã®è¡ã stdout ã« print ã㊠Python ã¹ã¯ãªãããçµäºããŸãã
bash åŽã§ãã®åºåã bad 倿°ã«åãåãã空ã§ãªããã° exit 2ã空ã§ããã° exit 0ã
ãšã©ãŒã¡ãã»ãŒãžã«ã¯ãæ¬äººã5åä»¥äžæææž(2026-07-16)ããšããèšè¿°ããã®ãŸãŸå ¥ã£ãŠããŸããããã¯å°æ¥ã®èªåïŒãŸã㯠ClaudeïŒãžã®ã³ã³ããã¹ãã§ãããªããã®ã¹ã¯ãªãããååšããã®ãããªããããã«ãŒã«ãªã®ãããã³ãŒãå ã®ã³ã¡ã³ããšãšã©ãŒã¡ãã»ãŒãžã§èªå·±èª¬æãããŠããŸãã
èšå®ãã¡ã€ã«ãžã®ç»é²
Stop hook 㯠~/.claude/settings.json ã® hooks ã»ã¯ã·ã§ã³ã«ç»é²ããŸãã
{
"hooks": {
"Stop": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "~/.claude/hooks/bang_handoff_amp_guard.sh"
}
]
}
]
}
}
Stop ã€ãã³ã㯠Claude ãå¿çã宿ãããçŽåŸã«çºç«ããŸããmatcher ã空æåã«ããããšã§å
šãŠã®å¿çã«å¯ŸããŠå®è¡ãããŸããç¹å®ã®ãããžã§ã¯ãã ãã«é©çšãããå Žåã¯ãããžã§ã¯ãã® .claude/settings.json ã«æžããŸããã°ããŒãã«ã«é©çšããããªã ~/.claude/settings.json ã§ãããã®ã¹ã¯ãªãã㯠~/.claude/hooks/ ã«çœ®ããŠã°ããŒãã«ç»é²ããŠããŸãââ&& åé¡ã¯ãããžã§ã¯ã暪æã§çºçããããã§ãã
ã¹ã¯ãªããã«ã¯å®è¡æš©éãå¿ èŠã§ãã
chmod +x ~/.claude/hooks/bang_handoff_amp_guard.sh
ããã§èšå®ã¯å®äºã§ããæ¬¡ã®ã»ãã·ã§ã³ä»¥éã&& ãå«ã ! ãã³ããªãã³ãã³ããåºåããããšããç¬éã« Claude ã®å¿çããããã¯ãããstderr ã«ãšã©ãŒã¡ãã»ãŒãžã衚瀺ãããŸããClaude ã¯å¿çãåºãçŽãïŒ&& ã & ã«çŽãïŒãããªããªããŸãã
å£é ã§5åææãç¶ããåé¡ãã46è¡ã®ã¹ã¯ãªããã§ç©ççã«æ¶ããŸããã
ãªããã®æžãæ¹ã§ãªããã°ãªããªãã
åç« ã§ã¹ã¯ãªããå šäœã®æ§é ãš3ãããã¯ã®åœ¹å²ãèŠãŸãããããã§ã¯ãåãã ããã§ã¯ãªããå£ãã«ããåããããã«æœããèšèšå€æãæãäžããŸããå®éã«è©°ãŸã£ãŠåŸããæ°ã¥ãããã®ã°ããã§ãã
stdin ã倿°ã«äžåºŠåããçç±
input=$(cat)
tpath=$(printf '%s' "$input" | /usr/bin/python3 -c "..." 2>/dev/null)
æåã®è¡ã§ cat ã倿° input ã«å
¥ããŠããŸããStop hook ã® JSON ã¯æšæºå
¥åããæ¥ãã®ã§ãcat ã Python ã«çŽæ¥ãã€ãããã°1è¡ã§æžã¿ãŸãããããããªãçç±ã¯ãstdin ã¯äžåºŠããèªããªããããã§ãã
ãã€ãã§ãã®ãŸãŸæž¡ããš stdin ãæ¶è²»ãåããŸãããããã°æã«åãå
¥åãå¥ã® Python åŒã³åºãã«ãæž¡ãããããããã¯ã¹ã¯ãªãããæ¡åŒµããŠè€æ°ã®å€ãåãåºãããââããããå Žé¢ã§è©°ã¿ãŸããinput=$(cat) ã§å
ã«å
šéšåãåããprintf '%s' "$input" ã§äœåºŠã§ãåå©çšã§ãã圢ã«ããããããã·ã§ã«ã¹ã¯ãªããã§ stdin ãæ±ãå®å
šãªåã§ãã
/usr/bin/python3 ãšãã«ãã¹ã§æžãçç±
tpath=$(printf '%s' "$input" | /usr/bin/python3 -c "..." 2>/dev/null)
bad=$(/usr/bin/python3 - "$tpath" <<'PY'
2ç®æãšã python3 ã§ã¯ãªã /usr/bin/python3 ã§ãã
Stop hook ãèµ·åããã·ã§ã«ã¯éåžžã®ã¿ãŒããã«ã»ãã·ã§ã³ã§ã¯ãããŸããã~/.zshrc ã ~/.bash_profile ãèªã¿èŸŒãŸããŠããªãããã$PATH ã¯æå°éã®ç¶æ
ã§ããnvm çµç±ã§ã€ã³ã¹ããŒã«ããããŒã«é¡ã¯åœç¶èŠããªããpyenv ã Homebrew ã® Python ãèŠããŸããã
python3 ãšããã³ãã³ãåã ãã§ã¯ãhook ã®ã·ã§ã«ç°å¢ã«å®å
šã«äŸåããŸããmacOS ã®ã·ã¹ãã Python 㯠Xcode ã³ãã³ãã©ã€ã³ããŒã«ããå
¥ã£ãŠããã°å¿
ã /usr/bin/python3 ã«ãããŸãããã«ãã¹ã§æå®ããããšã§ãç°å¢ã«å·Šå³ãããªãç§»æ€æ§ã確ä¿ã§ããŸãã
ç¢ºèªæ¹æ³ã¯ç°¡åã§ãã
/usr/bin/python3 --version
ãã®ã³ãã³ããéãã° hook å ã§ãåããã¹ã䜿ããŸãã
ãã¢ããã¥ã¡ã³ãã®ã·ã³ã°ã«ã¯ã©ãŒããåœç¶±
bad=$(/usr/bin/python3 - "$tpath" <<'PY'
import sys, json, re
...
if re.match(r'^!\s', s) and '&&' in s:
PY
)
ãã¢ããã¥ã¡ã³ãã®ããŒã«ãŒã 'PY'ïŒã·ã³ã°ã«ã¯ã©ãŒãããïŒã«ããŠããŸãã<<PYïŒã¯ã©ãŒããªãïŒãšã®éãã¯æ ¹æ¬çã§ãã
ã¯ã©ãŒããªã <<PY ã§ã¯ããã¢ããã¥ã¡ã³ãå
ã® $倿° ãããã¯ã¯ã©ãŒããã·ã§ã«ã«å±éãããŸããããšãã°æ£èŠè¡šçŸ r'^!\s' ã® \s ãã·ã§ã«ã«ãã£ãŠ s ã«å€æãããŠããŸããŸããPython ã«ã¯ r'^!s' ãšãããã¿ãŒã³ãæž¡ããããã¹ããŒã¹ã«ãããããã¯ãã® \s ã倱ãããæ€åºããžãã¯å
šäœãå£ããŸãã
<<'PY' ã«ãããšãã¢ããã¥ã¡ã³ãå
šäœããªãã©ã«æååãšããŠæ±ãããŸããã©ã㪠Python ã³ãŒãããã®ãŸãŸæž¡ããŸããã·ã§ã«ã¹ã¯ãªããã« Python ãåã蟌ãå Žåã®ã·ã³ã°ã«ã¯ã©ãŒãã¯çµ¶å¯Ÿååã§ãã
type ãš role ã®äž¡æ¹ãèŠãçç±
if o.get("type") == "assistant" or o.get("role") == "assistant":
or ã§2ã€ã®ãã£ãŒã«ããåç
§ããŠããŸãããã㯠Claude Code ã®ãã©ã³ã¹ã¯ãªãã JSONL ããããŒãžã§ã³ãã»ãã·ã§ã³ã®é·ãã«ãã£ãŠç°ãªããã©ãŒãããã䜿ã£ãŠããããã§ãã
å€ããšã³ããªã¯ role: "assistant" ãã£ãŒã«ããæã¡ãŸããæ°ãããšã³ããªã¯ type: "assistant" ãã£ãŒã«ãã䜿ããŸããäžã€ã®ãã©ã³ã¹ã¯ãªãããã¡ã€ã«ã«äž¡æ¹ãæ··åšããããšããããŸããé·ãã»ãã·ã§ã³ã§ã¯ååãæ§ãã©ãŒããããåŸåãæ°ãã©ãŒããããšããç¶æ³ãæ®éã«èµ·ããŸãã
type ã ãèŠãŠãããšãrole: "assistant" ã®ã¡ãã»ãŒãžã msgs ãªã¹ãã«ç©ãŸãããæåŸã® assistant ã¡ãã»ãŒãžãæ£ããç¹å®ã§ããªããªããŸãã
Claude Code ã¯ããŒãžã§ã³ã¢ããã§å éšãã©ãŒããããå€ããããšããããŸããç¹å®ãã£ãŒã«ãã ãã«äŸåããå®è£ ã¯ãã¢ããããŒãã®ãã³ã«å£ããå¯èœæ§ããããŸããè€æ°ãã£ãŒã«ãããã©ãŒã«ããã¯ãšããŠèŠãã®ãå®å šãªæžãæ¹ã§ãã
chr(96) ã§ããã¯ã¯ã©ãŒãã鿥çæããçç±
bt = chr(96) # backtick ãã³ãŒãå
ã§çŽæ¥æžããªã
for ln in last.splitlines():
s = ln.strip().strip(bt).strip()
ASCII ã³ãŒã96çªãããã¯ã¯ã©ãŒãã§ãããªãçŽæ¥æžããªãããšãããšãã¹ã¯ãªãããã·ã§ã«ã® heredoc ã«åã蟌ãŸããŠãã以äžãå°æ¥å¥ã®ã·ã§ã«ã³ã³ããã¹ãïŒeval çµç±ãå¥ã¹ã¯ãªããããã® source ãªã©ïŒã«ç§»æ€ãããéã«ããã¯ã¯ã©ãŒããèªå·±ããŒã¹ãšã©ãŒãåŒãèµ·ãããªã¹ã¯ãããããã§ãã
chr(96) ã§å®è¡æã«æåãçæããã°ãã¹ã¯ãªããæ¬æã«ããã¯ã¯ã©ãŒããäžæåãç»å ŽããŸãããå ããŠãstr.strip(bt) ã䜿ãããšã§ãã³ãŒããã§ã³ã¹ã§å²ãŸããã³ãã³ãããæ£ããåŠçã§ããŸãã
Claude ãã³ãã³ããã€ã³ã©ã€ã³ããã¯ã¯ã©ãŒãã§å²ãã§æžããå Žåââããšãã° ãæ¬¡ã®ã³ãã³ããå®è¡ããŠãã ãã: `! npx wrangler dev --local && open http://localhost:8787` ã ã®ãããªåºåââã§ããããã¯ã¯ã©ãŒããå¥ãããåŸã«æ£èŠè¡šçŸã§ãã§ãã¯ããã®ã§æ€åºæŒãã«ãªããŸããã
ç§ãè©°ãŸã£ã話
宿ãã46è¡ã¯æŽç¶ãšããŠèŠããŸãããåãåã«ã¯4åè©°ãŸããŸããããããããçç¶âåå âçŽãæ¹ãã§æžããŸãã
è©°ãŸã1: grep ã§æžãããæ€åºçãŒãã ã£ã
æåã®å®è£
äžçªã·ã³ãã«ã«èããŠãããæžããŸããã
if grep -qE '^\! .* &&' "$tpath"; then
echo "ð« && ã䜿ããªãã§ãã ãã" >&2
exit 2
fi
ã¿ãŒããã«ã§æåãã¹ããããšåããClaude ã« && å
¥ãã®ã³ãã³ããå®éã«åºåãããŠã¿ããšââééããããããã¯ãããªãã
åå
ãã©ã³ã¹ã¯ãªãã㯠JSONL ã§ããåè¡ã1ã€ã® JSON ãªããžã§ã¯ãã§ãå®éã®ããã¹ã㯠"text" ãã£ãŒã«ãã®å€ãšã㊠JSON ãšã³ã³ãŒããããŠããŸãããã¡ã€ã«ããã®ãŸãŸ grep ãããšããã³ãŒãåã®çãã€ãåãèŠãããšã«ãªããŸãã
JSON ã®äžã§ã¯ ! ã ! ã«ãªã£ãŠããããšããããŸãã&& 㯠&& ã«å€æãããŠããããšããããŸããæ¹è¡ã¯ \n ã®ãªãã©ã«2æåïŒããã¯ã¹ã©ãã·ã¥ãšnïŒãšããŠæ ŒçŽãããŠããŸããgrep ã®ãã¿ãŒã³ ^\! .* && ã¯1è¡ã®ããã¹ãã«ãããããããšããŸãããJSONL ã®1è¡ã¯ JSON ãªããžã§ã¯ãå
šäœã§ããäžèº«ã®æ¹è¡ã¯ \n ãšãã2æåãšããŠæ ŒçŽãããŠããã®ã§ãå®éã®ã³ãã³ãè¡ã¯ grep ã«ã¯ã1è¡ããšããŠèŠããŸããã
çŽãæ¹
Python ã§ JSON ãããŒã¹ããŠãtext ãã£ãŒã«ããåãåºããŠããæ£èŠè¡šçŸããããããã³ãŒãæžã¿ã®å®ããã¹ããèŠãéããJSON ãšã¹ã±ãŒãã®åé¡ã¯çºçããŸãããgrep ã§ãã©ã³ã¹ã¯ãªãããçŽæ¥ã¹ãã£ã³ããå®è£
ã¯æ ¹æ¬çã«èª€ãã§ãã
è©°ãŸã2: ãã§ã€ã«ãªãŒãã³ããåžžã«ééãã«åããŠãã
çç¶
Stop hook ãèšå®ãçŽããClaude ã« && ãå«ã ! ã³ãã³ããåºåãããŠãããã¯ããããã¯ãããªããexit 0 ã§çŽ éãããŠããããããã°çšã« echo "hookèµ·å" >&2 ãå
é ã«å
¥ãããšåºåãããââhook èªäœã¯ç¢ºãã«åããŠããããªã®ã« exit 2 ã«å°éããªãã
åå
2>/dev/null ã§ python3 ã®ãšã©ãŒãæšãŠãŠãããããæ°ã¥ããªãã£ãã®ã§ããå®éã«ã¯ïŒ
/usr/bin/python3: command not found
ãšãããšã©ãŒãåºãŠããŸãããhook ã®ã·ã§ã«ãã python3ïŒãã«ãã¹ãªãïŒãåŒãã§ããããèŠã€ãããªããpython3 ãèŠã€ãããªã â tpath ã空æååã«ãªã â [ -n "$tpath" ] || exit 0 ã§ãã§ã€ã«ãªãŒãã³ â å
šéšééããšããæµãã§ãã
ãã§ã€ã«ãªãŒãã³èšèšãæ£ããæ¹åæ§ã§ããäžæ¹ãã誀ããé ããŠããŸããå¯äœçšãšããŠçŸããŸããã
çŽãæ¹
ãŸã /usr/bin/python3 --version ã hook ã®ã·ã§ã«ã§ç¢ºèªããŸããHook 㯠launchd ãå
éšããã»ã¹ããèµ·åããããããPATH ãéåžžãšéããŸãã確èªã§ãããã«ãã¹ããã®ãŸãŸã¹ã¯ãªããã«æžãããããã°æã¯ 2>/dev/null ãäžæçã«å€ã㊠stderr ãèŠãŸãââãšã©ãŒãèŠããããã«ãªãã ãã§åå ç¹å®ãåçã«éããªããŸãã
è©°ãŸã3: ãã¢ããã¥ã¡ã³ãã Pyhon ã³ãŒããç Žå£ããŠãã
çç¶
python3 ã®ãã«ãã¹åé¡ã¯çŽãããã§ã bad 倿°ãåžžã«ç©ºã§ã&& ãå«ãã³ãã³ããæžããŠã exit 2 ã«ãªããªãã2>/dev/null ãå€ã㊠stderr ãèŠããšïŒ
File "<stdin>", line 1
if re.match(r'^!s', s) and '&&' in s:
^
SyntaxError: invalid syntax
r'^!\s' ã r'^!s' ã«ãªã£ãŠããŸãã
åå
ãã¢ããã¥ã¡ã³ãã <<PYïŒã¯ã©ãŒããªãïŒã§æžããŠããŸãããPython ã³ãŒãã®æ£èŠè¡šçŸ r'^!\s' 㯠\s ãå«ã¿ãŸããbash ã¯ã¯ã©ãŒããªãã®ãã¢ããã¥ã¡ã³ãå
ã§ããã¯ã¹ã©ãã·ã¥ããšã¹ã±ãŒããšããŠåŠçããããã\s ã® \ ãæ¶ã㊠s ã ããæ®ããŸãããPython åŽã§ã¯ r'^!s' ãšããå
šãå¥ã®ãã¿ãŒã³ãæž¡ãããŸããã¹ããŒã¹ã«ãããããã¯ãã® \s ã倱ãããã©ã®è¡ããããããªãç¶æ
ã«ãªã£ãŠããŸããã
çŽãæ¹
<<PY ã <<'PY' ã«å€ãããããã ãã§ãããã®1æåïŒ'ïŒã®å·®ã§åäœãæ ¹æ¬ããå€ãããŸããPython ãåã蟌ã heredoc ã«ã¯å¿
ãã·ã³ã°ã«ã¯ã©ãŒããã€ããŸããä»ã®ã¹ã¯ãªããã§ãåãåé¡ãèžãå¯èœæ§ãããã®ã§ãPythonã³ãŒãåã蟌ã¿çšã® heredoc ã¯ã·ã³ã°ã«ã¯ã©ãŒãå¿
é ãšäœã«èŠããããŸããã
è©°ãŸã4: ç¹å®ã»ãã·ã§ã³ã ããããã¯ãçºåããªã
çç¶
åºæ¬çã«ã¯åããŠããŸãããã ããé·ãã®ã»ãã·ã§ã³ïŒ30åŸåŸ©ä»¥äžã®äŒè©±ïŒã§ Claude ã && ã³ãã³ããæžããŠããééããŠããŸãããšããããçãã»ãã·ã§ã³ã§ã¯ç¢ºå®ã«ãããã¯ãããã
åå
å®éã®ãã©ã³ã¹ã¯ãªãããçŽæ¥èŠããŠç¢ºèªããŸããã
python3 -c "
import json
for l in open('/path/to/transcript.jsonl'):
l = l.strip()
if not l: continue
o = json.loads(l)
print(list(o.keys())[:4])
"
åºåãèŠããšãã»ãã·ã§ã³åºç€ã®ãšã³ããªã¯ ['role', 'content', ...] ãšããæ§é ã§ãåŸåã®ãšã³ããªã¯ ['type', 'message', ...] ãšããæ§é ã«ãªã£ãŠããŸããæåã®å®è£
ã§ã¯ o.get("type") == "assistant" ã ããèŠãŠãããããåºç€ã® role: "assistant" ãšã³ããªãå
šéšã¹ããããããŠããŸããã
é·ãã»ãã·ã§ã³ã§ã¯ type: "assistant" ã®ã¡ãã»ãŒãžãååšããªãããããã¯æåŸã®ã¡ãã»ãŒãžã role: "assistant" 圢åŒã«ãªã£ãŠããããšããããŸãããããªããš msgs ã空ã«ãªããlast = "" â äœãæ€åºããªã â exit 0ããšããçµè·¯ããã©ããŸãã
çŽãæ¹
if o.get("type") == "assistant" or o.get("role") == "assistant":
or ã§äž¡æ¹ã®ãã£ãŒã«ãã確èªããŸããClaude Code ã®ããŒãžã§ã³ã¢ããã§ãã©ãŒããããå€ãã£ãŠããã©ã¡ããã®ãã£ãŒã«ãã "assistant" ãæã£ãŠããã°æŸããŸãã
4åè©°ãŸã£ãŠããã®éœåºŠ1è¡ã2è¡è¶³ããçµæãä»ã®46è¡ã§ããã³ãŒãã®åè¡ã¯ããªãããã«ååšããããã«çããããŸãã/usr/bin/python3 ã¯ãã«ãã¹ã§ãªããš hook ç°å¢ã§èŠã€ãããªãããã<<'PY' ã¯ã·ã³ã°ã«ã¯ã©ãŒãããªããš Python ã³ãŒããå£ãããããor o.get("role") ã¯æ§ãã©ãŒããããæŸãããŒããªãããããã§ã€ã«ãªãŒãã³ã® exit 0 ã¯èª€ãããã¯ãé²ãããã
ããªãããæžããããèšããªãã³ãŒãã¯ãå£ããæã«çŽããŸãããè©°ãŸã£ãèšæ¶ããã®ãŸãŸèšèšæ ¹æ ã«ãªã£ãŠããŸãã
å ±éã®ãããã°æé ââhook ãããªããçŽ éãããããšæããã
Stop hook ç³»ã®ãã©ãã«ã¯ã©ããããã§ã€ã«ãªãŒãã³ãéãã«ééãããŠããããã¿ãŒã³ã«åž°çããŸãããŸã確èªããããš3ç¹ã§ãã
1. hook èªäœãèµ·åããŠãããã確èªãã
ã¹ã¯ãªããã®åé ã«1è¡è¿œå ããŸãã
echo "[DEBUG] hookèµ·å tpath=${tpath}" >&2
Claude ã®å¿çåŸã« stderr ã«ãã®è¡ãåºãªããã°ãhook èªäœãèµ·åããŠããŸãããèšå®ãã¡ã€ã«ã®ãã¹ãééã£ãŠããããå®è¡æš©éãã€ããŠããªããã§ãã
ls -la ~/.claude/hooks/bang_handoff_amp_guard.sh
# â -rwxr-xr-x ã«ãªã£ãŠããã確èªãrãæããŠããã chmod +x
2. 2>/dev/null ãå€ããŠãšã©ãŒãèŠã
ãã§ã€ã«ãªãŒãã³èšèšã¯ãéãã«ééããããããå
éšã§ãšã©ãŒãèµ·ããŠããŠã衚é¢ã«åºãŸãããäžæçã« 2>/dev/null ãå€ããŸãã
# 倿Žå
tpath=$(printf '%s' "$input" | /usr/bin/python3 -c "..." 2>/dev/null)
# ãããã°çšïŒç¢ºèªåŸã«æ»ãïŒ
tpath=$(printf '%s' "$input" | /usr/bin/python3 -c "...")
stderr ã« command not found ã SyntaxError ãèŠãããåå ãããããŸãã確èªãçµãã£ããå¿
ã 2>/dev/null ãæ»ããŠãã ããã
3. ãã©ã³ã¹ã¯ãªããã®æ§é ãçŽæ¥èŠã
python3 -c "
import json, sys
for l in open(sys.argv[1]):
l = l.strip()
if not l: continue
o = json.loads(l)
role = o.get('role') or o.get('type', '?')
if role == 'assistant':
print('--- assistant entry keys:', list(o.keys()))
" ~/.claude/projects/.../transcript.jsonl
ããã§ type ãš role ã©ã¡ãã®ãã£ãŒã«ãã䜿ãããŠããããcontent ããªã¹ããæååããå®éã®ãã¡ã€ã«ã§ç¢ºèªã§ããŸããClaude Code ã®ããŒãžã§ã³ãå€ãã£ãŠãã©ãŒããããå€ãã£ãŠãããšæã£ããšããããããèŠãã°å³åº§ã«ããããŸãã
3ç¹ç¢ºèªããã°ããçŽ éãã®åå ãã¯å¿ ãã©ããã«åœãŠã¯ãŸããŸããHook ã®åé¡ã¯ä»çµã¿ãçè§£ããŠããã°é£ãããããŸãããè©°ãŸãã®ã¯ãã€ããéãã«ééããŠãããããšã«æ°ã¥ãã®ãé ãã ãã§ãã
ã€ãŸãããã€ã³ã
p2ã§ã¯å®éã«è©°ãŸã£ã4åãæãäžããŸãããããã§ã¯éçšãç¶ããäžã§ããããåºãŠãã远å ã®èœãšã穎ãç®æ¡æžãã§ç¶²çŸ ããŸããããªããåããªããããªãããããã¯ãããªããã®ãããã°ç §åãªã¹ããšããŠäœ¿ã£ãŠãã ããã
settings.json ã®æ§æãšã©ãŒã§ hook ããµã€ã¬ã³ãã«ç¡å¹åããã
JSON ã®æ«å°Ÿã«ã³ãã»éãæ¬åŒ§ã®äžè¶³ã»ããŒåã®ã¯ã©ãŒãæŒããClaude Code ã¯èµ·åæã«ãããã®ããŒã¹ãšã©ãŒãç®ç«ã€åœ¢ã§éç¥ããªãããšããããŸããçµæãšã㊠hook ãäžåèµ·åããªãã®ã«ããªãå¹ããªãã®ãåå ã«æ°ã¥ããªãç¶æ ãç¶ããŸããèšå®ã倿Žãããå¿ ãæ¬¡ã®ç¢ºèªãããŠãã ããã
echo '{"transcript_path":""}' | ~/.claude/hooks/bang_handoff_amp_guard.sh; echo "exit: $?"
# exit: 0 ãè¿ãã° hook èªäœã¯èµ·åããŠãã
ã¹ã¯ãªãããã¹ã® ~ ãã«ããå±éãããªã
settings.json ã® command ãã£ãŒã«ãã« ~/.claude/hooks/bang_handoff_amp_guard.sh ãšæžããŠããhook ãèµ·åããã·ã§ã«ã«ãã£ãŠã¯ãã«ãå±éãè¡ãããŸããã~ ã®ãŸãŸæž¡ããããã¹ã¯ãã¡ã€ã«ãšããŠååšããªãã®ã§ãµã€ã¬ã³ãã«ç¡å¹åãããŸããrealpath ~/.claude/hooks/bang_handoff_amp_guard.sh ã§ååŸãããã«ãã¹ã settings.json ã«çŽæ¥æžããŠãã ããããã«ãã䜿ãã®ã¯äººéãèªãèšå®ã§ã¯ãªããã¿ãŒããã«ã§çŽæ¥å®è¡ããã³ãã³ãã ãã«ããããšããã«ãŒã«ã§æŽçã§ããŸãã
chmod +x ãå¿ãã
å®è¡æš©éããªããšã¹ã¯ãªããã¯èµ·åããŸãããls -la ~/.claude/hooks/bang_handoff_amp_guard.sh ã§ -rwxr-xr-x ã«ãªã£ãŠããããšã確èªããŠãã ããã-rw-r--r-- ã®ããã« x ãç«ã£ãŠããªãå Žåãhook ã¯éãã«æ©èœããªããŸãŸã§ãããããäžçªå€ãããªããåããªããã®åå ã§ããæ°ããã¹ã¯ãªãããäœã£ãçŽåŸã« chmod +x ãŸã§1ã»ããã«ããç¿æ
£ãå¿
èŠã§ãã
exit 1 ãš exit 2 ã®éããèŠèœãšã
Stop hook ã§ãããã¯ããã«ã¯ exit 2 ãè¿ãå¿
èŠããããŸããexit 1 ãè¿ããš Claude Code ã®ããŒãžã§ã³ã«ãã£ãŠã¯å¿çããããã¯ãããŸããããã®å·®ã¯å
¬åŒããã¥ã¡ã³ãã«ç®ç«ã€åœ¢ã§æžããŠããŸããããå®éã®æåã§ç¢ºèªããŠããŸããèªåã® hook ãæžããŠãããã¯ãå¹ããªããšãããŸã exit ã³ãŒãã確èªããŠãã ããã
è€æ°ã® Stop hook ãç»é²ãããŠãããšãã®å®è¡é
hooks.Stop é
åã«è€æ°ã® hook ãæžããå Žåãé
åã®å
é ããé ã«å®è¡ãããŸããæåã® hook ã exit 2 ãè¿ããæç¹ã§ãããã¯ã確å®ããåŸç¶ã® hook ã¯å®è¡ãããŸãããè€æ°ã®ã¬ãŒã hook ã䞊ã¹ãå Žåã¯ãæã軜ããŠç¢ºå®ã«åããã®ãå
é ã«çœ®ããŠãã ãããéãåŠçãå
é ã«çœ®ããšãä»ã® hook ãå
šãŠå®è¡ãããªãç¶æ
ã«ãªããŸãã
ã°ããŒãã«ãšãããžã§ã¯ãã®äž¡æ¹ã«åã hook ãç»é²ããŠããŸã
~/.claude/settings.json ãš .claude/settings.json ã®äž¡æ¹ã«åã hook ãæžããš2åå®è¡ãããŸããããã©ãŒãã³ã¹äžã®åœ±é¿ã¯å°ããã§ããããšã©ãŒã¡ãã»ãŒãžã2è¡åºåãããŠèŠèªæ§ãäžãããŸãããããžã§ã¯ã暪æã§çºçããåé¡ïŒä»åã® && åé¡ãããïŒã¯ã°ããŒãã«ã ãã«æžããŠãã ããããããžã§ã¯ãåºæã®å¶çŽã ããããžã§ã¯ãã® .claude/settings.json ã«æžããšããæ£²ã¿åããæå¿«ã§ãã
hook å ã§ãããã¯ãŒã¯åŒã³åºããéãåŠçãèµ°ããã
Stop hook 㯠Claude ã®å¿çãããããã¯äžãã«ããŠå®è¡ãããŸããhook å ã«å€éš API åŒã³åºããæéã®ãããåŠçãå ¥ãããšããã®é Claude Code å šäœãåŸ æ©ç¶æ ã«ãªããŸããhook ã¯ããã¡ã€ã«ãèªãã§æ£èŠè¡šçŸã§ãã§ãã¯ã㊠exit 0 ã exit 2 ãè¿ããçšåºŠã®åæåŠçã«çµãã¹ãã§ããä»åã® 46 è¡ã¯ãã¡ã€ã«èªã¿èŸŒã¿ãš Python ã¹ã¯ãªããå®è¡ã ãã§ãå®è¡æéã¯éåžž 100ms æªæºã§ãã
ã³ãŒããããã¯å šäœã1ã€ã®è¡ãšããŠåŠçããŠããŸã
Claude ãè€æ°è¡ã®ã³ãŒããããã¯ãšããŠã³ãã³ããæžãå ŽåããããŸãã
```bash
! npx wrangler dev --local && open http://localhost:8787
ãã®ãšã `splitlines()` ã§è¡ããšã«åŠçãããšã` ``` `bash`ïŒãã§ã³ã¹è¡ïŒãšå®éã®ã³ãã³ãè¡ãå¥ã
ã«æ¥ãŸãããã§ã³ã¹è¡ã¯ `^!\s` ã«ãããããªãã®ã§ã¹ããããããã³ãã³ãè¡ã¯æ£ããæ€åºãããŸãããã ãèªåã§ã¹ã¯ãªãããæžãå Žå㯠` ``` ` ã§å§ãŸãè¡ãæç€ºçã«ã¹ãããããããããã¯ã¯ã©ãŒãã strip() ããåŠçãå¿
èŠã§ãã`bang_handoff_amp_guard.sh` ã§ã¯ `strip(bt)` ããã®åœ¹å²ãæ
ã£ãŠããŸãïŒ34ã36è¡ç®ïŒã
**`bad` 倿°ã«è€æ°è¡ãå
¥ã£ãŠæ··ä¹±ãã**
Python ã¹ã¯ãªããã§ `print(s)` ã®åŸã« `break` ãå¿ãããšãè€æ°ã®è¡ããããããŠãã¹ãŠåºåãããŸãã`bad` ã«æ¹è¡æ··ããã®ããã¹ããå
¥ã£ãç¶æ
ã§ã `exit 2` ã¯æ£åžžã«æ©èœããŸããããšã©ãŒã¡ãã»ãŒãžãè€æ°è¡ã«ãªã£ãŠèªã¿ã«ãããªããŸããå®éã®ã¹ã¯ãªããã§ã¯ `print(s)` ãš `break` ãã»ããã«ãªã£ãŠããŸãïŒ38ã39è¡ç®ïŒãæåã®1ä»¶ã§æ¢ããèšèšãæå³çã§ãã
**hook ã¯ããã¹ãå¿çå
ã® `!` ã³ãã³ãã ããæ€æ»ãã**
Bash ããŒã«ãéã㊠Claude ãå®è¡ããã³ãã³ã㯠Stop hook ã®å¯Ÿè±¡å€ã§ããStop hook ãæ€æ»ããã®ã¯ãClaude ã®å¿çããã¹ãã®äžã«ãã `! ` ããå§ãŸãè¡ã ãã§ããBash ããŒã«çµç±ã®åŠçã«åé¡ãããå Žå㯠PostToolUse hook ãªã©å¥ã®ã€ãã³ãã䜿ãå¿
èŠããããŸãããã®éããçè§£ããŠããªããšãBash ããŒã«ã§ã¯ `&&` ãåºãŠããŠãæ¢ãŸããªãããšããçåã«çŽé¢ããŸãââ仿§ã©ããã§ãã
**`^!\s` ã¯å
šè§ã¹ããŒã¹ããããããªã**
`re.match(r'^!\s', s)` ã® `\s` ã¯åè§ã¹ããŒã¹ã»ã¿ãã»æ¹è¡ã«ãããããŸããå
šè§æå笊ïŒïŒïŒãå
šè§ã¹ããŒã¹ã§æžãããã³ãã³ãã¯æ€åºãããŸãããå®éçšã§ãã®ã±ãŒã¹ã¯ã»ãŒçºçããŸããããClaude ãäœããã®çç±ã§å
šè§æåã䜿ã£ãå Žåã¯çŽ éãããŸããå¿
èŠã«å¿ã㊠`s.replace('ïŒ', '!')` ã `s = unicodedata.normalize('NFKC', s)` ã§æ£èŠåããåŠçã远å ã§ããŸãã
---
## ãã¹ããã©ã¯ãã£ã¹
å®éã«åã 46 è¡ãäœããŸã§ã«æŽçãããã«ãŒã«ã§ããåçš®ã®ã¬ãŒã hook ãæ°ããæžããšãã«åãè©°ãŸããèžãŸãªãããã®åºæºãšããŠäœ¿ã£ãŠãã ããã
**1. ãã§ã€ã«ãªãŒãã³ãèšèšã®ååã«ãã**
ã¹ã¯ãªãããèªããªãã»ããŒã¹ã§ããªãã»Python ãèŠã€ãããªãââããããã¹ãŠã®ã±ãŒã¹ã§ `exit 0` ãè¿ããŸãã誀ãããã¯ã®ã³ã¹ãã¯æ€åºæŒãã®ã³ã¹ãããé«ããèªåã®ä»äºãæ¢ãŸããŸãã`&&` ã1åééããããããäœæ¥ãæ¢ãŸãããšã®ã»ããæå€±ã§ãã
```bash
[ -n "$tpath" ] && [ -f "$tpath" ] || exit 0
ãã§ã€ã«ãªãŒãã³ã貫ããäžã§ãããªãééããã®ãããå¥éãããã°ããããããæ£ããé çªã§ãã
2. Python 㯠/usr/bin/python3 ãã«ãã¹ã§åŒã¶
hook ãèµ·åããã·ã§ã«ã¯ ~/.zshrc ãèªã¿ãŸãããnvmã»pyenvã»Homebrew ã® Python 㯠PATH ã«ååšããŸããã/usr/bin/python3 --version ãéãããšãã¿ãŒããã«ã§ç¢ºèªããŠããæžããŠãã ãããã³ãã³ãåã ãã§æžããš hook ã®ç°å¢ã§ã¯èŠã€ãããããã§ã€ã«ãªãŒãã³ã«ãã£ãŠéãã«ééããŸãã
3. Python åã蟌ã¿ã® heredoc ã¯å¿
ã <<'PY'
<<PYïŒã¯ã©ãŒããªãïŒã§ã¯ããã¯ã¹ã©ãã·ã¥ãã·ã§ã«ã«æ¶è²»ãããŸããæ£èŠè¡šçŸã® \s ã s ã«ãªããæ€åºããžãã¯ãå£ããŸãã<<'PY'ïŒã·ã³ã°ã«ã¯ã©ãŒãããïŒã«ãããšãã¢ããã¥ã¡ã³ãå
šäœããªãã©ã«æååãšããŠæž¡ãããŸãããã®1æåã®å·®ã§åäœãæ ¹æ¬ããå€ãããŸããPython ã³ãŒãã heredoc ã«åã蟌ãå Žåã¯ç¡æ¡ä»¶ã«ã·ã³ã°ã«ã¯ã©ãŒããã€ããŠãã ããã
4. type ãš role ã or ã§äž¡æ¹ãã§ãã¯ãã
if o.get("type") == "assistant" or o.get("role") == "assistant":
Claude Code ã®ãã©ã³ã¹ã¯ãªãã JSONL ã¯ããŒãžã§ã³ãšäŒè©±é·ã«ãã£ãŠãã£ãŒã«ãåãå€ãããŸããã©ã¡ããã ããèŠãŠãããšãç¹å®ã®ã»ãã·ã§ã³æ§æã§æ€åºæŒããçºçããŸããçæ¹ãå€ãã£ãŠããããçæ¹ã§ã«ããŒã§ããŸããClaude Code ã®ã¢ããããŒãã«å¯Ÿã㊠hook ã匷ãããããã®æå°éã®é²åŸ¡ã§ãã
5. ããã¯ã¯ã©ãŒã㯠chr(96) ã§éæ¥çæãã
ã¹ã¯ãªããæ¬æã«ããã¯ã¯ã©ãŒãããªãã©ã«ã§æžããšãeval ãå¥ã¹ã¯ãªããããã® source çµç±ã§åããããšãã«èªå·±ããŒã¹ãšã©ãŒãçºçãããªã¹ã¯ããããŸããbt = chr(96) ã§å®è¡æã«æåãçæããln.strip().strip(bt).strip() ãšããŠäœ¿ããŸããã¹ã¯ãªããæ¬æã«ããã¯ã¯ã©ãŒããäžæåãç»å Žããªãç¶æ
ãå®å
šã§ãã
6. stdin=$(cat) ã§æšæºå
¥åãå
ã«å€æ°ã«åãã
stdin ã¯äžåºŠããèªããŸãããæåã« input=$(cat) ã§å
šéšåã蟌ã¿ãprintf '%s' "$input" ã§äœåºŠã§ãåå©çšã§ãã圢ã«ããŸããããã¯ã·ã§ã«ã¹ã¯ãªããã§ stdin ãæ±ãæ®éçãªåã§ããå°æ¥ã¹ã¯ãªãããæ¡åŒµããŠè€æ°ã®å€ãåãåºãå Žåããæåãã倿°ã«åããŠããã°è©°ãŸããŸããã
7. ãšã©ãŒã¡ãã»ãŒãžã«çç±ã»æ¥ä»ã»ä¿®æ£æ¹æ³ãå šéšå ¥ãã
echo "ð« ! ãã³ããªãã« && ã䜿ã£ã(æ¬äººã5åä»¥äžæææž)ã... >> && ãåäž & ã«çŽããŠåºãçŽã <<ã該åœè¡: ${bad}" >&2
ãã®ã¡ãã»ãŒãžã¯å°æ¥ã® ClaudeïŒæ¬¡ã®ã»ãã·ã§ã³ä»¥éãå«ãïŒãžã®æç€ºã§ããããªããããã¯ããããããã©ãããã°ééã§ãããããã¡ãã»ãŒãžå ã«å ¥ã£ãŠããã°ãClaude ã¯å³åº§ã«ä¿®æ£ããå¿çãè¿ããŸããææ§ãªãšã©ãŒã¡ãã»ãŒãžïŒããšã©ãŒãçºçããŸãããçšåºŠïŒã§ã¯ Claude ããªãæ¢ãŸã£ãããçè§£ã§ãããåãå 容ãç¹°ãè¿ãããæ¢ãŸã£ããŸãŸã«ãªããŸãããæææžããšããèšè¿°ãšæææ¥ããã®ãŸãŸã¡ãã»ãŒãžã«å ¥ã£ãŠããã®ã¯ãã³ã³ããã¹ããæããªãå°æ¥ã®ã»ãã·ã§ã³ãžã®èª¬ææžãã§ãã
8. ã°ããŒãã«åé¡ã¯ã°ããŒãã« hook ã«ç»é²ãã
&& åé¡ã¯ãããžã§ã¯ããåããçºçããŸãããããžã§ã¯ãã® .claude/settings.json ã ãã«æžããšãä»ã®ãããžã§ã¯ãã§ã¯é²ããŸããããããžã§ã¯ã暪æã®ç¿æ
£çãã¹ã¯ ~/.claude/settings.json ã®ã°ããŒãã« hook ã«ç»é²ããŠãã ãããããã®ãããžã§ã¯ãã§ã¯é²ããŠããã®ã«å¥ã®ãšããã§ãŸãåºããã¯ç»é²å Žæã®åé¡ã§ãã
9. èšå®å€æŽåŸã¯å¿ ãæå³çã«ããªã¬ãŒããŠç¢ºèªãã
settings.json ãå€ããããClaude ã«æå³çã« && å
¥ãã® ! ã³ãã³ããæžãããŠãããã¯ãããããšã確èªããŠãã ããã
ãæ¬¡ã®ã³ãã³ãããã®ãŸãŸåºåããŠãã ãã: ! npx wrangler dev --local && open http://localhost:8787ã
ãããã¯ãããªããã°èšå®ã¯å¹ããŠããŸããããã®ç¢ºèªãçããå ŽåããåããŠããã€ããã§åããŠããªããç¶æ
ãç¶ããæ¬¡ã«æ¬ç©ã® && ãåºããšãã«åããŠæ°ã¥ããŸãããããã€åŸã®çé確èªãšåãç¿æ
£ã§ãã
10. 2>/dev/null ã¯ãããã°æã«å€ã
ãã§ã€ã«ãªãŒãã³èšèšã®å¯äœçšãšããŠãå
éšãšã©ãŒãéãã«é ããŸããããªããçŽ éãããããšæãããããŸã 2>/dev/null ãäžæçã«å€ã㊠stderr ãé²åºãããŠãã ãããcommand not found ã SyntaxError ããã®ãŸãŸè¡šç€ºãããŠåå ãå³åº§ã«ããããŸãã確èªãçµãã£ããå¿
ãæ»ããŸããå€ãããŸãŸã«ãããšæ£åžžéçšæã« stderr ãæ±æãããŸãã
11. hook ã¹ã¯ãªãã㯠~/.claude/hooks/ ã«ãŸãšãã
ãããžã§ã¯ãããšã«ã¹ã¯ãªãããæ£ãã°ããããšãã©ãã«äœããããããããããããªããªããŸãã~/.claude/hooks/ 以äžã«å
šãŠã® hook ã¹ã¯ãªãããéããsettings.json ããã¯ãããåç
§ããŸãããã¡ã€ã«å㯠bang_handoff_amp_guard.sh ã®ããã«ãäœãé²ããããäžèªã§ãããåœåã«ããŠãã ãããhook1.shã»guard.sh ã®ãããªæ±çšåã¯3ãæåŸã«èªåãèªãã§ãæå³ãããããŸããã
12. æåŸã® assistant ã¡ãã»ãŒãžã ããæ€æ»ãã
last = msgs[-1] if msgs else ""
å
šã¡ãã»ãŒãžãã¹ãã£ã³ãããšãéå»ã®äŒè©±ã«å«ãŸãã ! ã³ãã³ãã®æ®éªžãæŸã£ãŠèª€ãããã¯ãçºçããŸããä»åã®å¿çã ããæ€æ»ããããã« msgs[-1] ã§æåŸã®1ä»¶ã«çµãèšèšã¯æå³çãªéžæã§ããéå»ã®ã¡ãã»ãŒãžã«å«ãŸãã && ã¯é¢ä¿ãªãââåé¡ã¯ãä»ãã®ç¬é Claude ãæžãããã®ãã ãã§ãã
13. ã³ãŒããããšã©ãŒã¡ãã»ãŒãžã«çç±ãæžã
ã¹ã¯ãªããæ¬æã®ã³ã¡ã³ãã¯å°æ¥åãããå¯èœæ§ããããŸãããšã©ãŒã¡ãã»ãŒãžã¯ Claude ãåãåã£ããšãã«èªããã®ãªã®ã§åããŸãããèšèšå€æã®çç±ã¯ # ã³ã¡ã³ã ã§ã¯ãªã echo "..." >&2 ã®ãšã©ãŒã¡ãã»ãŒãžæ¬æã«æžããŠãã ãããbang_handoff_amp_guard.sh ã®1ã4è¡ç®ïŒã³ã¡ã³ãïŒãš44è¡ç®ïŒãšã©ãŒã¡ãã»ãŒãžïŒã®äž¡æ¹ã«ãæ¬äººã5åä»¥äžæææž(2026-07-16)ããšæžããŠããã®ã¯ãã®ããã§ããã³ã¡ã³ããèªãŸããªããŠãããšã©ãŒã¡ãã»ãŒãžã¯å¿
ãèªãŸããŸãã
ãŸãšã
å£é ã§5åææããŠãçŽããªãã£ãããããã³ãŒãã§ç©ççã«å°ããã®ãã46è¡ã®ã·ã§ã«ã¹ã¯ãªããã§ãã
Stop hook ã¯ãClaude ãå¿çãè¿ãçŽåã«å²ã蟌ããä»çµã¿ã§ãããã©ã³ã¹ã¯ãªãã JSONL ã Python ã§ããŒã¹ããæåŸã® assistant ã¡ãã»ãŒãžã ããåãåºãã^!\s ã«ãããããè¡ã« && ãå«ãŸããŠããã° exit 2 ã§ãããã¯ãããæ§é ã¯ã·ã³ãã«ã§ãã
ãã ããåçŽãªããšãã»ãã·ã§ã³ããŸããã§ç¢ºå®ã«åãããããã«ããã§ã€ã«ãªãŒãã³ã»/usr/bin/python3 ãã«ãã¹ã»<<'PY' ã·ã³ã°ã«ã¯ã©ãŒãã»type/role äž¡ãã£ãŒã«ãåç
§ã»chr(96) 鿥çæââãããã®èšèšå€æãå¿
èŠã§ãããè©°ãŸã£ã4åãšãéçšã§æ°ã¥ãã远å ã®èœãšã穎ã¯ãã©ãããç¥ã£ãŠããã°5åã§ééã§ãããã®ãã§ãããããæžããã®ã¯ãåãæéã䜿ããã«æžãããã«ããããã§ãã
Claude ã«äœåºŠèšã£ãŠãçŽããªãããšããããããã¯ã¢ãŒããã¯ãã£ã®åé¡ã§ãã£ãŠãClaude ã®æ æ ¢ã§ããèªåã®ææã®ä»æ¹ã®åé¡ã§ããããŸãããã»ãã·ã§ã³ã¯äŒè©±ããšã«ç¬ç«ããŠãããææã¯ã³ã³ããã¹ãã«ä¹ããã³ã³ããã¹ãã¯ã»ãã·ã§ã³ãšå ±ã«æ¶ããŸãã解決çã¯ææã®å埩ã§ã¯ãªãããç©ççã«ééã§ããªãç°å¢ãäœããããšââããã Stop hook ãšããèšèšææ³ã®æ žå¿ã§ãã
æå120äžã®èªåŸç°å¢ã§åã倱æãç¹°ãè¿ãããªãã®ã¯ããã®ããã«ãå£é ã§ã¯ãªãã³ãŒãã§çŽãããç©ã¿éããŠããããã§ããäžã€ã®ã¹ã¯ãªãããäžã€ã®ç¹°ãè¿ããæã¡åãããããç¶ããçµæãä»ã®ç°å¢ã§ãã
ä»çµã¿ã®å šäœåã»æ120äžã®å èš³ã»30æ¥æé ã¯æænoteã«ãŸãšããŠããŸãã
ð Claude CodeèªåŸç°å¢ã§ãå®éã©ã皌ãã â ä»çµã¿ã»å®äŸã»å§ãæ¹ã»ãµããŒã
LilyïŒ@bokuwalilyïŒâ å人éçºè ãClaude Code ã§èªåååºç€ãçµã¿ãªãããiOSã¢ããªãWebãµãŒãã¹ãéç£ããŠããŸã
- AIã§ãå¯ãŠãŠãåãä»çµã¿ããäœã£ãŠæ120äžã«ãã話㯠noteã®ææèšäº ã«ð°
- OSS: github.com/bokuwalily ð
- ææ°æ å ±ã»ãåãåãã㯠X @bokuwalily ãžð
- AIå°å ¥ã»èªååã®çžè«ãšå®è£ ãã³ãã¬7æ¬ã®é åžã¯ å ¬åŒLINE ããð¬
çããã® â€ïž ãã·ã§ã¢ãå±ã¿ã«ãªããŸãïŒ