Skip to content

[Bug]: OpenCode background shells aren't pending work: the thread looks finished, Stop and restart recovery miss them #32829

Closed

Description

@nkoynov

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

  • apps/server

OpenCode provider, packages/provider-opencode v2 adapter.

Steps to reproduce

  1. In an OpenCode thread, have the agent start a background shell (OpenCode's shell tool with background: true, e.g. sleep 300; echo done) and end its turn.
  2. While the shell runs, look at the thread, press Stop, or restart T3.

Expected behavior

The running shell counts as the thread's pending background work, the way Claude and Codex background commands do (pendingBackgroundTasks with kind: "command"). The thread doesn't look finished, Stop ends the shell, and restart recovery records it as cancelled work, so the agent is told on its next turn.

Actual behavior

On main (e11c2fd), syncRoster builds pendingBackgroundTasks only from background subagent calls. So while an OpenCode shell runs:

A subagent's own background shell has the same gap. Once the subagent ends its turn, settleCall drops its call (L1427), and nothing above it tracks the shell.

Running OpenCode shells could be listed as pendingBackgroundTasks with kind: "command", from #18920's state.shells including child sessions via sessionsOf, with parentTaskId for a subagent's shell, which recovery already handles. Stop could end them with client.shell.remove (DELETE /api/shell/:id, in the pinned @opencode/client 2.0.28).

Impact

Minor bug or occasional failure

Version or commit

Seen on 0.1.x nightlies since October; code unchanged on main e11c2fd.

Environment

Linux (NixOS), T3 server as a systemd service, OpenCode 2.2.x, cursor-opencode-provider.

Logs or stack traces

Where we hit it, 2026-10-21 01:29 UTC: a T3 restart we ran while T3 showed nothing running ended a subagent's background test gate 16 minutes in (exit 143). Its parent kept waiting for a result that never came. That shell ran in cursor-opencode-provider's own runner, which T3 can't see anyway. An OpenCode shell job in the same spot behaves the same on main today.

Workaround

Our restart script checks OpenCode's shell list itself before restarting T3.

Related: #19061 (same class, Muse monitors), #18880 (idle unload; #18920 fixes that part for OpenCode shell jobs), and the code paths in our comment on #18920.

Activity

  1. juliusmarminge commented on Nov 11, 2026

    @juliusmarminge
    Member

    Fixed by https://git.cafe/pingdotgg/t3code/pulls/34141, now on main: An OpenCode background shell now remains in the command roster after its turn ends, Stop removes it and descendant shells, and restart recovery uses the persisted roster to record cancelled work for the next turn.

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