Hook-ul e deja configurat, comanda /hooks îl arată, iar apoi începe ceva ciudat. Trimiteți o cerere, dar în requests.log nu apare nicio linie nouă. Sau apare de două ori. Uneori e mai rău: o acțiune automată pornește după orice modificare și începe să vă deranjeze munca obișnuită.

Într-o astfel de situație nu trebuie să reconstruiți toată configurația de la zero. E mai util să transformați observația într-o sarcină mică și verificabilă: ce anume trebuie să declanșeze hook-ul, ce urmă trebuie să rămână și ce caz este obligat să-l ignore. Apoi Claude Code va putea verifica fișierele respective și propune o corectare minimă.

Când trebuie să se declanșeze hook-ul

În acest articol analizăm hooks de tip comandă din fișierele de configurare. La un astfel de hook sunt importante trei părți: evenimentul, condiția de declanșare și handler-ul. Evenimentul răspunde la întrebarea "când verificăm", condiția îngustează cazurile potrivite, handler-ul execută acțiunea.

De exemplu, jurnalul de cereri este abonat la UserPromptSubmit. Acest eveniment apare când în sesiune sosește o cerere, încă înainte ca modelul s-o proceseze. Cel mai des e cererea dumneavoastră, dar Claude Code îl declanșează și la turele pe care le începe singur: o nouă tură a /loop, raportul unui subagent din fundal. De aceea linia nouă din jurnal confirmă foarte puțin - hook-ul a primit cererea și a înregistrat-o, atât. Dacă agentul a rezolvat sarcina corect, din această linie nu aflați.

UserPromptSubmit nu are matcher. Dacă jurnalul are nevoie doar de anumite cereri, acestea sunt selectate chiar de handler. La evenimentele legate de instrumente situația e diferită. De exemplu, matcher-ul Edit|Write selectează instrumentele, iar calea către fișier se verifică separat, din datele apelului. Un matcher cu numele instrumentului nu înseamnă "doar fișierele din src".

Verificați evenimentul și rezultatul

Evenimentul Stop înseamnă că Claude a terminat de răspuns. E un moment convenabil pentru o notificare, dar nu o dovadă că codul e corect sau că sarcina s-a încheiat cu succes.

Înainte de corectare, notați două scenarii scurte:

  • cel necesar: trimiteți o cerere de test și vedeți o singură linie nouă în requests.log;
  • cel de prisos: deschideți fișierul într-un editor obișnuit, fără să trimiteți o cerere nouă către Claude Code, și verificați că jurnalul nu s-a schimbat. Pentru jurnalul tuturor cererilor, al doilea prompt trimis trebuie de asemenea să producă o înregistrare; el nu va fi un control negativ.

Acestea sunt criteriile de verificare. Răspunsul concret al Claude Code nu trebuie inventat dinainte.

Înregistrarea nu a apărut

Începeți din locul unde observația diferă de așteptare. Pentru jurnal, asta înseamnă lipsa unei linii noi după cererea de test. Apoi mergeți de la configurare spre acțiune:

  1. Introduceți /hooks în sesiunea interactivă Claude Code și verificați dacă înregistrarea necesară s-a încărcat. Acest meniu îl deschideți dumneavoastră; transmiteți agentului rezultatul verificării.
  2. Verificați evenimentul. Jurnalul de cereri trebuie să reacționeze la UserPromptSubmit, iar acțiunea de după modificarea unui fișier e de obicei legată de un eveniment al instrumentelor.
  3. Găsiți fișierul sursă al configurației. Poate fi o configurație de utilizator, de proiect sau locală; comparați nu doar numele, ci și comenzile complete. Același handler întâlnit simultan în mai multe fișiere de configurare nu înseamnă neapărat două rulări.
  4. Verificați comanda handler-ului: există fișierul, se potrivește comanda cu sistemul dumneavoastră de operare, nu s-a stricat calea cu spații.
  5. Verificați locul rezultatului. Calea relativă depinde de directorul de lucru al procesului, așa că handler-ul ar fi putut scrie fișierul altundeva decât acolo unde îl căutați dumneavoastră.

Ruta principală aici trece prin agent. Transmiteți-i observația, rezultatul verificării /hooks și limitele corectării:

Hook-ul UserPromptSubmit e vizibil în /hooks, dar după cererea de test
în requests.log nu apare nicio linie nouă.

Găsește configurația sursă și handler-ul. Verifică evenimentul, calea comenzii,
directorul de lucru și crearea directorului pentru jurnal. Arată cauza
și fă o corectare minimă. Păstrează celelalte hooks și configurații.
După corectare, descrie scenariile de control, cel necesar și cel negativ.
Verificați locul corectării

Cereți agentului să numească fișierul și liniile exacte pe care le modifică. Așa veți vedea dacă el corectează configurația sursă sau o copie întâmplătoare, care nici măcar nu se încarcă.

De exemplu, agentul a stabilit: handler-ul scrie în logs/requests.log, dar folderul logs/ nu există, iar scriptul nu îl creează. Corectarea minimă constă în crearea acestui folder înainte de scriere. După ea, verificați exact logs/requests.log: o cerere de test trebuie să adauge o singură înregistrare. Acesta e un exemplu de cauză posibilă, nu diagnosticul oricărui jurnal gol.

Dacă configurația există în fișier, dar lipsește din /hooks, cauza poate fi sintaxa JSON, domeniul configurației sau faptul că hooks-urile nu rulează deloc în acest moment: folderul proiectului nu e marcat ca de încredere, e activat disableAllHooks sau administratorul a permis doar hooks-urile din politica gestionată. Hooks-urile din fișiere de configurare diferite se adună, nu se înlocuiesc unele pe altele. Dacă înregistrarea e încărcată, dar urma lipsește, atenția se mută spre comandă, datele de intrare și calea de ieșire.

Bifurcația diagnosticării hook-ului după rezultatul verificării din meniul /hooksNicio linie nouă după cerereÎnregistrarea apare în /hooks?Verificăm evenimentul, sursa, comandaCăutăm în configurațieJSON, domeniu, folder de încredereVerificăm handler-ulComandă, stdin, calea rezultatuluinuda
Rezultatul din /hooks determină pe ce nivel continuăm căutarea

Sensul bifurcației e simplu: cât timp Claude Code n-a încărcat înregistrarea, e prematur să analizăm funcționarea scriptului. Când înregistrarea e vizibilă, configurația a ajuns deja la aplicație și e mai util să verificați pornirea handler-ului, JSON-ul de intrare și locul unde trebuie să apară rezultatul.

Handler-ul s-a terminat cu eroare

Un hook de tip comandă primește JSON prin intrarea standard. În el se află câmpurile generale ale evenimentului și datele evenimentului concret. Pentru UserPromptSubmit, textul cererii vine în câmpul prompt. Acest text trebuie citit ca date. Nu-l puteți concatena cu o comandă shell și executa: cererea de test poate conține ghilimele, întreruperi de linie și orice text obișnuit.

Cereți-i lui Claude Code să reproducă pornirea handler-ului pe o intrare fictivă. În cerere indicați direct cazurile importante:

Verifică handler-ul hook-ului separat de sesiune, pe un JSON fictiv.
Cazuri necesare: prompt obișnuit și pe mai multe linii, calea proiectului cu spații,
directorul de jurnal lipsă și intrare incorectă.

Nu executa textul din prompt drept cod. Arată comanda de pornire, codul de ieșire,
stderr și modificarea reală a fișierului de test. Nu modifica jurnalul real.

Codul de ieșire ajută să înțelegeți soarta handler-ului însuși, dar sensul lui depinde de eveniment. exit 0 spune că comanda hook-ului s-a încheiat fără eroare. Asta nu confirmă rezultatul întregii sarcini. exit 2 poate bloca acțiunea la evenimentele care au loc înaintea acțiunii, dar după ce instrumentul s-a executat deja, nu-i mai poate anula efectul. De aceea aceeași rețetă cu exit 2 nu poate fi mutată orbește de la un eveniment la altul.

Dacă rularea separată reușește, iar în sesiune hook-ul tot tace, porniți Claude Code din folderul proiectului cu comanda claude --debug-file hook-debug.log și repetați o cerere de test. Deschideți fișierul hook-debug.log care a apărut și găsiți evenimentul, hooks-urile potrivite și codul de ieșire. Acesta e jurnalul lui Claude Code însuși, separat de requests.log-ul dumneavoastră. După verificare încheiați această sesiune de diagnosticare; pentru munca obișnuită porniți Claude Code fără acest flag. La majoritatea evenimentelor, stdout-ul obișnuit merge în debug log și nu apare neapărat în transcript. Excepțiile depind de eveniment, așa că liniile de diagnosticare arbitrare din stdout pot influența contextul în loc să devină un jurnal comod.

Diagnosticarea separat de rezultat

Pentru prima analiză e mai sigur să scrieți o marcă de diagnosticare într-un fișier local separat, iar după verificare s-o ștergeți. Documentația oficială nu are un flag universal dry-run pentru hooks; modul de probă se construiește ca parte a unui anumit handler de studiu.

Hook-ul se declanșează de prisos

Două linii identice după o singură cerere pot indica o înregistrare dublă: hooks asemănătoare, dar nu complet identice, se află, de exemplu, în configurația de utilizator și cea de proiect. Dacă e literalmente aceeași comandă, doar repetată în fișiere diferite, ea tot se va executa o singură dată. Copiile dintr-un plugin sau skill se numără separat, așa că sursa din meniu contează și ea. Mai întâi transmiteți agentului rezultatul /hooks și cereți-i să listeze înregistrările acestui eveniment în toate fișierele de configurare disponibile. Dacă în configurație totul e în regulă, verificați dacă nu cumva handler-ul însuși scrie de două ori la o singură rulare. E prea devreme să ștergeți prima linie găsită.

O altă cauză frecventă - o condiție prea largă. Să zicem că hook-ul trebuie să lase o marcă de diagnosticare după modificarea fișierelor din src/, dar reacționează la fiecare utilizare a instrumentelor Edit și Write. Aici sunt necesare două niveluri de selecție:

  • matcher-ul selectează instrumentele Edit și Write;
  • o condiție separată verifică calea din argumentele instrumentului și ignoră tot ce e în afara src/.
Două niveluri de selecție pentru hook-ul PostToolUseEvenimentul PostToolUseInstrumentul e Edit sau Write?Ignoră hook-ulCalea e în src/?Verificăm argumentele apeluluiNu lăsa marcăScrie marcanudanuda
Matcher-ul selectează instrumentul, iar o verificare separată îngustează setul de fișiere

O verificare nu o înlocuiește pe cealaltă. Matcher-ul respinge instrumentele nepotrivite, apoi condiția aplicată argumentelor lasă doar căile din src/. Marca de diagnosticare apare doar când ambele verificări dau răspunsul "da".

Un fragment de configurație poate arăta așa:

"PostToolUse": [
  {
    "matcher": "Edit|Write",
    "hooks": [
      { "type": "command", "command": "python .claude/hooks/mark-source-edit.py" }
    ]
  }
]

Acesta este un element din obiectul hooks al unui settings.json existent, nu un document JSON complet. Verificarea căii trebuie să fie în handler; scriptul mark-source-edit.py e aici doar ipotetic, corpul lui nu se află în articol. Comanda presupune python disponibil și pornire din rădăcina proiectului. Agentul trebuie să verifice interpretorul, shell-ul și calea din configurația dumneavoastră; copierea exemplului ca o conectare gata făcută nu e recomandată.

Acest fragment e comod de citit ca o singură propoziție:

  • După o modificare reușită a fișierului
  • Dacă instrumentul e Edit sau Write
  • Rulează mark-source-edit.py

Lanțul arată doar ceea ce e stabilit în configurație. Decizia "lasă marca sau ignoră fișierul" o ia deja handler-ul după verificarea căii. De aceea prezența matcher-ului confirmă alegerea instrumentului, dar nu dovedește încă filtrarea corectă a src/.

AcțiuneUrma așteptatăCe verifică
Modificați src/card.js prin EditO marcă de diagnosticare nouăInstrumentul potrivit și calea potrivită trec condiția
Creați src/theme.css prin WriteO marcă de diagnosticare nouăA doua operație permisă e luată în calcul și ea
Modificați README.md prin EditNicio marcă nouăFișierul din afara src/ e exclus

În acest tabel, Edit și Write înseamnă instrumentele Claude Code. Modificarea manuală a unui fișier într-un editor nu le declanșează și deci nu verifică un astfel de matcher. Înainte de fiecare acțiune notați sfârșitul fișierului de diagnosticare, iar apoi comparați doar înregistrările noi.

Cât timp limita nu e verificată, lăsați acțiunea inofensivă: o singură marcă de declanșare, fără formatare, blocare sau modificare masivă a fișierelor. Mai întâi asigurați-vă că cazul necesar trece exact o dată, iar cel de prisos nu trece.

O rulare de prisos adaugă întotdeauna muncă în plus. Totodată, o comandă locală care doar scrie un fișier nu apelează prin ea însăși modelul. Un hook de tip prompt sau agent e construit altfel și folosește modelul. O analiză detaliată a costurilor nu e necesară aici, e suficient să nu amestecați aceste două tipuri de handler.

Cum dezactivați reacția

Dacă hook-ul vă deranjează chiar acum, găsiți-i înregistrarea sursă și ștergeți-o doar pe ea din array-ul evenimentului necesar. Restul hooks-urilor lăsați-le pe loc. Aceasta este dezactivarea rulărilor viitoare: nu anulează comanda deja executată, nu restaurează fișierele modificate și nu șterge liniile care au ajuns deja în jurnal.

Înainte de ștergere, salvați o copie a înregistrării alese, dacă intenționați s-o readuceți. După modificare deschideți din nou /hooks și asigurați-vă că această înregistrare nu mai există. Dacă meniul încă arată configurația veche, închideți sesiunea și deschideți una nouă din același proiect. Apoi executați acțiunea de control și comparați jurnalul înainte și după. Nu trebuie să apară linii noi de la hook-ul dezactivat.

Pentru dezactivarea temporară a tuturor hooks-urilor există setarea "disableAllHooks": true. Dar acesta e un comutator general, nu o modalitate de a opri o singură înregistrare. Pentru această setare însăși prioritatea fișierelor funcționează: "disableAllHooks": false în fișierul de proiect va avea întâietate față de true din setările dumneavoastră de utilizator. În plus, hooks-urile stabilite printr-o politică gestionată la nivel de organizație nu pot fi dezactivate printr-o configurație obișnuită de utilizator sau de proiect.

Nu confundați dezactivarea cu anularea modificărilor

Un hook dezactivat va înceta să mai ruleze în viitor. Dacă handler-ul a modificat deja un fișier, restaurarea acelui fișier se face separat și doar după examinarea diff-ului sau a versiunii salvate.

Cum să-i încredințați corectarea lui Claude Code

O sarcină bună conține observația, evenimentul așteptat, fișierele concrete și limita modificării. Atât e suficient ca agentul să investigheze configurația, fără să rescrie toată automatizarea:

Analizează hook-ul din acest proiect.

Observație: după o singură cerere de test, requests.log primește două linii.
/loop și subagenții din fundal nu sunt porniți în această sesiune.
Așteptare: UserPromptSubmit trebuie să adauge exact o linie.
Atașez rezultatul /hooks. Verifică toate sursele disponibile de configurare
și comanda handler-ului.

Mai întâi numește cauza și fișierele care trebuie modificate. Apoi fă
o corectare minimă, păstrează celelalte hooks și arată diff-ul.
Verifică cazul necesar și cazul negativ. După aceea arată
cum se dezactivează doar această reacție.

La final ar trebui să rămâneți cu patru răspunsuri clare:

  • ce eveniment declanșează hook-ul;
  • ce condiție ignoră cazurile de prisos;
  • unde se află configurația sursă și handler-ul;
  • cum se dezactivează exact această reacție, fără să afecteze restul.

Și ruta de control în întregime: acțiunea necesară lasă o urmă așteptată, cea de prisos nu lasă nicio urmă, eroarea handler-ului se vede într-un diagnostic țintit, iar după dezactivare urma nouă nu mai apare. Totul e destul de pragmatic. Tocmai de aceea un astfel de hook e mai ușor de întreținut decât o automatizare care doar "uneori face ceva".

Pentru a verifica comportamentul, folosiți referința oficială pentru hooks și ghidul practic: interfața se schimbă odată cu Claude Code.

Comportamentul a fost verificat conform documentației oficiale pe 18 septembrie 2026. Exemplele arată ordinea verificării; nu există aici un handler gata făcut. Comanda și căile verificați-le în sistemul de operare și shell-ul dumneavoastră.