Skip to content

A delegated child waiting on a permission approval never wakes its parent #26294

Open

Description

@EtanHey

What happened

Two delegate_task children (Claude, claude-opus-5-5, spawned with bypassPermissions) each sat for about 2 hours on a command permission request. The parent got no completion and no notice. task_status showed pendingApproval with a request id, but t3_pending_request read on that id returned "not found", and t3_thread_organize settle on the child refused with "is waiting on an approval or question". The only way out was task_cancel.

Why (read on upstream/main d0b81ce; the reactor and settle checks are unchanged on 0c80751)

  • DelegatedTaskQuestionReactor.ts wakes the parent only for user_input requests (it filters on request.kind !== "user_input"). A permission request gets no wake message.
  • t3_pending_request covers questions only by design: "approvals are not listed … this cannot approve a permission request" (toolkits/thread/tools.ts:126). readQuestion looks only for kind === "user_input", so an approval id comes back as "The pending user-input request was not found."
  • pendingApproval on the delegate result does surface it ("Oldest pending approval … Ends a wait. Grants no approval rights.", contracts/orchestratorMcp.ts:208), but only to a parent that happens to poll or wait.
  • Settle refuses while any non-user_input request is pending (Orchestrator.ts ~3060).

So a child blocked on an approval is invisible unless the parent polls, and once found it can't be answered from MCP or settled.

It also leaks. After task_cancel, the approval on the cancelled child is still pending, so settle keeps refusing ("waiting on an approval or question"). No agent tool can answer a permission request, so the child thread keeps its provider session and MCP processes until a human clicks through it in the UI. (Interrupting a run does cancel its pending requests with "The run was interrupted." via settleInterruptedRun; the cancel path evidently didn't reach that here. We didn't trace why.)

Ask (any one helps; we'd take them in this order)

  1. Wake the parent on a pending approval, the same way the question reactor does for questions: a notification saying which child, which request kind, and that a human must approve it in the UI.
  2. Make t3_pending_request read on an approval id say what it is ("this is a permission approval; agents can't answer it") instead of "not found".
  3. Put the approval text in that wake. It already exists: t3_thread_read activity on a third stalled child showed the approval_request text ("Dangerous rm operation on working directory or its ancestor: /scratch/..."). A parent that gets told which child and why can tell the user what to approve.
  4. Make task_cancel cancel the child's pending approvals, like a run interrupt does, so a cancelled child can settle.

Agents answering approvals is reasonably out of scope; we're asking for visibility, not approval rights.

Why a bypassPermissions child asked at all: Claude Code's own safety check refuses to rm a directory that contains the shell's current working directory, and it asks even under bypassPermissions. The child had cd'd into the directory it then removed. That check is correct; the T3 gap is only that nobody hears about it.

Activity

  1. Dropje97 commented on Oct 28, 2026

    @Dropje97

    Additional version and timing evidence on 0.1.3-nightly.20261027.3754, Linux x64 (Debian 13). A Claude Fable 5.1 parent delegated to Claude Opus 5.5. Provider initialization records confirm Claude Code 2.1.311, bypassPermissions, and T3 Full access. Codex CLI 0.165.0 is installed at inspection; these approval cases are Claude-specific observations.

    The server has local SQLite read-performance patches. The delegated-request reactor, MCP service, question handlers and tool definitions match upstream d2c440312e5f39d59827ed466838a623516454d6 byte for byte. No clean-release reproduction was run.

    All times below are 2026-10-28 UTC, from persisted requests and tool results:

    • 03:09:25.054Z: a child opened a command approval with fullAccessOverride: provider_check. Claude's reason was “Dangerous rm operation not ruled out — the shell may read this command differently than it was parsed.”
    • 05:28:51.121Z: the parent's t3_pending_request(action: list, threadId: child) returned {"requestIds":[]} while that approval was pending, 2 h 19 min later. The parent had to inspect the child to discover the stall.
    • 05:29:46.043Z: the child's run was interrupted. The approval was still recorded as pending at inspection, so interruption did not clear it in this case either (related cleanup issue: [Bug]: Command approvals stay pending after a delegated task is cancelled #21935).
    • Two further child approvals opened at 09:44:36.025Z and 09:55:27.131Z, resolving at 09:44:55.177Z and 09:56:05.131Z. Both were provider_check requests for statically unresolvable wildcard removal targets. Paths omitted.

    We now avoid the flagged cleanup commands. The missing behavior is a parent notice identifying the child, request kind and reason, and directing the user to the approval UI. Agent approval rights need not change. #22925 already tracks that notification path and its fix #20928 remains open and unmerged; these observations do not test that PR.

  2. EtanHey commented on Oct 28, 2026

    @EtanHey
    ContributorAuthor

    Rechecked on 2026-10-28 through T3 Code's built-in triage playbook with Codex / GPT-6.1 Sol.

    Installed/running nightly on both Macs: 0.1.4-nightly.20261028.3814. Latest published nightly checked in source: 0.1.4-nightly.20261028.3824 (eb751fa0730d6a51d56547cb7fcaf4822a7e0e3b); it is not yet running on these Macs.

    DelegatedTaskQuestionReactor.ts is unchanged between those tags. Its event path still returns unless event.payload.kind === "user_input", and its catch-up path likewise skips non-user_input requests. The primary missing approval-notification behavior therefore remains. Related #22925 is still open; proposed fix #20928 is still open and unmerged at this check.

    Keeping this open. No fresh dangerous-command approval was induced, and this recheck does not independently establish whether every cancellation/approval-cleanup subcase remains. Multi-machine orchestration does not change the reactor's request-kind filter.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions