Skip to content

fix(agent-status): a nested claude -p no longer takes over its parent pane's status - #31780

Merged
AmoabaKelvin merged 2 commits into
mainfrom
nested-agent-owner-guard
Oct 22, 2026
Merged

AmoabaKelvin merged 2 commits into
mainfrom
nested-agent-owner-guard

Conversation

@AmoabaKelvin

@AmoabaKelvin AmoabaKelvin commented Oct 22, 2026 •

Copy link
Copy Markdown
Collaborator
Files Added Deleted Net
Test 4 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​159 $\color{#cf222e}{\Huge{\mathbf{−}}}$​3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​156
Prod 7 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​107 $\color{#cf222e}{\Huge{\mathbf{−}}}$​28 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​79

What users saw

An interactive Claude runs in an Orca pane, and a script in that pane starts its own claude -p. Each time that child finished, or hit its quota and fired StopFailure, the parent pane's status row became the child's: its session id, prompt, and a done/failed state. Desktop showed " - Claude failed" for the parent pane, and the paired phone got one push per child retry. The parent's own session, prompt, pending permission and subagent roster were overwritten too.

Now

The parent pane keeps its own session, prompt and state while a nested claude -p runs and fails. The child's hooks leave the row alone, so no banner or push fires for it. A new Claude started in the pane after the old one is gone (exited or crashed) still takes the pane over, because the owner's process is checked first.

Root cause

hasOtherAgentProcessOwner (src/shared/agent-process-presence.ts) decided whether a hook comes from someone other than the pane's owning process by comparing provider type only. resolveAgentStatusIdentity also skipped that check for the same provider, so a second Claude with a different PID and start time counted as the owner. Every route asks that one function: the local listener's pre-fold gate, the host status update, the owner probe before admission, and the SSH/WSL relay's normalization and admission. Now it takes the sender's process too: while the owner's process is live and not suspended, a different process of the same provider is a guest.

On the relay, the owner's per-provider prompt/tool folds are shared with a same-provider guest, so the relay now refuses such a guest before folding (isOwnerProviderGuestHook). Without that, the parent's next Stop over SSH showed the child's prompt.

Hooks with no process identity (Windows hooks and hooks installed by older builds) keep today's behaviour: they can only be told apart by provider. A nested claude -p there still updates the parent's row. This change never suppresses an owner's own events on a guess. Relayed rows on the desktop keep adopting the relay's verdict, and the phone only shows what the host decided, so old and new phones behave the same.

@Jinwoo-H, for #26408: when its transitionHookPresence classifier rebases, it should keep this rule. A different PID/start time of the same provider is not the owner, so "same agent type → owner" must come after the process check.

Verified

  • New src/main/agent-hooks/server-nested-same-provider-owner.test.ts (local hook server, real HTTP hooks): a nested Claude's UserPromptSubmit + StopFailure leaves the parent row working with its own prompt and session, and nothing emits done. This fails on main. A new Claude is admitted once the owner probe says the old process exited.
  • New src/wsl-guest/relay-nested-same-provider-owner.test.ts (real relay hook server): nothing is forwarded for the child, the parent's next Stop keeps "Parent task", and a replacement is admitted after the owner exits. This fails on main, and it also fails when the relay pre-fold check is removed.
  • Updated tests:
    • Two server-agent-presence tests: a replacement Claude's hook now waits for the owner probe before it is admitted, as a different provider's hook already did.
    • The owed-notification test: it now mocks its fictional owner process as live.
  • Ran the agent-hooks, wsl-guest, shared agent-*, renderer agent-status and runtime mobile status suites, plus check:code-quality:changed and check:react-doctor:changed.

Visual Proof

This is a real run in hidden dev builds of main and this branch. An interactive Claude in a pane runs claude -p "CHILD TASK: reply with the word hi" ; sleep 45 with its Bash tool. Each caption shows the pane's status row as the host published it.

Before (main): the child's hooks take the row. The session changes to the child's (7bd3ee97), the prompt becomes "CHILD TASK…", and the row goes Done (green check) while the parent is still working. After the parent resumes, its row keeps the child's prompt.

before

After (this PR): the row stays the parent's: working, with its own prompt and session (f6f8e1dc), until the parent finishes. The child ran (its session 40c90826 exists on disk) but never reached the row.

after

Full runs: before · after

Fixes #30067

…t pane

The pane-ownership guard told a nested agent apart from the pane's owner by
provider only, so a second Claude process (a script's claude -p) wrote its
session, prompt and failed turn into the parent's row. A hook whose process
identity differs from the owner's live process is now a guest on every route:
the local listener, the host status update, the owner probe and the relay.
@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fcd7fc3c-59ea-4d42-92c3-da7e575eb0dc
📥 Commits

Reviewing files that changed from the base of the PR and between 7ad01e1 and 1ab42ab.

📒 Files selected for processing: 1
  • src/main/agent-hooks/server/server-status-update.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

Hook status resolution and relay ownership checks now use Claude process identity to distinguish processes that share a pane. The changes include tests for nested same-provider processes, process relaunch, and overlapping presence reads.

Priority: ➖ Normal

Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 1ab42

No actionable merge-blocking risk remains on the inspected paths; the change is ready for normal checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 30.77% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 11 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description check Passed The description explains the user impact, root cause, implementation, limitations, testing, visual proof, and linked issue. It does not use every template heading or checklist item, but it contains th…
Title check Passed The title is concise, specific, and accurately states the primary change: a nested claude -p no longer takes over its parent pane's status.
Linked Issues check Passed Issue #30067 is open and directly linked. The change carries the Claude hook process identity into ownership and status-identity checks. A different PID and start time is treated as a guest while the …
Out of Scope Changes check Passed The production changes support issue #30067 across local hooks, status identity, host admission, and relay normalization. The test changes verify these ownership paths and preserve existing probe beha…
Full details: Description check

Explanation

The description explains the user impact, root cause, implementation, limitations, testing, visual proof, and linked issue. It does not use every template heading or checklist item, but it contains the required review information and is substantially complete.

Full details: Linked Issues check

Explanation

Issue #30067 is open and directly linked. The change carries the Claude hook process identity into ownership and status-identity checks. A different PID and start time is treated as a guest while the recorded owner remains active. Local admission, status updates, and relay normalization reject the guest before state folding. The owner process remains accepted. Replacement admission still depends on the owner probe, and an exited result admits the replacement. Hooks without process identity retain provider-only behavior. The new local and relay tests cover child failure suppression, parent state retention, and replacement admission.

Full details: Out of Scope Changes check

Explanation

The production changes support issue #30067 across local hooks, status identity, host admission, and relay normalization. The test changes verify these ownership paths and preserve existing probe behavior. No unrelated production behavior or unrelated test scope is evident.

✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 24de30cd-ba7d-4542-ad93-d8c9d2dc86e7
📥 Commits

Reviewing files that changed from the base of the PR and between 7a912a3 and 7ad01e1.

📒 Files selected for processing: 11
  • src/main/agent-hooks/server-agent-presence.test.ts
  • src/main/agent-hooks/server-claude-owed-notification-expiry.test.ts
  • src/main/agent-hooks/server-nested-same-provider-owner.test.ts
  • src/main/agent-hooks/server/server-status-update.ts
  • src/shared/agent-hook-listener.ts
  • src/shared/agent-hook-owner-presence.ts
  • src/shared/agent-process-presence.ts
  • src/shared/agent-status-identity.ts
  • src/wsl-guest/agent-hook-event-admission.ts
  • src/wsl-guest/agent-hook-provider-normalization.ts
  • src/wsl-guest/relay-nested-same-provider-owner.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

Comment thread src/main/agent-hooks/server/server-status-update.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Repeated Claude quota retries send failure notifications for the interactive parent pane

1 participant