SessionStart hooks do not fire on /clear (related to #10373)
[BUG] SessionStart hooks do not fire on /clear (related to #10373)
Summary
SessionStart hooks configured in project .claude/settings.json execute correctly on startup (via --init-only and fresh sessions) but never execute when triggered by /clear. This may be related to #10373, which reports a different failure mode for the same hook type. Other hook types (e.g. PostToolUse) from the same settings file fire correctly during the same session.
Environment
- Claude Code: 2.1.72
- Node: v22.22.0
- Platform: Linux aarch64 (Docker container, kernel 6.12.72-linuxkit)
- Shell: bash
Minimal reproduction
1. Set up a test repo with SessionStart and PostToolUse hooks:
mkdir /tmp/hook-test && cd /tmp/hook-test
git init
mkdir .claude
cat > .claude/settings.json << 'EOF'
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "date >> /tmp/sessionstart_log.txt && echo 'SessionStart fired'"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "date >> /tmp/posttooluse_log.txt"
}
]
}
]
}
}
EOF
git add -A && git commit -m "init"
2. Confirm the hook fires on startup:
rm -f /tmp/sessionstart_log.txt
cd /tmp/hook-test && claude --init-only
cat /tmp/sessionstart_log.txt
# Expected: timestamp printed (hook fired)
# Actual: timestamp printed (PASS)
3. Test /clear in an interactive session:
rm -f /tmp/sessionstart_log.txt /tmp/posttooluse_log.txt
cd /tmp/hook-test && claude
Inside the session:
- Ask Claude to run any bash command (e.g.
echo hello) - Run
/clear - Exit and check the log files:
cat /tmp/posttooluse_log.txt # Expected: exists (PostToolUse fired)
wc -l /tmp/sessionstart_log.txt # Expected: 2 lines (startup + clear)
# Actual: 1 line (startup only - clear trigger never fired)
Expected behaviour
Per the hooks documentation, SessionStart fires on four triggers:
| Source | Trigger | Status |
|--------|---------|--------|
| startup | New session / --init-only | Works |
| resume | --resume / --continue | Not tested |
| clear | /clear | Broken |
| compact | Auto/manual compaction | Not tested |
Actual behaviour
startuptrigger: hook fires (verified via--init-onlyand side-effect file creation)cleartrigger: hook does not fire (side-effect file contains only the startup entry - no second entry from/clear)- PostToolUse hooks in the same settings file work correctly, confirming settings are loaded
Relationship to #10373
Issue #10373 reports a different failure mode for SessionStart hooks: hooks execute on startup but their output is not injected into conversation context. In this issue, the hook command itself never executes when triggered by clear (the side-effect file contains only the startup entry, with no second entry from /clear). Comments on #10373 suggest the behaviour may be intermittent and version-dependent.
Source code analysis
The /clear command handler does call executeSessionStartHooks("clear"):
// Simplified from minified cli.js
async function clearConversation({setMessages, ...}) {
await executeSessionEndHooks("clear", ...);
setMessages(() => []); // clear messages
// ... reset state, new session ID, new session file ...
let msgs = await executeSessionStartHooks("clear");
if (msgs.length > 0) setMessages(() => msgs);
}
The hook runner (kb()) has several early-return guards that could silently prevent execution:
async function* kb({hookInput, ...}) {
if (disableAllHooks()) return; // policy check
if (process.env.CLAUDE_CODE_SIMPLE) return; // env var check
let matched = getMatchingHooks(appState, agentId, eventName, hookInput);
if (matched.length === 0) return; // no hooks found
if (signal?.aborted) return; // abort check
if (!workspaceTrustAccepted()) return; // trust check
// ... execute hooks ...
}
Notably, getMatchingHooks() wraps its entire body in try { ... } catch { return []; }, which would silently swallow any error during hook resolution and make it appear as if no hooks matched.
The exact failure point is unclear from the minified source, but the hook command itself never executes (confirmed by the absence of the side-effect file).
Workaround
Add instructions to CLAUDE.md to manually read the target file at session start, since CLAUDE.md is reliably loaded on both startup and /clear.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗