[BUG] Hooks silently don't fire in Desktop app or new RC session slots (terminal & first RC session work)

Status Open
Reported on v2.1.267
Maintainer reply None cached
Activity 1 comment · opened Sep 23, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Hooks configured in a project's .claude/settings.json (SessionStart, Stop, PreToolUse, PostToolUse) fire reliably in two of four session-entry paths and silently fail to fire in the other two, on the same machine, same settings file, same repo:

| Path | Hooks fire? |
|---|---|
| claude in the terminal | Yes |
| claude rc / /rc — the first remote-control session on a connection | Yes |
| Claude Desktop app, Code tab | No |
| A new session slot opened within an already-existing remote-control connection | No |

This looks like the same underlying mechanism as two already-open issues, and I want to add corroborating evidence tying them together as one coherent pattern rather than isolated reports:

  • #87657 — Desktop-app / Agent SDK entrypoint sessions intermittently load Hooks: Found 0 total hooks in registry despite settings declaring them.
  • #90798 — WarmLifecycle pre-warms a session by spawning a throwaway backing CLI process (which fires its own SessionStart), then attaches the visible session to a different, already-running process instead — so the slot the user actually types into never gets its own fresh SessionStart.
  • #95339 — forked/new session slots reuse the parent's already-running process rather than spawning a fresh one, so process-start-bound behavior (there: RC auto-connect; here: hooks) never fires for them.

I can confirm WarmLifecycle is actively running on my machine while reproducing this — see log excerpt below — which is consistent with #90798's mechanism being the cause of the "new session slot inside an existing RC connection" failure, separately from whatever causes #87657's "0 hooks in registry" in the plain Desktop Code-tab case.

What Should Happen?

Per the hooks docs: "Claude Code fires the same hook events wherever it runs: sessions in the terminal, IDE extensions, the Desktop app, and cloud sessions." Hooks declared in .claude/settings.json should fire consistently regardless of which UI/entry path started the session.

Error Messages/Logs

No error is shown in any of the four cases — failure is silent, which is what makes it hard to diagnose (I initially suspected my own hook config).

Project .claude/settings.json used for reproduction (generated by a third-party tool's init routine, @drewpayment/mink, but the shape is a plain, unremarkable hooks config):

{
  "hooks": {
    "SessionStart": [
      { "matcher": "", "hooks": [{ "type": "command", "command": "mink session-start" }] }
    ],
    "Stop": [
      { "matcher": "", "hooks": [{ "type": "command", "command": "mink session-stop" }] }
    ],
    "PreToolUse": [
      { "matcher": "Read", "hooks": [{ "type": "command", "command": "mink pre-read" }] },
      { "matcher": "Edit", "hooks": [{ "type": "command", "command": "mink pre-write" }] },
      { "matcher": "Write", "hooks": [{ "type": "command", "command": "mink pre-write" }] }
    ],
    "PostToolUse": [
      { "matcher": "Read", "hooks": [{ "type": "command", "command": "mink post-read" }] },
      { "matcher": "Edit", "hooks": [{ "type": "command", "command": "mink post-write" }] },
      { "matcher": "Write", "hooks": [{ "type": "command", "command": "mink post-write" }] },
      { "matcher": "Bash", "hooks": [{ "type": "command", "command": "mink post-tool" }] },
      { "matcher": "Grep", "hooks": [{ "type": "command", "command": "mink post-tool" }] }
    ]
  }
}

~/Library/Logs/Claude/main.log excerpt showing WarmLifecycle active during reproduction of the "new session slot within an existing RC connection" case:

[info] [WarmLifecycle:session] Initialized (arm=when-hidden)
[info] [WarmLifecycle:preview] Initialized (arm=when-hidden)
[info] [WarmLifecycle:preview] Starting idle timeout for local_<id>: 1800s
[info] [WarmLifecycle:preview] Warming up session local_<id>

Steps to Reproduce

  1. Add the hooks config above (or any SessionStart/PreToolUse hook that logs to a file, for an unambiguous signal) to a project's .claude/settings.json. For debugging I've used a plain echo $(date) >> file command alongside the mink hook. Example:

``json
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "mink session-start"
}
]
},
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "echo \"PROJECT MINK SESSIONSTART $(date)\" >> claude-hook.log"
}
]
}
],
``

  1. Start claude in a terminal in that project — confirm the hook fires (log line appears).
  2. From that terminal session, run /rc to start remote control — confirm the hook fires for that first remote session too.
  3. From within an already-connected remote-control session, open an additional session slot in the same connection (mobile app "+" / new chat) — confirm the hook does not fire for that new slot, even though it fired for the first slot on the same connection.
  4. Other setting (independent from claude terminal/remot): Open the same project in the Claude Desktop app, Code tab — confirm the hook does not fire (no log line), and optionally run /debug to check for Hooks: Found 0 total hooks in registry.

Claude Model

Sonnet

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.267 (terminal CLI, via PATH). Desktop app bundled CLI reports required_version:2.1.270 internally; Desktop app itself is 2.110.0.

Platform

Claude Pro subscription

Operating System

macOS 26.6.2 (25G83)

Terminal/Shell

zsh

Additional Information

Related issues that each cover part of this pattern individually: #87657, #90798, #95339. Filing this to connect them as one reproducible matrix (terminal / first-RC-session work; Desktop / additional-RC-slot don't) rather than duplicate any of them — happy to have this closed as a dupe if a maintainer prefers to fold it into one of the three instead.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗