Skip to content

Background shells are excluded from #870's turn-hold — the #866 hazard (out-of-turn permission/ask request) still reproduces via run_in_background #876

Description

@xintaofei

Summary

This is the background-shell twin of #866, which #870 fixed only for spawned
sub-agents. #870's own scoping is explicit: "a hold must NEVER wait on a
shell"
(since a shell can outlive every turn — e.g. a dev server — and its
contract is wake-on-exit, not a turn-scoped drain). We reproduced the identical
hazard #866 described, through that deliberately-excluded door, on v0.59.0:

  1. The model launches a Bash(run_in_background) command. The turn resolves
    end_turn immediately — per Background sub-agents & shells aren't trackable to completion — forward background_tasks_changed / task_updated status #865, the tool result returns at launch, not at
    process completion.
  2. The background command finishes. The model resumes autonomously
    (a task-notification-style followup), with no turn held open for it (by
    design, per fix: hold a turn open while its background subagents are still live #870).
  3. In that followup, the model calls a tool that requires user input — in our
    repro, the ask_user_question tool — fully out-of-turn, with no live
    session/prompt for it to be framed inside.
    This is functionally the same
    shape as Async sub-agent stranded at turn settlement — frozen mid-tool-call on an out-of-turn permission request, promised result undeliverable #866's frozen session/request_permission call, just via a
    different tool and a shell instead of a sub-agent as the trigger.

Why this isn't fully covered by #870

#870's hold-open logic keys on liveBackgroundTasks entries with isSubagent: true; shell tasks are explicitly walked past ("shells-never-defer" is even
named in a code comment). So a run_in_background shell's post-completion
followup gets none of the protection #870 added — the turn settles at launch,
and whatever the model does after the shell finishes (including raising a
request that blocks on user input) rides in as bare post-settlement
session/updates, exactly as #866 originally described for sub-agents.

Client-side impact varies, but the hazard is real either way

We can't speak for every ACP client, but it's worth noting the failure mode
isn't uniformly "hang":

Either way, this is the same root cause #864/#865/#866 already describe — a
background task's continuation has no session-level representation once its
launching turn has settled — just reached via the one class (run_in_background
shells) that #870's fix intentionally does not cover.

Proposal

No new mechanism needed beyond what #864/#865/#866 already proposed — this
issue is here to flag that #870 leaves the identical hazard live for shells,
in case that wasn't an intentional accepted risk:

  1. A session-level active/idle signal (session/update keeps arriving after session/prompt resolves — expose a session-level active/idle signal #864) would at least let a client keep
    a "still working" indicator alive across the shell's post-completion
    followup, so a subsequent question/permission request isn't a surprise.
  2. Forwarding background_tasks_changed (Background sub-agents & shells aren't trackable to completion — forward background_tasks_changed / task_updated status #865) would let a client know a
    shell-triggered continuation is plausible before it happens.
  3. (Per Async sub-agent stranded at turn settlement — frozen mid-tool-call on an out-of-turn permission request, promised result undeliverable #866's own proposal Track line numbers for text file edits #3) At minimum, documenting that
    session/request_permission (and, by extension, any tool requiring human
    input) may arrive between turns — so client authors know to keep that
    channel's UI live independent of turn/status state, the way fix: hold a turn open while its background subagents are still live #870 now
    guarantees for sub-agents but not shells.

Related

Environment: @agentclientprotocol/claude-agent-acp@0.59.0.

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