Tinklaraštis

Hooks Claude Code 2026: konfigūravimas žingsnis po žingsnio ir 7 paruošti naudoti pavyzdžiai

Markdown

7 paruošti naudoti hooks failui .claude/settings.json, kuriuos galima kopijuoti ir įklijuoti: .env apsauga, prettier, force-push į main, ilgieji brūkšniai ir kūrimo serveris. 4 apdorojimo tipai ir 31 įvykis.

Skaityti visą straipsnį

Claude Code hooks yra shell komandos, HTTP iškvietimai arba trumpos LLM patikros, kurios automatiškai vykdomos prieš Claude veiksmą arba po jo. Jos prideda patikrų konkretiems įrankių įvykiams, suformatuoja kodą po redagavimo ir įterpia kontekstą sesijos pradžioje. Atitinkantis PreToolUse hook gali atmesti tą iškvietimą; šie reguliariųjų išraiškų pavyzdžiai yra patogumo apsaugos, o ne visų failų ar Git prieigos kelių saugumo riba. Toliau pateikiama 4 apdorojimo tipų, 31 gyvavimo ciklo įvykio apžvalga, patikra „kada taisyklė priklauso hook“, 7 paruošti kopijuoti hooks failui .claude/settings.json ir 3 spąstai, su kuriais teko susidurti man pačiam.

Ailoot dokumentacija: API, raktai ir konfigūravimas.

Kas yra Claude Code hooks?

Pagrindinė įžvalga

Hook yra shell komanda, HTTP iškvietimas, trumpa LLM užklausa arba subagentas, kurį Claude Code paleidžia reaguodamas į konkretų gyvavimo ciklo įvykį. Skirtingai nuo CLAUDE.md nurodymų, kuriuos modelis gali ignoruoti arba pamiršti, hook kiekvieną kartą veikia vienodai: tai kodas, o ne pasiūlymas.

Pusę metų taisyklę „niekada neredaguoti .env tiesiogiai“ laikiau CLAUDE.md faile. Claude ją pažeisdavo kartą per mėnesį. Ne iš piktos valios; ilgos sesijos pabaigoje jis tiesiog pamiršdavo. Kartą .env faile atsirado papildomas tokenas; kitą kartą kintamasis pasikartojančiu pavadinimu perrašė naudojamą kintamąjį.

Perkėliau šią taisyklę į hook, kad jos būtų neįmanoma pamiršti. Kai atitinkantis tiesioginio redagavimo įrankis pateikia .env kelią, sukonfigūruotas hook atmeta tą iškvietimą. Bash nukreipimui, scenarijams, MCP ir kitiems keliams reikia atskirų valdiklių; pavyzdys nepadaro failo nekeičiamo.

Hooks yra jūsų apibrėžtos shell komandos, HTTP galiniai taškai arba LLM užklausos, kurios automatiškai vykdomos konkrečiais Claude Code gyvavimo ciklo momentais.

— Anthropic, https://code.claude.com/docs/en/hooks

Kitaip tariant, hook yra jūsų komanda, kurią Claude Code paleidžia įvykus konkrečiam įvykiui. Kiekvienas failo redagavimas, Bash paleidimas, sesijos pradžia arba subagento užbaigimas yra įvykis, prie kurio galite priskirti hook.

Kodėl tai svarbu vibe coder:

  • Apsaugokite failus su paslaptimis nuo atsitiktinio redagavimo.
  • Automatiškai paleiskite prettier/eslint po kiekvieno kodo generavimo.
  • Blokuokite git push --force į main be aiškaus leidimo.
  • Įterpkite naują kontekstą kiekvienos sesijos pradžioje.
  • Registruokite Claude veiksmus auditui.

CLAUDE.md tvarko kontekstą. Hooks tvarko veiksmus. Tai du skirtingi dalykai, o jų painiojimas yra pagrindinė pradedančiųjų klaida.

Kuo hooks skiriasi nuo CLAUDE.md ir skills?

Pagrindinė įžvalga

CLAUDE.md yra tekstas, kurį modelis perskaito sesijos pradžioje ir bando vykdyti. Hook yra shell komanda, kurią Claude Code procesas paleidžia reaguodamas į įvykį, nepriklausomai nuo modelio. Skill yra įvardytas nurodymų paketas, kurį Claude gali iškviesti naudodamas Skill įrankį, tarsi funkciją. Visi trys skirti skirtingoms užduotims.

Anthropic dokumentacijoje aiškiai paaiškinamas skirtumas tarp CLAUDE.md ir hooks:

CLAUDE.md turinys pateikiamas kaip naudotojo pranešimas po system prompt, o ne kaip system prompt dalis. Claude jį perskaito ir bando vykdyti, bet griežtas laikymasis negarantuojamas.

— Anthropic, atminties dokumentacija, https://code.claude.com/docs/en/memory

Kitaip tariant, CLAUDE.md turinys Claude pasiekia kaip pirmasis naudotojo pranešimas, o ne kaip sistemos nurodymas. Modelis jį perskaitys ir bandys vykdyti. Tačiau garantijų nėra, ypač ilgos sesijos pabaigoje, kai kontekstas išauga, o senesni nurodymai išstumiami.

Hook veikia kitaip. Jis yra settings.json faile, nepriklauso nuo modelio ir paleidžiamas Claude Code proceso konkretaus įvykio metu: PreToolUse, PostToolUse, SessionStart ir kitų. Komanda įvykdoma prieš Claude gaunant rezultatą ir gali fiziškai užblokuoti veiksmą (exit 2) arba pakeisti failą po redagavimo (exit 0).

Palyginimas:

FunkcijaCLAUDE.mdHookSkill
Kur yraCLAUDE.md projekto šakniniame kataloge.claude/settings.json.claude/skills/ aplankas
Kas vykdoModelis perskaito jį kaip naudotojo pranešimo dalįClaude Code procesas įvykio metuModelis per Skill įrankį
Vykdymo garantijaNe (geriausių pastangų principu)Sukonfigūruotas atitinkantis komandinis hook vykdo kodą; nesėkmės ir išėjimo elgsena priklauso nuo įvykioModelio iškvietimu (su suteiktomis teisėmis, bet ne shell lygmeniu)
Kam skirtaProjekto kontekstui, tonui, stiliui, maršrutizavimuiApribojimams, formatavimui, konkrečių failų patikromsSudėtingoms kelių žingsnių procedūroms su parametrais
Kada vykdomaKiekvieno modelio pranešimo metu sesijojeGyvavimo ciklo įvykio metuKai iškviečia modelis
Ar gali blokuoti veiksmą?NeTaip (exit 2)Ne

Visą CLAUDE.md šabloną ir 6 taisykles, kaip prižiūrėti šį failą, rasite vadove Kaip sukonfigūruoti CLAUDE.md 2026 m.: paruoštas šablonas ir 6 taisyklės. Apie skills kaip įvardytas galimybes skaitykite Claude Code Skills: kaip susikurti savo biblioteką.

Hook yra žemiausias lygmuo: jokio modelio, jokio interpretavimo, tik shell.

Hooks yra vienas iš konteksto inžinerijos įrankių, kartu su Plan Mode ir /compact.

4 hook tipai: Command, HTTP, Prompt, Agent — kurį pasirinkti?

Pagrindinė įžvalga

Claude Code turi 4 apdorojimo tipus. Command yra shell scenarijus, dažniausiai naudojamas tipas. HTTP siunčia POST užklausą į jūsų URL, skirtas komandoms ir integracijoms. Prompt atlieka trumpą Haiku iškvietimą semantinei patikrai. Agent sukuria subagentą su įrankių prieiga išsamiai validacijai. Pradedantiesiems reikia Command ir Prompt; jie apima 90% užduočių.

TipasKą daroKada rinktisSudėtingumas
CommandPaleidžia shell komandą, gauna JSON per stdin ir atsako išėjimo kodu bei stdout90% atvejų: kelių tikrinimas, formatavimas, grep turinyje, lsof, git operacijosmažas
HTTPSiunčia POST užklausą jūsų URL su JSON turiniu ir gauna JSON atsakymąKai taisyklė skirta komandai/CI: centralizuota validacija, bendra būsenos suvestinė, nuotolinis auditasvidutinis (reikia serverio)
PromptNusiunčia trumpą užklausą Haiku (pagal numatytuosius nustatymus) ir gauna taip/ne semantiniam vertinimuiKai grep nepakanka: „įvertink, ar šis tekstas skamba korporatyviai“mažas
AgentSukuria subagentą su Read/Grep/Glob prieiga kelių žingsnių patikromsSudėtingai validacijai: „rask visus pakeistus failus ir patikrink, ar yra atitinkami tests“didelis

Dažniausia klaida – bandyti su Command atlikti tai, kam reikia Prompt. Pavyzdžiui, „nenaudok ilgųjų brūkšnių .md failuose“ yra grep užduotis, todėl Command puikiai tinka. Tačiau „nerašyk korporatyviniu tonu“ yra semantinė taisyklė, todėl jai reikia Prompt.

Jei tik pradedate, naudokite Command. Visi 7 toliau pateikti paruošti hooks yra Command tipo. HTTP/Prompt/Agent ateis vėliau, kai būsite pasirengę.

Kur yra settings.json ir kokie yra 4 konfigūracijos lygiai?

Pagrindinė įžvalga

Claude Code ieško konfigūracijos 4 vietose: įmonės (platinama per MDM), naudotojo (~/.claude/settings.json), projekto (.claude/settings.json saugyklos šakniniame kataloge) ir vietinėje (.claude/settings.local.json, neįtraukiama į git). Visi 4 failai sujungiami sesijos pradžioje, o žemesnio lygio nustatymai turi pirmenybę.

LygisKeliasKada taikomasGit saugykloje?
Įmonės/Library/Application Support/ClaudeCode/settings.json (Mac), /etc/claude-code/settings.json (Linux)Visoje komandoje per MDMne
Naudotojo~/.claude/settings.jsonVisuose vieno naudotojo projektuosene
Projekto.claude/settings.json saugyklos šakniniame katalogeŠiam projektui, visai komandaitaip
Vietinis.claude/settings.local.jsonTik šiam projektui ir tik šiam naudotojuine (.gitignore faile)

Visus 7 toliau aprašytus hooks laikau projekto .claude/settings.json faile, kad jie būtų automatiškai įtraukti klonuojant saugyklą ir Claude laikytųsi tų pačių taisyklių naujame lange. Asmeniniai eksperimentiniai hooks keliauja į .claude/settings.local.json, kad netrukdytų komandai.

Visi 4 failai sujungiami sesijos pradžioje. Jei taisyklės prieštarauja viena kitai, pirmenybę turi žemesnis lygis (vietinis prieš projekto, projekto prieš naudotojo).

Greičiausias būdas sukurti pirmą hook – interaktyvus /hooks meniu pačiame Claude Code. Iš sąrašo pasirinkite įvykį, pasirinkite matcher (pavyzdžiui, Bash arba Edit) ir įklijuokite komandą. Claude Code už jus įrašo tinkamą JSON į settings.json.

31 gyvavimo ciklo įvykis: kurių reikia pradedantiesiems?

Pagrindinė įžvalga

Šiuo metu Claude Code turi 31 gyvavimo ciklo įvykį, suskirstytą į 3 dažnius: kartą per sesiją (SessionStart/SessionEnd), kartą per ėjimą (UserPromptSubmit/Stop) ir per kiekvieną įrankio iškvietimą (PreToolUse/PostToolUse). Pradedantiesiems reikia 4 iš 31 įvykių: PreToolUse apribojimams, PostToolUse automatiniams pakeitimams, SessionStart kontekstui ir Stop galutinėms patikroms.

Įvykiai vyksta trimis dažniais: kartą per sesiją (SessionStart, SessionEnd), kartą per ėjimą (UserPromptSubmit, Stop, StopFailure) ir per kiekvieną įrankio iškvietimą agentiniame cikle (PreToolUse, PostToolUse).

— Anthropic, hooks nuoroda, https://code.claude.com/docs/en/hooks

Svarbu suprasti šiuos tris dažnius, kad nesusipainiotumėte:

  1. Kartą per sesiją - SessionStart, SessionEnd, Setup. Jie paleidžiami vieną kartą, kai Claude Code atidaromas ir uždaromas. Naudokite juos kontekstui inicijuoti ir laikiniesiems failams išvalyti.
  2. Kartą per ėjimą - UserPromptSubmit, UserPromptExpansion, Stop, StopFailure. Jie suveikia gavus kiekvieną jūsų pranešimą ir kaskart sustojus modeliui. Naudokite juos pokalbiui registruoti ir galutiniams rezultatams tikrinti.
  3. Per kiekvieną įrankio iškvietimą - PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied, PostToolBatch, SubagentStart, SubagentStop. Jie suveikia kaskart redaguojant failą, paleidžiant Bash, skaitant arba ieškant. Tai aktyviausias lygmuo, kuriame taikomi apribojimai, formatavimas ir validacijos.

Visame 31 įvykio sąraše taip pat yra asinchroninių / reaktyvių įvykių: TeammateIdle, PreCompact, PostCompact, Elicitation, ElicitationResult, InstructionsLoaded, ConfigChange, CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove, Notification. Jie skirti pažangesniems scenarijams; kol kas juos praleiskite.

Penkių klausimų testas: kada taisyklė priklauso hook, o kada lieka CLAUDE.md?

Pagrindinė įžvalga

Jei taisyklė susijusi su veiksmu (ne kontekstu), sauga / pinigais / duomenimis, ją galima patikrinti su grep/regex, ją sunku atitaisyti pažeidus, o Claude jau bent kartą ją pažeidė, ji priklauso hook. Jei mažiau nei trys iš penkių atsakymų yra „taip“, taisyklė lieka CLAUDE.md. Pritaikiau testą savo 80 eilučių ir 5 taisykles perkėliau į hooks.

Man tai veikia kaip įstatymas, o ne pasiūlymas. Pasirinkimą tarp CLAUDE.md ir hook sutraukiau į paprastą penkių klausimų testą. Jei bent trys atsakymai yra „taip“, taisyklė keliauja į hook. Jei mažiau nei trys, ji lieka tekste.

Testas „kada taisyklė priklauso hook?“:

  1. Ar ši taisyklė susijusi su veiksmu, o ne kontekstu? („nevykdyk rm -rf“ yra veiksmas; „turiu TypeScript projektą“ – kontekstas.)
  2. Ar ši taisyklė susijusi su sauga, pinigais arba duomenimis? („neliesk .env“, „neskelbk raktų“.)
  3. Ar galite ją patikrinti su grep, regex arba shell komandos išėjimo kodu? („po .md redagavimo patikrink, kad nebūtų ilgojo brūkšnio“.)
  4. Jei taisyklė būtų pažeista, ar pasekmes būtų sunku atitaisyti? („force push į main“ sunku atitaisyti; „pamiršau tašką pabaigoje“ – lengva.)
  5. Ar jau matėte, kad Claude šią taisyklę bent kartą pamiršo?

Pavyzdys: „Nenaudok ilgųjų brūkšnių; naudok tik brūkšnelius.“ Veiksmas? Taip. Sauga? Ne. Galima patikrinti grep? Taip. Sunku atitaisyti? Ne. Matėte pažeidimą? Taip. 3 iš 5: įdėkite į hook.

Priešingas pavyzdys: „Dirbu su vibe coderiais, ne programuotojais; rašyk be slengo.“ Veiksmas? Greičiau kontekstas. Sauga? Ne. Galima patikrinti regex? Per sunku. Sunku atitaisyti? Ne. Matėte pažeidimą? Taip. 1 iš 5: palikite CLAUDE.md.

Testą atitiko penkios mano taisyklės. Jos perkeltos į hooks. Likę 75% liko tekstiniame faile.

7 hooks, paruošti kopijuoti

Pagrindinė įžvalga

Toliau pateikiami 7 paruošti hooks failui .claude/settings.json: blokuoti .env redagavimą, automatiškai paleisti prettier, neleisti force-push į main, tikrinti ilguosius brūkšnius, atlaisvinti prievadą prieš npm run dev, automatiškai sukurti commit po sėkmingų tests ir įterpti naują kontekstą sesijos pradžioje. Nukopijuokite kiekvieną į failą, iš naujo paleiskite Claude Code ir viskas veiks.

Visi 7 hooks saugomi viename .claude/settings.json faile projekto šakniniame kataloge. Kiekviename įraše yra įvykio tipas, įrankio filtras (matcher) ir shell komanda. Išėjimo kodas 2 prieš vykdymą atmeta atitinkantį PreToolUse iškvietimą. PostToolUse metu veiksmas jau įvyko: hook pateikia grįžtamąjį ryšį ir negali jo atšaukti.

Daugumos hook įvykių atveju veiksmą blokuoja tik išėjimo kodas 2. Claude Code išėjimo kodą 1 laiko neblokuojančia klaida ir tęsia veiksmą, nors Unix aplinkoje 1 įprastai reiškia nesėkmę.

— Anthropic, hooks nuoroda, https://code.claude.com/docs/en/hooks

exit 0 reiškia sėkmę. exit 1 reiškia klaidą, bet Claude tęsia (tai pirmasis toliau aptariamas antipattern). exit 2 elgsena priklauso nuo įvykio: jis gali blokuoti PreToolUse, o PostToolUse tik pateikia grįžtamąjį ryšį apie jau atliktą veiksmą.

Hook 1. Saugokite tiesioginius .env redagavimus (PreToolUse, exit 2)

Blokuoja bandymus tiesiogiai redaguoti bet kokį failą, atitinkantį .env, .env.local, .env.production ir panašiai.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '(^|/)\\.env(\\.|$)' && { echo 'Neredaguokite `.env` tiesiogiai. Pasakykite, kurį kintamąjį pridėti, ir pats atidarysiu failą.' >&2; exit 2; } || exit 0"
          }
        ]
      }
    ]
  }
}

Ką daro: Prieš kiekvieną Edit/Write/MultiEdit gauna failo kelią, su grep patikrina, ar jis atitinka .env šabloną, ir, jei taip, grąžina exit 2 su pranešimu. Claude mato stderr ir sako: „Bandžiau redaguoti .env, bet hook mane užblokavo; pasakyk, kurį kintamąjį pridėti.“

Hook 2. Automatiškai paleiskite prettier po kiekvieno kodo redagavimo (PostToolUse, exit 0)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(ts|tsx|js|jsx|json)$' && npx prettier --write \"$FILE\" 2>/dev/null & exit 0"
          }
        ]
      }
    ]
  }
}

Ką daro: Po kiekvieno Edit/Write gauna kelią ir, jei plėtinys yra .ts/.tsx/.js/.jsx/.json, paleidžia prettier fone su &. Visada grąžina 0, nes tai formatavimas, o ne apribojimas. Jei prettier nepavyksta, nieko tokio; failas lieka toks, koks buvo.

Skirtumas nuo hook 1 yra esminis: PreToolUse + exit 2 yra griežtas blokavimas prieš veiksmą. PostToolUse + exit 0 yra švelnus pakeitimas po veiksmo. Tai du skirtingi režimai skirtingoms užduotims.

Hook 3. Blokuokite git push --force į main šaką (PreToolUse, exit 2)

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE 'git[[:space:]]+push' && echo \"$CMD\" | grep -qE '(\\-\\-force|\\-\\-force-with-lease|[[:space:]]-f([[:space:]]|$))' && echo \"$CMD\" | grep -qE '([[:space:]/:])main([[:space:]/:]|$)' && { echo 'Priverstinis siuntimas į main draudžiamas. Sukurkite naują šaką arba paprašykite, kad tai padaryčiau rankiniu būdu.' >&2; exit 2; } || exit 0"
          }
        ]
      }
    ]
  }
}

Ką daro: Kiekvieno Bash paleidimo metu tikrina, ar komandoje yra push, --force/--force-with-lease/-f ir main. Jei atitinka visos trys sąlygos, veiksmas blokuojamas aiškiu pranešimu.

Anksčiau šią taisyklę CLAUDE.md rašiau didžiosiomis raidėmis. Claude vis tiek ją pažeisdavo maždaug kartą per dvi savaites, kai paprašydavau „force push, kad atšauktų mano blogą commit“. Šis hook aptinka parodytas pažodines komandas, tačiau pseudonimai, scenarijai, numanoma paskirties šaka ar kitas Git klientas gali apeiti eilučių patikrą. Pagrindinės šakos apsaugą užtikrinkite nuotoliniame serveryje ir ribokite agentui prieinamus prisijungimo duomenis.

Hook 4. Blokuokite ilguosius brūkšnius tekstiniuose failuose (PostToolUse, exit 2)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(md|mdx|tsx?)$' && grep -q $'\\xe2\\x80\\x94' \"$FILE\" && { echo \"Faile $FILE yra ilgasis brūkšnys (U+2014). Pakeiskite jį į įprastą brūkšnelį (U+002D).\" >&2; exit 2; } || exit 0"
          }
        ]
      }
    ]
  }
}

Ką daro: PostToolUse su exit 2 praneša Claude apie patikros nesėkmę jau po redagavimo. Jis neatšaukia ir neužkerta kelio rašymui. Jei Claude redaguoja failą ir palieka ilgąjį brūkšnį, hook nepavyksta, Claude gauna grįžtamąjį ryšį ir bando dar kartą. Po 2–3 sesijų Claude visai nustoja įterpti šį simbolį.

Atkreipkite dėmesį, kad grep ieško būtent ilgojo brūkšnio simbolio (U+2014), naudodamas $'\xe2\x80\x94' – Bash žymėjimą, skirtą išreikšti jį UTF-8 baitais. Jei tiesiog parašysite grep -q '-', bus aptikti ir įprasti brūkšneliai, o patikra vyks kiekviename faile. Nematomas simbolis sugadina visą logiką.

Hook 5. Atlaisvinkite 3000 prievadą prieš npm run dev (PreToolUse, exit 0)

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE '(npm|pnpm|yarn)[[:space:]]+run[[:space:]]+dev' && { lsof -ti:3000 | xargs -r kill -9 2>/dev/null; echo 'Prieš paleidžiant atlaisvintas 3000 prievadas' >&2; }; exit 0"
          }
        ]
      }
    ]
  }
}

Ką daro: Prieš kiekvieną npm run dev (arba pnpm/yarn) nutraukia 3000 prievado procesą. Visada grąžina 0, nes tai pasiruošimas, o ne apribojimas. Taip apsisaugoma nuo situacijų, kai Claude mato „prievadas naudojamas“, mano, kad yra kodo problema, ir pradeda ką nors taisyti, nors iš tikrųjų tiesiog liko veikti senas serveris.

Hook 6. Automatiškai sukurkite commit po sėkmingų testų (PostToolUse, exit 0)

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "INPUT=$(cat); CMD=$(printf '%s' \"$INPUT\" | jq -r '.tool_input.command // empty') || exit 1; EXIT=$(printf '%s' \"$INPUT\" | jq -r '.tool_response.exit_code // empty') || exit 1; case \"$CMD\" in 'npm test'|'pnpm test'|'yarn test') ;; *) exit 0 ;; esac; [ \"$EXIT\" = \"0\" ] || exit 0; git diff --cached --quiet || { echo 'Existing staged changes: review manually' >&2; exit 0; }; git add -- src/orders.ts tests/orders.test.ts || exit 1; git diff --cached --quiet && exit 0; git commit -m 'tests: checkpoint after successful run'"
          }
        ]
      }
    ]
  }
}

Ką daro: Vieną kartą perskaito stdin JSON ir priima tik tiksliai parodytas paprastas testų komandas. Tęsia tik kai pateiktas tool_response.exit_code aiškiai lygus nuliui; jei įdiegta versija tokio lauko neteikia, įrašą praleidžia, užuot spėjusi sėkmę. src/orders.ts ir tests/orders.test.ts pakeiskite tiksliais užduočiai priklausančiais failais. Esami paruošti pakeitimai sustabdo receptą, kad nesusijęs darbas nepatektų. Nepavykęs add sustabdo, tuščias skirtumas nekuria įrašo, įprasti commit hook lieka įjungti. Prieš įjungdami vietoje išbandykite sėkmingą, nepavykusią ir rezultato neturinčią įvestį.

Antipattern: pridėti git commit --no-verify prie kiekvieno Edit. Įrašų patikras palikite įjungtas. Jei patikra rekursyviai sužadina automatizavimą, susiaurinkite aktyviklį ar pakeiskite patikrą; pagal numatytuosius nustatymus neapeikite tikrinimo. Prieš automatinius įrašus peržiūrėkite paruoštą skirtumą ir failų priklausymą užduočiai.

Hook 7. Įterpkite naują kontekstą sesijos pradžioje (SessionStart su additionalContext)

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo 'no-branch'); STATUS=$(git status --short 2>/dev/null | head -10); echo \"{\\\"additionalContext\\\":\\\"Dabartinė šaka: $BRANCH. Nepatvirtinti pakeitimai:\\n$STATUS\\\"}\""
          }
        ]
      }
    ]
  }
}

Ką daro: Sesijos pradžioje surenka dabartinę Git šaką ir nepatvirtintų pakeitimų sąrašą, tada grąžina JSON su additionalContext lauku. Claude Code įterpia šį tekstą į pirmąją sistemos žinutę, todėl Claude nuo pat pradžių žino, kur yra ir kas liko nuo ankstesnės sesijos.

Naudokite additionalContext informacijai apie dabartinę aplinkos būseną arba ką tik užbaigtą operaciją, kurią Claude turėtų žinoti: aplinkos būsena (dabartinė šaka, diegimo tikslas, aktyvios funkcijų vėliavėlės), sąlyginės projekto taisyklės (kuri test komanda taikoma ką tik redaguotam failui), išoriniai duomenys (jums priskirtos atviros issues, naujausi CI rezultatai).

— Anthropic, hooks nuoroda, https://code.claude.com/docs/en/hooks

Šio hook plėtiniai: gauti naujausią commit ir jo aprašą, GitHub Actions būseną, aktyvų sprintą iš Linear/Jira ir atviras dabartinės saugyklos issues.

3 hook spąstai, į kuriuos pakliūva kas antras

Pagrindinė įžvalga

Pirmieji spąstai: hook su exit 1 tyliai praleidžia veiksmą, o Claude ignoruoja klaidą. Antrieji: sunkus darbas hook viduje nutraukiamas po 60 sekundžių timeout. Tretieji: hook mato tik ~/.zshrc aplinkos kintamuosius, o ne projekto .env. Kiekvieną problemą galima išspręsti viena eilute, tačiau nežinant šių spąstų gali atrodyti, kad „hooks neveikia“.

Spąstai 1. Hook su exit 1 tyliai praleidžia veiksmą

Pavojingiausi spąstai. Savaitę maniau, kad mano .env apsaugos hook veikia, bet paaiškėjo, kad hook naudojau jq -r '.tool_input.file_path' nepatikrinęs null. Kai tool_input buvo tuščias, jq baigė darbą su kodu 1. Claude exit 1 palaikė „hook klaida, tęsti“, todėl veiksmas įvyko. Nesupratau, kodėl .env vis dar buvo liečiamas. Priežastį pamačiau tik tada, kai rankiniu būdu paleidau hook terminale su tuščia įvestimi.

Sprendimas – viena taisyklė: kiekvieną hook pradėkite null patikra ir užbaikite || exit 0. Tada bet koks netikėtas išėjimas baigiasi „saugiu“ išėjimu, o ne tyliu praleidimu.

# Saugaus pradžios ir pabaigos šablonas:
FILE=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE" ] && exit 0
# ... jūsų logika ...
exit 0   # arba vienoje eilutėje || exit 0

Spąstai 2. Lėti hooks nutraukiami pasibaigus timeout

Turėjau hook, kuris po Edit paleisdavo eslint --fix visam failui. Dideliems failams (1000+ eilučių) apdoroti reikėdavo 8–10 sekundžių. Claude Code numatytasis hook timeout yra 60 sekundžių, todėl maniau, kad telpu į limitą. Tačiau per vieną minutę įvykus keliems Edit, hooks kaupiasi eilėje, o kai kurie tiesiog praleidžiami. Supratau tai tik tada, kai žurnale pamačiau „hook timed out“.

Sprendimas: jei hook reikia atlikti daug darbo, vykdykite jį fone. eslint --fix "$FILE" & nelaukiant rezultato. Tuomet hook per milisekundes grąžina exit 0, o tikras darbas vyksta fone.

# Sunki operacija fone:
npx eslint --fix "$FILE" &
exit 0

Spąstai 3. Hook nemato projekto aplinkos kintamųjų

Maniau, kad process.env hook viduje bus pasiekiamas taip pat, kaip Node.js programoje. Taip nėra. Hook vykdomas shell aplinkoje, kurią paleidžia Claude Code tėvinis procesas, ir mato tik tai, kas yra ~/.zshrc arba ~/.bashrc, taip pat tai, ką Claude Code aiškiai perduoda. Jei hook priklauso nuo OPENAI_API_KEY iš .env, .env turėsite perskaityti rankiniu būdu.

Sprendimas: aiškiai nuskaitykite .env hook komandoje.

# Projekto aplinkos kintamųjų perdavimas hook:
cd "$PWD" && source .env && curl -H "Authorization: Bearer $OPENAI_API_KEY" ...
# Arba naudojant dotenv:
dotenv -e .env -- node my-validator.js

Tai ypač skausminga monorepo, kur skirtingi paketai turi atskirus .env failus. Išspręskite tai perduodami PWD ir aiškiai vykdydami cd "$PWD" komandos pradžioje.

Kaip išbandyti hooks prieš kuriant commit?

Pagrindinė įžvalga

Hook yra shell komanda. Galite ją rankiniu būdu paleisti terminale su netikru stdin, patikrinti jos išėjimo kodą ir stderr – visa tai dar prieš Claude Code ją paleidžiant. Taip sutaupysite valandų derinimo ir apsisaugosite nuo hooks, kurie blokuoja savo pačių veikimą.

Pagrindinis testavimo scenarijus. Paimkite hook komandą iš JSON, atidarykite terminalą ir pateikite JSON, kurį Claude Code siųstų:

# Hook 1 bandymas (apsaugoti .env):
echo '{"tool_input":{"file_path":".env"}}' | bash -c '
FILE=$(jq -r ".tool_input.file_path // empty")
[ -z "$FILE" ] && exit 0
echo "$FILE" | grep -qE "(^|/)\.env(\.|$)" && {
  echo "BLOCKED" >&2
  exit 2
} || exit 0
'
echo "Exit code: $?"

stderr turėtumėte matyti BLOCKED ir Exit code: 2. Jei gaunate exit 0, regex neveikia; pataisykite grep.

Tikrinimo scenarijai:

  1. Teigiamas kelias - failas turi būti užblokuotas. .env hook 1 atveju, git push --force main hook 3 atveju.
  2. Neigiamas kelias - failas neturi būti užblokuotas. README.md hook 1 atveju, git push origin feature-branch hook 3 atveju.
  3. Kraštiniai atvejai - tuščia įvestis, null reikšmės, netikėti simboliai. Hook turi arba grąžinti exit 0, arba nepavykti su aiškia klaida, o ne tyliai praleisti veiksmą.

Kur laikyti eksperimentinius hooks. Ne .claude/settings.json, o .claude/settings.local.json faile (neįtraukiamame į git). Įdėkite ten naujus hooks į PostToolUse, naudodami echo vietoj tikro veiksmo, patikrinkite, ar jie suveikia, o tada perkelkite į produkcinį settings.json.

// Eksperimentas settings.local.json faile – įrašo į /tmp/hook-debug.log:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"[hook fired] $(date) $(jq -r '.tool_input.file_path // \"?\"')\" >> /tmp/hook-debug.log"
          }
        ]
      }
    ]
  }
}

Atlikę 5–10 redagavimų Claude Code aplinkoje, atidarykite /tmp/hook-debug.log ir pažiūrėkite, kurie failai suaktyvino hook. Jei failas tuščias, matcher netinka; pataisykite regex.

Kas toliau?

Pagrindinė įžvalga

Pradėkite nuo PostToolUse hooks, kurie grąžina exit 0; jie saugiausi ir nieko neblokuoja. Po savaitės pridėkite pirmą PreToolUse hook su exit 2, kad apsaugotumėte .env arba neleistumėte force-push. Po dviejų savaičių CLAUDE.md sumažės nuo 200 eilučių sutarties iki trumpo 50–80 eilučių konteksto aprašo, o pasirinktos įvykių patikros bus perkeltos į hook, griežtas prieigos ribas atskirai užtikrinant leidimais, smėlio dėže ir nuotolinėmis apsaugomis.

5 žingsniai ateinančiai savaitei:

  1. Peržiūrėkite CLAUDE.md su grep ir ieškokite tokių žodžių kaip „niekada“, „draudžiama“, „visada“ ir „privalo“. Kiekviena tokia taisyklė gali tapti hook. Jei taisyklė įsakmi, tekstinis failas jos neužtikrins.
  2. Pradėkite nuo PostToolUse + exit 0. Tai saugiausi variantai: jie pakeičia ką nors, bet nieko neblokuoja. Prettier (hook 2), kūrimo serverio nutraukimas (hook 5), automatinis commit po testų (hook 6).
  3. Tik įsitikinę pridėkite pirmą PreToolUse + exit 2. Pavyzdžiui, apsaugą .env (hook 1) arba apsaugą nuo force-push (hook 3). Tai griežtas blokavimas, o klaida grep komandoje gali užblokuoti ir jus.
  4. Prieš kurdami commit hooks išbandykite rankiniu būdu (žr. pirmiau esantį skyrių). Taip sutaupysite valandų derinimo.
  5. Eksperimentams naudokite settings.local.json. Įdėkite naujus hooks ten, naudodami echo, o ne tikrą veiksmą.

Sukonfigūravę hooks, kitas žingsnis šioje temų grupėje – kaip atšaukti pakeitimus Claude Code, jei hook praleistų ką nors pavojingo. Jei norite, kad Claude tarp sesijų prisimintų jūsų projekto struktūrą, sukurkite Antrąjį smegenų centrą Claude Code aplinkoje (business/ aplankas + susieta žinių bazė). O norėdami suteikti projekto skills pavadinimus, kad galėtumėte juos pakartotinai naudoti, žr. Claude Code Skills.

Jei jums reikia prieigos prie neuroninių tinklų per Ailoot, apsilankykite Ailoot.

Išsamiau

Klausimai ir atsakymai

Kodėl hook JSON įvestį turi perskaityti tik vieną kartą?

Stdin yra srautas: pirmasis jq procesas jį sunaudoja, vėlesniems skaitymams palikdamas EOF. Vieną kartą išsaugokite įvestį, tada iš tos reikšmės ištraukite komandą ir rezultatą. Trūkstamą ar nežinomą rezultatą laikykite nepatikrintu ir praleiskite automatinį įrašą.

Ar pavyzdiniai reguliariųjų išraiškų hook sukuria saugumo ribą?

Ne. Jie tikrina konkrečius įvykius ir atpažįstamas komandų eilutes. Shell nukreipimas, pseudonimai, scenarijai, MCP ar kitas rašymo kelias gali juos apeiti; griežtoms riboms naudokite siaurus prisijungimo duomenis, failų sistemos leidimus, smėlio dėžę ir apsaugotas šakas.

Visi straipsniai