Claude Code / hook lifecycle field notes
Claude Code Hooks: events, matchers, and a Windows test
hooks. Choose the lifecycle event, narrow it with a matcher when the event supports one, and attach a command, HTTP, MCP, prompt, or agent handler. On Windows, make the shell explicit or use exec form with a real executable. In our local Claude Code 2.1.283 test, a command hook captured Setup:init before authentication and before any model request.That result proves one narrow thing: a local Setup command hook can run in this environment without a paid Claude request. It does not prove that tool-call hooks, prompt hooks, or agent hooks work without an authenticated session.

The hook shape in one table
| Layer | Question it answers | Example |
|---|---|---|
| Event | When should Claude Code consider the hook? | Setup, PreToolUse, PostToolUse, Stop |
| Matcher | Which occurrences should activate the group? | init for Setup; Bash for a tool event |
| Handler | What executes? | A command, HTTP endpoint, MCP tool, prompt, or agent |
| Output | Does the handler add context, allow, deny, or report nothing? | Exit code plus optional JSON on stdout |
The official reference says command-hook input arrives as JSON on stdin. An exit code of zero with no decision means the normal flow continues; it is not an automatic approval. Tool hooks can deny a call, but the permission system remains the harder enforcement boundary.
A Windows-safe Setup hook
This test used exec form: command was the real node.exe executable and args carried the script and output paths. That avoids shell quoting and the Windows limitation that .cmd shims are not native executables.
{
"hooks": {
"Setup": [{
"matcher": "init",
"hooks": [{
"type": "command",
"command": "node",
"args": [
"${CLAUDE_PROJECT_DIR}/.claude/hooks/capture-event.mjs",
"${CLAUDE_PROJECT_DIR}/hook-events.jsonl"
]
}]
}]
}
}
claude --init-only \
--settings .claude/settings.json \
--setting-sources project \
--debug-file setup-debug.log
The first attempt reached Setup:init but failed before the handler because Claude Code could not create its user-level .claude\session-env directory. After granting the CLI normal write access to its own configuration directory, the second attempt exited zero and wrote this event:
{"session_id":"ff20f6a5-f8bb-4b55-9c96-dd8a2fc02abd","cwd":"C:\\Users\\Administrator\\Documents\\Codex\\2026-09-24\\javascript-ilang-type-command-course-ai\\work\\claude-code-lab-2026-09-27","hook_event_name":"Setup","trigger":"init"}
What was tested, and what remains untested
| Claim | Verdict | Evidence |
|---|---|---|
| Claude Code was installed and runnable | Tested | 2.1.283 (Claude Code); doctor ended with No installation issues found. |
| The Setup command hook ran without a model call | Tested | Exit code 0 and a JSONL record with hook_event_name: Setup and trigger: init. |
| PreToolUse or PostToolUse fired | Untested | No authenticated model session made a tool call. |
| A prompt or agent hook returned a decision | Untested | Those handlers require a model-backed session; none was run. |
| The same fixture behaves identically on another release | Untested | Only version 2.1.283 was installed. |
Where hooks live and what that changes
| Location | Scope | Operational note |
|---|---|---|
~/.claude/settings.json | All local projects | Machine-local; easy to forget when reproducing elsewhere. |
.claude/settings.json | One project | Shareable and reviewable with the repository. |
.claude/settings.local.json | One project | Local override; normally not committed. |
| Plugin, skill, or subagent metadata | Component lifetime | Registration and trust rules differ by component. |
On Windows, shell form can run through Git Bash or PowerShell depending on the machine. Use shell: "powershell" when you need PowerShell behavior, or prefer exec form for a script path and pass every argument separately.
FAQ
Can command hooks run before Claude is logged in?
The local Setup fixture did on Claude Code 2.1.283. This result is limited to the Setup command hook tested here; it does not establish behavior for every event or handler type.
Does a silent exit code 0 approve a tool call?
No. The official reference describes it as no hook decision; the normal permission flow still applies.
Did this test spend money?
No. No model request was sent. The installed CLI reported no login and no API key.