Gabay

Claude Code hooks: paano gawing garantiya ang mga panuntunan ng agent

Na-update: · Skillaria.Top

Ang Claude Code hooks ay mga shell command na mismong Claude Code ang nagpapatakbo sa tiyak na mga pangyayari: bago at pagkatapos tumawag ng tool, kapag may ipinadalang prompt, sa simula ng session, at bago huminto ang agent. Itinatakda ang mga ito sa settings.json, at hinaharangan ng exit code 2 ang aksyon at ibinabalik sa agent ang mensahe ng error, kaya ginagawang garantiyang hindi malilimutan ng modelo ang panuntunan mula sa CLAUDE.md.

Ano ang mga hook ng Claude Code

Ang hook ay command na pinapatakbo hindi ng modelo, kundi mismo ng programang Claude Code sa itinakdang sandali ng trabaho ng agent. Akmang gagawin ng agent ang rm -rf: tumatakbo ang hook at pinapasya kung papayagan ang command. Nag-edit ng file ang agent: pinapatakbo ng hook ang formatter. Gustong tapusin ng agent ang trabaho: pinapatakbo ng hook ang mga test at hindi siya hinahayaang huminto habang pula pa ang mga ito.

Ang pangunahing pagkakaiba sa mga tagubilin sa CLAUDE.md: ang tagubilin ay teksto na isinasaalang-alang ng modelo nang may tiyak na posibilidad, samantalang ang hook ay deterministikong code. Laging tatakbo ito, anuman ang haba ng context, anuman ang "napagpasyahan" ng agent, at kahit makalimutan niya ang panuntunan sa ika-100 minuto ng session. Kaya ang claude code hooks ang pangunahing paraan para gawing garantiya ang kagustuhan.

Bakit hindi sapat ang mga panuntunan sa CLAUDE.md

Karaniwang eksena: tinapos ng agent ang feature, berde ang unit test, at may tiwalang "Tapos na" sa chat. Pero walang nagpatakbo ng end-to-end na senaryo, hindi tumakbo ang linter, at pumalya ang migration sa kalagitnaan. Nakasulat naman sa CLAUDE.md na "bago tapusin, patakbuhin ang test." Hindi nagsisinungaling nang sadya ang modelo; sinusuri lang niya ang sarili niya, at hindi maaasahan ang ganoong pagsusuri.

Dito nanggagaling ang prinsipyo ng harness: ang anumang kayang suriin nang mekanikal ay dapat suriin ng mekanismo, hindi ng modelo. Ang panuntunang "patakbuhin ang linter" ay nagiging hook na nagpapatakbo ng linter. Ang panuntunang "huwag galawin ang prod config" ay nagiging hook na humaharang sa pagsulat sa file na iyon. Nananatili ang tekstong tagubilin, pero nagsisilbi na lamang itong paliwanag sa agent kung bakit siya hinarang.

Mga event: kailan tumatakbo ang mga hook

Bawat hook ay nakakabit sa isang event ng lifecycle ng session. Ang mga pangunahing event:

EventKailan tumatakboKaraniwang gamit
PreToolUsebago tumawag ng tool (Bash, Edit, Write at iba pa)pagbabawal ng mapanganib na command, proteksyon ng file
PostToolUsepagkatapos ng matagumpay na tawag ng toolformatter, linter, mabilis na test pagkatapos ng edit
UserPromptSubmitkapag naipadala ng user ang prompt, bago ito iprosesomagdagdag ng context, tanggihan ang prompt na may secret
Stopkapag malapit nang tapusin ng agent ang sagothuwag hayaang huminto hangga't hindi pumapasa ang mga pagsusuri
SubagentStopkapag tapos na ang trabaho ng subagentpagsusuri sa resulta ng subagent
SessionStartsa pagsisimula o pagpapatuloy ng sessionilabas ang estado: git status, plano, log ng progreso
SessionEndkapag natapos ang sessionpaglilinis, pagsulat ng log
Notificationkapag nagpadala ng notification ang Claude Code (halimbawa, naghihintay ng pahintulot)tunog o mensahe sa telepono
PreCompactbago paikliin ang contextitago ang mahalaga bago ang compaction

Ang pinakamakabuluhan para sa pagiging maaasahan ay ang PreToolUse, PostToolUse, at Stop: tinatakpan nila ang tatlong mahinang bahagi ng agent: mapanganib na aksyon, hindi nasuring pagbabago, at maagang pag-aangking tapos na.

Saan itinatakda ang mga hook: settings.json

Inilalarawan ang mga hook sa mga file ng setting ng Claude Code:

  • ~/.claude/settings.json — inyong personal na setting, para sa lahat ng proyekto;
  • .claude/settings.json sa repositoryo — para sa buong team, kino-commit sa git;
  • .claude/settings.local.json — lokal sa proyekto, hindi napupunta sa git.

Ganito ang istruktura: event → listahan ng mga grupo na may matcher → listahan ng mga command.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/lint.sh",
            "timeout": 60
          }
        ]
      }
    ]
  }
}

Ang matcher ay pangalan ng tool o regular expression sa pangalan nito: Bash, Edit|Write, .*. Kailangan ito para sa mga event na may kinalaman sa tool; para sa Stop o UserPromptSubmit ay maaari itong hindi ilagay. Itinuturo ng variable na CLAUDE_PROJECT_DIR ang ugat ng proyekto, kaya maginhawang itago ang mga script sa .claude/hooks/ at tawagin sa pamamagitan nito. Makikita ang kasalukuyang hook gamit ang command na /hooks sa loob ng Claude Code.

Paano kumukuha ng datos at sumasagot ang hook

Input: JSON sa stdin

Ipinapasa ng Claude Code sa hook ang JSON na may impormasyon tungkol sa event: ID ng session, working directory, pangalan ng event, at para sa mga tool ay ang tool_name at tool_input. Sa Bash, nasa tool_input.command ang command; sa Edit at Write, nasa tool_input.file_path ang landas ng file. Maginhawang basahin ito gamit ang jq.

{
  "session_id": "abc123",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": { "command": "rm -rf build/" },
  "cwd": "/home/dev/project"
}

Output: exit code

CodeAno ang nangyayari
0tagumpay, tuloy ang trabaho; para sa UserPromptSubmit at SessionStart, idinadagdag ang stdout sa context ng agent
2nakaharang na error: ipinapasa ang stderr sa agent at hinihinto ang aksyon (sa PreToolUse — kinakansela ang tawag ng tool; sa Stop — nagpapatuloy ang agent)
iba pahindi nakaharang na error: ipinapakita ang stderr sa user, tuloy ang trabaho

Ang exit code 2 ang pangunahing mekanismo. Tinatanggap ng agent ang teksto mula sa stderr bilang feedback at maaari siyang mag-ayos: isulat muli ang command, ayusin ang test, o huwag galawin ang file. Kaya sa stderr ay huwag isulat ang "error" lamang, kundi ang malinaw na dahilan at kung ano ang dapat gawin sa halip.

Bukod sa exit code, maaaring maglabas ang hook ng JSON sa stdout na may desisyon, halimbawa "decision": "block" at "reason". Kapaki-pakinabang ito para sa mas pinong setup, pero sa karamihan ng gawain ay sapat na ang code 2 at ang mensahe sa stderr.

Halimbawa 1: linter at test pagkatapos ng bawat edit

Ang hook sa PostToolUse na may matcher na Edit|Write ay tumatakbo pagkatapos baguhin ang file. Tapos na ang tool, hindi na mababawi ang edit, pero ibabalik ng code 2 sa agent ang output ng linter, at aayusin niya agad ang error, hindi makalipas ang kalahating oras.

#!/usr/bin/env bash
# .claude/hooks/lint.sh
file=$(jq -r '.tool_input.file_path // empty')
case "$file" in
  *.py)
    if ! out=$(ruff check "$file" 2>&1); then
      echo "Nakita ng linter ang mga error sa $file:" >&2
      echo "$out" >&2
      exit 2
    fi ;;
  *.php)
    if ! out=$(php -l "$file" 2>&1); then
      echo "$out" >&2
      exit 2
    fi ;;
esac
exit 0

Huwag ilagay dito ang buong pagpapatakbo ng test na sampung minuto: tumatakbo ang hook sa bawat edit. Pagkatapos ng edit, mabilis na pagsusuri lamang (syntax, linter, test ng iisang module), at ang mabibigat ay sa hook na Stop.

Halimbawa 2: pagbabawal ng mapanganib na command

Ang hook sa PreToolUse na may matcher na Bash ay nakikita ang command bago ito patakbuhin. Kinakansela ng code 2 ang tawag at nakukuha ng agent ang paliwanag.

#!/usr/bin/env bash
# .claude/hooks/guard.sh
cmd=$(jq -r '.tool_input.command // empty')
if echo "$cmd" | grep -Eq 'rm -rf /|git push (-f|--force)|DROP (TABLE|DATABASE)'; then
  echo "Hinarang ang command ayon sa patakaran ng proyekto: $cmd. Ang tao ang nagpapatakbo ng mapanganib na operasyon." >&2
  exit 2
fi
exit 0

Ganito rin ang proteksyon ng mga file: sinusuri ng hook sa Edit|Write ang file_path at hinaharangan ang pagsulat sa .env, prod config, nabuong code, o mga migration file na nailapat na. Tandaan na nalulusutan ang paghahanap gamit ang regular expression: maaaring isulat ng agent ang command sa ibang paraan. Ang hook ay malakas na proteksyon, pero hindi kapalit ng karapatan ng access at sandbox.

Halimbawa 3: hindi maisusulat ng agent na "tapos na" habang pula ang test

Tumatakbo ang hook na Stop kapag malapit nang tapusin ng agent. Kung hindi pumapasa ang mga test, pinipigilan ito ng code 2 sa paghinto, at ang output ng test ay ipinapasa sa agent bilang susunod niyang gawain. Ito ang mekanikal na bersyon ng Definition of Done.

#!/usr/bin/env bash
# .claude/hooks/done.sh
input=$(cat)
# proteksyon laban sa walang katapusang loop: minsan nang pinahaba ng hook ang trabaho
if [ "$(echo "$input" | jq -r '.stop_hook_active')" = "true" ]; then
  exit 0
fi
if ! out=$(npm test --silent 2>&1); then
  echo "Hindi pumasa ang mga test, hindi pa tapos ang trabaho:" >&2
  echo "$out" | tail -n 40 >&2
  exit 2
fi
exit 0

Nagiging true ang field na stop_hook_active kapag nagpapatuloy na ang agent dahil sa stop hook. Kung walang ganitong tseke, maaaring paikutin ng hook ang agent nang walang katapusan, ang sitwasyong "nagtatrabaho ang agent buong gabi sa maling direksyon." Sa mga autonomous loop, magdagdag pa ng limitasyon ng pagsubok at kondisyong tumatawag ng tao.

Halimbawa 4: ilabas ang estado sa simula ng session

Sa SessionStart, napupunta sa context ang stdout ng hook. Maginhawang ilabas dito ang kasalukuyang branch, mga hindi pa naka-commit na pagbabago, at susunod na gawain mula sa plano, para hindi magsimula sa wala ang agent.

#!/usr/bin/env bash
echo "Branch: $(git branch --show-current)"
git status --short | head -n 20
[ -f PROGRESS.md ] && tail -n 15 PROGRESS.md
exit 0

Paano ginagawang garantiya ng mga hook ang mga panuntunan

Makatutulong na hatiin ang mga panuntunan ng harness sa tatlong antas. Una, ang teksto sa CLAUDE.md: nagpapaliwanag kung paano magtrabaho, pero sinusunod nang probabilistiko. Pangalawa, ang mga executable na pagsusuri: test, E2E, at mga architectural na panuntunan sa anyo ng script na pumapalya kapag may nalabag. Pangatlo, ang mga hook na awtomatikong nagpapatakbo ng mga pagsusuring ito sa tamang sandali, nang walang pakikialam ng modelo.

Praktikal na panuntunan: kung paulit-ulit nalabag ng agent ang iisang panuntunan, huwag magdagdag ng isa pang babala sa CLAUDE.md na naka-CAPS LOCK. Itanong kung maaaring suriin ang paglabag sa pamamagitan ng script. Kung oo, gumawa ng script at ikabit ito sa hook. Sa ganitong paraan, mas maikli ang tagubilin at mas matatag ang pag-uugali.

Panuntunan sa tekstoGarantiya sa pamamagitan ng hook
"Sundin ang pamantayan sa pag-format ng code"Pinapatakbo ng PostToolUse ang formatter sa binagong file
"Huwag mag-push nang may force"Hinaharang ng PreToolUse sa Bash ang command, exit 2
"Huwag sabihing tapos na habang pula ang test"Pinapatakbo ng Stop ang test at hindi pinapayagang tapusin
"Huwag i-edit ang .env"Sinusuri ng PreToolUse sa Edit|Write ang landas
"Tandaan kung saan tumigil"Inilalabas ng SessionStart ang plano at git status

Karaniwang pagkakamali

  • Code 1 sa halip na 2. Pumapalya ang script na may code 1, hindi malalaman ng agent, at dadaan ang aksyon. Tanging code 2 ang humaharang.
  • Mensahe sa stdout. Sa code 2, stderr ang ipinapasa sa agent. Isulat sa pamamagitan ng >&2.
  • Mabagal na hook sa madalas na event. Ang buong pagpapatakbo ng test sa PostToolUse ay nagpapabagal sa bawat edit nang isang minuto. Ang mabigat ay ilagay sa Stop.
  • Walang katapusang Stop. Walang tseke ng stop_hook_active o limitasyon, kaya umiikot ang agent nang walang hanggan.
  • Kamag-anak na landas. Tumatakbo ang hook sa working directory ng session; gamitin ang $CLAUDE_PROJECT_DIR.
  • Hindi nasuring hook ng iba. Tumatakbo ang hook gamit ang inyong karapatan nang walang kumpirmasyon. Basahin ang mga script mula sa ibang repositoryo bago sila pagkatiwalaan.

Buod

Inililipat ng Claude Code hooks ang pinakamahahalagang panuntunan mula sa teksto papunta sa code: hinihinto ng PreToolUse ang mapanganib na aksyon, sinusuri ng PostToolUse ang bawat edit, hindi hinahayaang mag-ulat ng pagiging handa ang Stop nang maaga, at ibinabalik ng SessionStart sa agent ang alaala tungkol sa proyekto. Magsimula sa dalawa o tatlong hook para sa mga panuntunang nalabag na ng agent, at panatilihing malinaw ang mga mensahe sa stderr. Kaya ng agent na ayusin ang sarili niyang mga error, at ang inyong trabaho ay suriin ang resulta sa halip na ang proseso. Ang beripikasyon, pagsusuri ng pagiging handa, at mga autonomous loop ay tinatalakay nang praktikal sa kurso.

Mga madalas itanong

Kailangan bang i-restart ang Claude Code pagkatapos baguhin ang mga hook?

Pinakamaaasahang nailalapat ang mga pagbabago sa settings.json sa bagong session; makikita ang kasalukuyang configuration ng hook gamit ang /hooks.

Puwede bang isulat ang mga hook sa ibang wika bukod sa bash?

Oo, anumang command ang hook: script sa Python, Node.js, o binary. Ang mahalaga lamang ay basahin ang JSON mula sa stdin at magbalik ng tamang exit code.

Nakikita ba ng agent ang output ng matagumpay na hook?

Karaniwan hindi: sa code 0, hindi napupunta sa context ang output. Ang eksepsyon ay ang UserPromptSubmit at SessionStart, kung saan idinadagdag ang stdout sa context ng agent.

Gumagana ba ang mga hook para sa mga subagent?

Oo, dumadaan sa parehong hook na PreToolUse at PostToolUse ang mga tawag ng tool ng subagent, at may hiwalay na event na SubagentStop para sa pagtatapos nila.

Ligtas bang i-commit ang mga hook sa repositoryo?

Oo, ang .claude/settings.json at mga script sa .claude/hooks/ ay karaniwang gawain para sa team; ang personal na hook ay itago sa settings.local.json o sa ~/.claude/settings.json.