Skip to content

Claude's PushNotification is never delivered from T3 threads (disabledReason: user_present) #25645

Open

Description

@juliusmarminge

What happened

Agents on long-running background threads use Claude Code's PushNotification tool to alert the user, and in T3 it isn't delivered. Both calls from the PR Takeovers dispatcher thread (mcp:launch:870f4a9a-16a6-4ff8-a844-a7c824708e01:orchestrator-prlabels-v1, Claude) returned:

"Not sent — this terminal is active, so your output here already reaches the user; a separate notification would be redundant."
{"pushSent": false, "localSent": false, "disabledReason": "user_present"}
  • 2026-10-24T11:30:12Z: "Issue leads pushed to contributor forks 4x today (…) — needs a push guard"
  • 2026-10-26T02:05:31Z: "t3code fleet.lock stuck 46 min … blocks all fleet ops. Kill it?"

It's a scheduled background dispatcher thread. The agent got pushSent: false back but had no other way to reach the user.

Cause

The decision is made inside Claude Code: it treats its SDK session as an active terminal. T3 doesn't intercept or replace the tool (no PushNotification handling in apps/server), so the alert goes nowhere.

Expected

In T3, an agent's push notification reaches the user through T3's own notifications (desktop / phone push), or the tool is disabled for T3 sessions and agents get a T3 path that does deliver. At minimum, the agent shouldn't be told the user is present when T3 has no client looking at that thread.

Activity

  1. added
    bugSomething is broken or behaving incorrectly.
    on Oct 26, 2026
  2. watashiwaaniket commented on Oct 27, 2026

    @watashiwaaniket

    We're fixing this.

    Claude's PushNotification decides delivery inside the CLI. An Agent SDK session counts as an active terminal, so the tool returns disabledReason: "user_present" and T3 never sees the call. CLAUDE_CODE_DISABLE_NOTIFICATION_PRESENCE_CHECK only changes that into no_transport: there is no OSC terminal and no Claude Remote Control session to deliver through. Disabling the tool would also leave the agent with no path that actually reaches anyone.

    The fix is a PostToolUse hook on PushNotification in the Claude adapter:

    • Ignore Claude's presence result. user_present means "this SDK session looks like a terminal," not "someone is looking at the thread in T3."
    • Deliver the message through T3: desktop and web notifications on the existing client path, and a one-shot phone push through the relay. This stays off the agent-activity phase, so a running thread is not marked as waiting for input.
    • Rewrite the tool result with updatedToolOutput before the model sees it, so the agent hears that T3 sent it (or that a T3 client has the thread open) instead of "this terminal is active."

    Existing completion, approval, and input alerts are unchanged. They only fire on a phase change, and these calls happen while the thread is still running.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething is broken or behaving incorrectly.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions