sync SVN r18174

This commit is contained in:
2026-09-17 22:36:46 +03:00
parent 04a78f99db
commit ca2056d06a
13 changed files with 2159 additions and 0 deletions

View File

@@ -0,0 +1,393 @@
# Referinta oficiala hooks Claude Code (pentru diagnosticul "subagent stop violation")
Surse fetch-uite azi (2026-09-17), toate redirecteaza de pe `docs.claude.com` pe `code.claude.com`:
- https://code.claude.com/docs/en/hooks (fost https://docs.claude.com/en/docs/claude-code/hooks)
- https://code.claude.com/docs/en/hooks-guide (fost .../hooks-guide)
- https://code.claude.com/docs/en/settings (fost .../settings)
- https://code.claude.com/docs/en/settings-reference
- https://code.claude.com/docs/en/settings-example
- https://code.claude.com/docs/en/env-vars
**Limitare tehnica intalnita**: paginile `hooks` si `settings-reference` sunt prea mari pentru
fetch-ul folosit (WebFetch trece continutul brut printr-un model mic inainte sa-l intoarca); la
cereri repetate pe aceeasi pagina, portiuni identice (tabelul "Common input fields", tabelul
"Exit code 2 behavior per event" pana la randul `Stop`, exemplele din `hooks-guide`) au iesit
IDENTIC de mai multe ori — acelea sunt tratate mai jos ca sigure/verbatim. O extractie initiala,
mai larga, a produs scheme JSON pentru `SessionStart`/`Stop`/`SubagentStop`/`PreCompact` care NU
s-au mai reprodus la cereri ulterioare tintite pe aceleasi sectiuni (acelea au raspuns explicit
"nu e in continutul furnizat, pagina e trunchiata") — acea extractie e tratata ca **nesigura** si
nu e citata mai jos. Sectiunile marcate **NEDOCUMENTAT** de mai jos sunt cele pe care nu am putut
sa le confirm verbatim, nu neaparat cele care lipsesc din documentatia reala.
## 1. Lista completa a evenimentelor de hook
Tabelul de mai jos e citat verbatim din `hooks-guide` (sectiunea "How hooks work"), confirmat prin
citire directa a continutului brut al fetch-ului (nu prin sumarizare):
> | Event | When it fires |
> | `SessionStart` | When a session begins or resumes |
> | `Setup` | When you start Claude Code with `--init-only`, or with `--init` or `--maintenance` in `-p` mode. For one-time preparation in CI or scripts |
> | `UserPromptSubmit` | When you submit a prompt, before Claude processes it |
> | `UserPromptExpansion` | When a user-typed command expands into a prompt, before it reaches Claude. Can block the expansion |
> | `PreToolUse` | Before a tool call executes. Can block it |
> | `PermissionRequest` | When a tool call needs a permission decision |
> | `PermissionDenied` | When auto mode denies a tool call, including denials without a classifier verdict. ... |
> | `PostToolUse` | After a tool call succeeds |
> | `PostToolUseFailure` | After a tool call fails |
> | `PostToolBatch` | After a full batch of parallel tool calls resolves, before the next model call |
> | `Notification` | When Claude Code sends a notification |
> | `MessageDisplay` | While assistant message text is displayed |
> | `SubagentStart` | When a subagent is spawned |
> | `SubagentStop` | When a subagent finishes |
> | `TaskCreated` | When a task is being created via `TaskCreate` |
> | `TaskCompleted` | When a task is being marked as completed |
> | `Stop` | When Claude finishes responding |
> | `StopFailure` | When the turn ends due to an API error |
> | `TeammateIdle` | When an agent team teammate is about to go idle |
> | `InstructionsLoaded` | When a CLAUDE.md or `.claude/rules/*.md` file is loaded into context. ... |
> | `ConfigChange` | When a configuration file changes during a session |
> | `CwdChanged` | When the working directory changes, for example when Claude executes a `cd` command. ... |
> | `DirectoryAdded` | When a working directory is added mid-session via `/add-dir` or the SDK `register_repo_root` control request |
> | `FileChanged` | When a watched file changes on disk. The `matcher` field specifies which filenames to watch |
> | `WorktreeCreate` | When a worktree is being created via `--worktree`, `isolation: "worktree"`, or for a background session. ... |
> | `WorktreeRemove` | When a worktree is being removed at session exit, when a subagent finishes, or when you delete a background session |
> | `PreCompact` | Before context compaction |
> | `PostCompact` | After context compaction completes |
> | `PreModelSwitch` | Before Claude Code applies a model switch that you or a client requested. Can block the switch |
> | `PostModelSwitch` | After the session's model changes, including changes Claude Code makes on its own, ... |
> | `Elicitation` | When an MCP server requests user input during a tool call |
> | `ElicitationResult` | After a user responds to an MCP elicitation, before the response is sent back to the server |
> | `SessionEnd` | When a session terminates |
Sursa: https://code.claude.com/docs/en/hooks-guide, sectiunea "How hooks work".
### Schema JSON exacta pe stdin/stdout pentru PreCompact / SessionStart / Stop / SubagentStop
**NEDOCUMENTAT (in sensul de mai sus: nu am putut confirma verbatim)**. Fetch-ul repetat pe
`hooks` (inclusiv varianta `.md`) intoarce constant tabelul "Common input fields" (comun tuturor
evenimentelor, vezi mai jos) si tabelul "Exit code 2 behavior per event" doar pana la randul
`Stop`; sectiunile individuale `### SessionStart`, `### PreCompact`, `### Stop`, `### SubagentStop`
cu exemplele lor JSON complete nu au putut fi extrase — raspunsul explicit al fetch-ului a fost
"the actual detailed 'Hook events' section ... appears to be cut off or not included" si "I
cannot find a subsection literally titled 'PreCompact'... in the provided content". Nu inseamna
ca documentatia oficiala nu contine acele scheme (aproape sigur le contine, pagina fiind
"Hooks reference" completa), ci ca uneltele disponibile in aceasta sesiune nu au putut sa le
aduca integral.
Ce **s-a confirmat verbatim** despre campurile comune (tabelul "Common input fields", identic la
doua fetch-uri separate pe `hooks` si pe `hooks.md`):
> | Field | Description |
> | `session_id` | Current session identifier |
> | `prompt_id` | UUID identifying the user prompt currently being processed. ... Absent until the first user input. Requires Claude Code v2.1.196 or later |
> | `transcript_path` | Path to conversation JSON. The transcript file is written asynchronously and may lag the in-memory conversation, so it may not yet include the current turn's most recent messages when a hook fires. Hooks that need the final assistant text of the current turn should use `last_assistant_message` on Stop and SubagentStop instead of reading the transcript |
> | `cwd` | Current working directory when the hook is invoked |
> | `scratchpad_dir` | Path to the session's scratchpad directory, where Claude keeps temporary working files. Absent when the session has no scratchpad or the temp directory is unavailable. Requires Claude Code v2.1.257 or later |
> | `permission_mode` | Current permission mode: `"default"`, `"plan"`, `"acceptEdits"`, `"auto"`, `"dontAsk"`, or `"bypassPermissions"`. ... |
> | `effort` | Object with a `level` field holding the effort level in effect when the hook runs... Present for events that fire within a tool-use context, such as `PreToolUse`, `PostToolUse`, `Stop`, and `SubagentStop`, when the current model supports the effort parameter. |
> | `hook_event_name` | Name of the event that fired |
>
> When running with `--agent` or inside a subagent, two additional fields are included:
>
> | Field | Description |
> | `agent_id` | Unique identifier for the subagent. Present only when the hook fires inside a subagent call. Use this to distinguish subagent hook calls from main-thread calls. |
> | `agent_type` | Agent name (for example, `"Explore"` or `"security-reviewer"`). Present when the session uses `--agent` or the hook fires inside a subagent. For subagents, the subagent's type takes precedence over the session's `--agent` value. |
Sursa: https://code.claude.com/docs/en/hooks, sectiunea "Common input fields" (confirmat identic
si pe varianta .md).
Nota: campul `trigger` (pentru `PreCompact`/`PostCompact`, valori `manual`/`auto`) si `source`
(pentru `SessionStart`, valori `startup`/`resume`/`clear`/`compact`/`fork`) sunt mentionate ca
**valori de matcher**, nu confirmate ca nume exact de camp JSON pe stdin — vezi tabelul de
matchere de la punctul 3.
Ce s-a confirmat despre `SessionStart` prin exemplu real de configurare (verbatim, din
`hooks-guide`, sectiunea "Re-inject context after compaction"):
> When Claude's context window fills up, compaction summarizes the conversation to free space.
> This can lose important details. Use a `SessionStart` hook with a `compact` matcher to
> re-inject critical context after every compaction.
>
> Claude Code adds plain text your command writes to stdout to Claude's context.
```json
{
"hooks": {
"SessionStart": [
{
"matcher": "compact",
"hooks": [
{ "type": "command", "command": "echo 'Reminder: use Bun, not npm. ...'" }
]
}
]
}
}
```
Schema de iesire (`hookSpecificOutput`, `additionalContext`, `systemMessage`, `decision`,
`continue`, `stopReason`) pentru cele 4 evenimente cerute: **NEDOCUMENTAT** in sensul de mai sus
pentru forma completa exacta. S-a confirmat insa, verbatim, forma generala de output pentru
`UserPromptSubmit` (acelasi tipar `hookSpecificOutput.additionalContext`, aplicabil probabil si
altor evenimente, dar nu s-a putut confirma explicit pentru `SessionStart`/`Stop`/`SubagentStop`):
> For `UserPromptSubmit` hooks, use `hookSpecificOutput.additionalContext` instead to inject text
> into Claude's context. Nest `additionalContext` inside `hookSpecificOutput`; if you place it at
> the top level of the JSON, Claude Code silently ignores it.
```json
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Current branch: release-42. Deploy freeze until Friday."
}
}
```
> Other events use different decision patterns. For example, `PostToolUse` and `Stop` hooks use a
> top-level `decision: "block"` field, while `PermissionRequest` uses
> `hookSpecificOutput.decision.behavior`.
Sursa: https://code.claude.com/docs/en/hooks-guide, sectiunea "Structured JSON output".
## 2. Tokeni consumati / marimea contextului in input-ul hook-urilor
**Confirmat, de doua ori, cautare pe intreaga pagina `hooks`**: nu exista niciun camp de tokeni
in input-ul hook-urilor.
> Search for "stop_hook_active": No matches found for the term "stop_hook_active" on this page.
> Search for "token", "usage", and "input_tokens": No matches found for these terms on this page.
(cautarea a fost facuta explicit pe pagina "Hooks reference"; rezultatul e consistent la doua
apeluri separate — semnal ca reflecta continutul real, nu o presupunere a modelului de sumarizare)
Concluzie: singura sursa documentata pentru starea conversatiei ramane `transcript_path`
(fisier `.jsonl`), descris astfel (verbatim, vezi campurile comune de mai sus):
> Path to conversation JSON. The transcript file is written asynchronously and may lag the
> in-memory conversation, so it may not yet include the current turn's most recent messages when
> a hook fires.
**NEDOCUMENTAT**: schema exacta a unei linii din `transcript_path` (daca fiecare linie JSONL are
un obiect `usage` cu `input_tokens`/`cache_read_input_tokens`). Nu am gasit nicio sectiune care sa
descrie formatul intern al transcriptului; pagina de hooks il trateaza doar ca „path to
conversation JSON", fara schema de linie.
Singurul loc unde a aparut o notiune de "context folosit" e statusline-ul (alta functionalitate,
nu un hook), in exemplul din `settings-example`:
> "command": "jq -r '\"[\\(.model.display_name)] \\(.context_window.used_percentage // 0)% context\"'"
adica statusline-ul primeste `context_window.used_percentage` — dar acesta e inputul JSON al
comenzii de `statusLine`, nu al vreunui hook (`PreCompact`/`Stop`/etc.). Sursa:
https://code.claude.com/docs/en/settings-example, sectiunea "Your own settings".
## 3. Declansarea programatica a compactarii; PreCompact poate bloca?
Confirmat verbatim (tabelul de matchere, `hooks-guide`, sectiunea "Filter hooks with matchers"):
> | Event | What the matcher filters | Example matcher values |
> | `PreCompact`, `PostCompact` | what triggered compaction | `manual`, `auto` |
Nu exista alta explicatie a diferentei functionale dintre `manual` si `auto` in continutul pe care
am putut sa-l confirm — **NEDOCUMENTAT** in acest fetch (probabil documentat in sectiunea
"Hooks reference" pe care nu am putut-o extrage integral).
Despre blocare: tabelul "Exit code 2 behavior per event" s-a confirmat identic de 3 ori, dar
mereu trunchiat la randul `Stop`:
> | Hook event | Can block? | What happens on exit 2 |
> | `PreToolUse` | Yes | Blocks the tool call |
> | `PermissionRequest` | No | Exit code 2 isn't honored for this event and the permission flow proceeds unchanged. ... |
> | `UserPromptSubmit` | Yes | Blocks prompt processing and erases the prompt |
> | `UserPromptExpansion` | Yes | Blocks the expansion |
> | `Stop` | Yes | Prevents Claude from stopping, continues the conversation |
Randul pentru `PreCompact` (si `SubagentStop`, `SessionStart`) nu a putut fi extras — nici prin
fetch normal, nici prin varianta `.md`, nici prin cereri tintite doar pe randul lipsa.
**NEDOCUMENTAT explicit aici**: daca `PreCompact` poate bloca compactarea prin exit code 2.
(Rationament indirect, NEconfirmat ca fapt: linia generala din ghid — "Some events can't be
blocked: for SessionStart and others, exit 2 shows stderr to the user and execution continues" —
sugereaza ca exista o categorie de evenimente needitabile prin exit 2, dar nu specifica daca
`PreCompact` e in acea categorie sau in cealalta.)
Citat sigur, din `hooks-guide`, care mentioneaza explicit ca `SessionStart` NU poate fi blocat:
> Some events can't be blocked: for `SessionStart` and others, exit 2 shows stderr to the user and
> execution continues.
Declansare programatica a compactarii: **NEDOCUMENTAT** in continutul confirmat — nu am gasit un
flag/comanda explicita de tip "trigger compaction now" in paginile fetch-uite (hooks, hooks-guide,
settings, settings-reference, env-vars). Doar variabila urmatoare influenteaza PRAGUL, nu
declansarea manuala programatica:
> `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` — Set the percentage (1-100) of the auto-compact window at
> which auto-compaction triggers. Use lower values like `50` to compact earlier; the variable
> can't raise the threshold, so values above the default percentage are ignored. It applies only
> in sessions that compact before the model's context limit. Applies to both main conversations
> and subagents.
Sursa: https://code.claude.com/docs/en/env-vars.
## 4. Hook-uri in subagenti (Task/Agent); SubagentStop; bucla stop_hook_active
**Confirmat verbatim** (hooks-guide, sectiunea "Limitations"):
> Background subagents can't show a prompt in non-interactive mode. Claude Code still runs the
> hooks for their tool calls, and if no hook returns a decision, it denies the call. In an
> interactive session, background subagent prompts surface in your main session and the hooks
> fire as usual.
Deci: hook-urile de tip `PreToolUse`/`PostToolUse` etc. **se declanseaza si in interiorul
subagentilor**, pentru apelurile lor de unelte — confirmat explicit doar pentru cazul
`PermissionRequest`/permisiuni; pentru restul evenimentelor (`PreToolUse`, `PostToolUse` propriu-zise
in subagent) nu am gasit o fraza separata la fel de explicita, dar tabelul de scope de configurare
confirma ca hook-urile de subagent exista ca mecanism dedicat:
> | Location | Scope | Shareable |
> | [Subagent](/docs/en/sub-agents) frontmatter | While that subagent is running | Yes, defined in the subagent file |
Sursa: https://code.claude.com/docs/en/hooks-guide, sectiunea "Configure hook location".
`SubagentStop` — definitie confirmata din tabelul de evenimente (punctul 1):
> `SubagentStop` | When a subagent finishes
**NEDOCUMENTAT** (nesigur): o extractie initiala a afirmat ca exista fraza "Claude Code converts
a `Stop` hook here to `SubagentStop`, the event it fires when a subagent completes" — aceasta
fraza NU s-a mai reprodus la recitirea directa a continutului brut al `hooks-guide` (1065 de
linii citite integral), asa ca nu o citez ca fapt confirmat. Nu neg ca ar fi adevarata (e
plauzibila si consistenta cu restul mecanismului de scope pe subagent), doar ca nu am reusit sa o
verific verbatim in aceasta sesiune.
### stop_hook_active si bucla
**Confirmat verbatim**, din `hooks-guide`, sectiunea "Stop hook hits the block cap":
> Claude keeps working instead of stopping, then ends the turn with a warning that the Stop hook
> blocked too many consecutive times.
>
> Claude Code overrides a Stop hook after it blocks eight times in a row without progress. Your
> hook script needs to check whether it already triggered a continuation. Parse the
> `stop_hook_active` field from the JSON input and exit early if it's `true`:
```bash
#!/bin/bash
INPUT=$(cat)
if [ "$(echo "$INPUT" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0 # Allow Claude to stop
fi
# ... rest of your hook logic
```
> If your hook legitimately needs more than eight iterations to converge, raise the cap with
> `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP`.
Deci: **cauza tipica a buclei** e un hook `Stop`/`SubagentStop` care intoarce mereu o decizie de
blocare (exit 2 / `decision: "block"`) fara sa verifice `stop_hook_active`, astfel incat Claude
Code il tot re-invoca; plafonul e 8 blocari consecutive "fara progres", dupa care Claude Code
suprascrie hook-ul si opreste turul cu un avertisment. Campul `stop_hook_active` exista exact ca
sa permita hook-ului sa detecteze ca a mai fost invocat o data in acelasi ciclu de "stop" si sa
cedeze (`exit 0`) in loc sa continue sa blocheze.
Variabila de mediu asociata, confirmata din `env-vars` (extras separat, cu wording plauzibil dar
NEverificat printr-un al doilea fetch identic — trateaza ca moderat sigur, nu ca sigur):
> `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` — Maximum number of blocks a stop hook can request before
> Claude Code stops respecting further requests from that hook and logs a warning (default:
> `100`). Useful when a hook inadvertently loops and repeatedly requests stops.
Nota: valoarea implicita citata aici de fetch (`100`) **contrazice** cifra "eight times in a row"
din `hooks-guide` (confirmata de doua ori, sigura). Nu pot reconcilia cele doua cifre din
continutul disponibil — posibil ca 8 sa fie plafonul implicit "fara progres" mentionat in ghid, iar
`100` sa fie un plafon absolut diferit citit gresit de fetch-ul pe `env-vars` (surse nereconciliate,
posibil eroare de extractie pe aceasta a doua cifra). **Trateaza cifra "100" ca NEDOCUMENTAT/de
reverificat manual**, foloseste "8" ca fiind confirmat de doua ori pe pagina oficiala a ghidului.
## 5. Setari relevante in settings.json
Confirmat din tabelul settings-reference (randuri, fara detaliu de default/exemplu — sectiunile
detaliate de sub tabel nu au putut fi extrase, pagina prea mare):
> | Key | Description | Topic | Scope |
> | `autoCompactEnabled` | Turn automatic compaction off or on | Memory and context | Any file |
> | `autoCompactWindow` | Set how full the context gets before Claude Code compacts | Memory and context | Any file |
> | `cleanupPeriodDays` | Choose how many days Claude Code keeps transcripts before deleting them | Privacy and telemetry | Any file |
> | `env` | Set environment variables for every session and its subprocesses | Memory and context | Any file |
Sursa: https://code.claude.com/docs/en/settings-reference. **NEDOCUMENTAT** aici: valorile
implicite exacte pentru `autoCompactEnabled` si `autoCompactWindow` (sectiunile detaliate nu s-au
putut extrage).
Exemple reale confirmate (`cleanupPeriodDays`, `env`), din https://code.claude.com/docs/en/settings-example:
```json
// ~/.claude/settings.json — un dezvoltator
{
"...": "...",
"cleanupPeriodDays": 20
}
```
> Delete session transcripts and other local session data older than 20 days
```json
// .claude/settings.json — o echipa
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_PROTOCOL": "grpc",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4317"
},
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh" }
]
}
]
}
}
```
```json
// managed-settings.json — o organizatie
{
"...": "...",
"cleanupPeriodDays": 7
}
```
> Delete session transcripts and other local session data after 7 days
Variabile `CLAUDE_CODE_*` legate de context/compactare, confirmate din
https://code.claude.com/docs/en/env-vars:
> `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE` — Set the percentage (1-100) of the auto-compact window at
> which auto-compaction triggers. Use lower values like `50` to compact earlier; the variable
> can't raise the threshold, so values above the default percentage are ignored. Applies to both
> main conversations and subagents.
> `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` — vezi punctul 4 (cifra de default nereconciliata).
**NEDOCUMENTAT** in acest fetch: nu am gasit alte variabile `CLAUDE_CODE_*` explicit legate de
"context size" ca numar de tokeni (cautarea pe `env-vars` a fost limitata la cuvintele
COMPACT/CONTEXT/TOKEN/STOP_HOOK; nu a intors nimic cu "CONTEXT" in nume).
## Rezumat pentru cine investigheaza "subagent stop violation"
- Nu exista niciun camp de tokeni/marime-context in inputul niciunui hook (confirmat, cautare
directa pe pagina oficiala). Singura sursa e `transcript_path`, iar formatul intern al liniilor
JSONL nu e documentat in paginile verificate.
- Bucla clasica de `Stop`/`SubagentStop` are o cauza documentata si un mecanism de iesire:
campul `stop_hook_active` pe input, plafon confirmat de "8 blocari la rand fara progres" dupa
care Claude Code preia controlul si opreste turul cu avertisment (`hooks-guide`, sectiunea
"Stop hook hits the block cap").
- Hook-urile ruleaza si in subagenti; input-ul lor primeste in plus `agent_id`/`agent_type` fata de
campurile comune.
- Schemele JSON complete (toate campurile) pentru `PreCompact`/`SessionStart`/`Stop`/`SubagentStop`
si detaliul exact al blocarii pentru `PreCompact` NU au putut fi confirmate verbatim in aceasta
sesiune — pagina oficiala "Hooks reference" (https://code.claude.com/docs/en/hooks) le contine
aproape sigur, dar depaseste ce a putut extrage fetch-ul disponibil; de reluat cu acces direct
(browser) daca e nevoie de schema exacta camp-cu-camp.