You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
tui: Subagents tab lists a subagent waiting on its own background shell as inactive #62365
The Subagents tab in the composer picker shows a subagent as inactive while it waits on its own background work. A subagent that backgrounds a shell (or a subagent of its own) and ends its turn to wait is idle to the host, so the tab's "active" filter (status === "running") drops it and it shows under inactive with no status, even though its shell is running and it will wake when that ends. Same root cause as #48826, on the TUI side.
Suggested fix: derive activity from live state: running while its turn runs, waiting while a shell it started is still running (the shell registry already has this by session) or a session under it is working. The active filter takes both and the row says Waiting.
Fix with a test on my fork: cevr@799f9b5 (about 50 lines in util/session.ts and subagents-tab.tsx).
Ask the agent to start a background subagent whose task is: run sleep 120; echo done with the shell tool in the background, then end your turn and wait for it.
Once the subagent says it's waiting, open the composer picker's Subagents tab.
The subagent isn't listed as active (or is listed with no status), although its shell runs for two more minutes and it resumes afterwards.
Thanks for the detailed report. I reproduced this on 2.2.5, and it still happens on the latest dev (885df74).
Steps, using a simulated model:
The parent starts a background general subagent.
The subagent starts a background shell (sleep 120; echo done) and ends its turn to wait for it.
With the shell still running, open the composer picker's Subagents tab. The active view shows "No active subagents".
Switch to the inactive view with ctrl+a. The subagent is listed there with no status.
The recording and screenshots below show this, and the script below reproduces it. The filter in subagents-tab.tsx only treats a subagent as active when its status is running, and an idle subagent waiting on its own background work doesn't match.
The parent also shows "↳ General finished" while the child's shell is still running. That's the core-side problem tracked in #48826. Related reports, most closely related first:
// Repro for #62365: a background subagent waiting on its own background shell// is listed as inactive in the composer picker's Subagents tab.import{Effect,Stream}from"effect"import{Llm,OpenCodeDriver}from"opencode-drive"consthas=(body: unknown,s: string)=>JSON.stringify(body).includes(s)exportdefaultOpenCodeDriver.use({
...(process.env.OC_DEV ? {opencode: {dev: process.env.OC_DEV}} : {}),tui: {recording: true,keypressOverlay: true},tools: ["shell"],},({ ui, llm, tools })=>Effect.gen(function*(){constshells=yield*tools.control("shell")yield*llm.serve((req)=>{constchild=has(req.body,"You are a subagent spawned")if(child){if(has(req.body,"CHILD_DONE_MARK")||has(req.body,'state=\\"completed\\"'))returnStream.make(Llm.text("Shell finished: done. CHILD_FINAL"))if(has(req.body,"call_shell"))returnStream.make(Llm.text("Shell is running in the background; waiting for it to finish."))returnStream.make(Llm.toolCall({index: 0,id: "call_shell",name: "shell",input: {command: "sleep 120; echo done",description: "Sleep then echo",background: true},}),Llm.finish("tool-calls"),)}if(has(req.body,"call_sub"))returnStream.make(Llm.text("Started the background subagent."))returnStream.make(Llm.toolCall({index: 0,id: "call_sub",name: "subagent",input: {agent: "general",description: "Wait on shell",prompt: "Run `sleep 120; echo done` in the background with the shell tool, then end your turn and wait.",background: true,},}),Llm.finish("tool-calls"),)})yield*ui.submit("Start a background subagent that runs a background shell and waits for it")constshell=yield*shells.take("call_shell")yield*ui.waitFor("General finished",{timeout: 20000})yield*Effect.sleep(3000)yield*ui.screenshot("01-parent-after-spawn")// open the subagent picker (composer Subagents tab, active filter)yield*ui.press("down")yield*Effect.sleep(1500)yield*ui.screenshot("02-subagents-active-filter")yield*ui.press("a",{ctrl: true})yield*Effect.sleep(1500)yield*ui.screenshot("03-subagents-inactive-filter")yield*ui.press("escape")// the child's shell is still running; finish it nowyield*shell.succeed({output: "done\n",exit: 0})yield*Effect.sleep(3000)yield*ui.screenshot("04-after-shell-finished")}),)
Run it with opencode-drive: opencode-drive run ./drive.ts. It drives opencode from your PATH; set OC_DEV to the path of an OpenCode checkout to run that from source instead.
Activity
opencodejr commentedon Nov 6, 2026
Thanks for the detailed report. I reproduced this on 2.2.5, and it still happens on the latest
dev(885df74).Steps, using a simulated model:
generalsubagent.sleep 120; echo done) and ends its turn to wait for it.The recording and screenshots below show this, and the script below reproduces it. The filter in
subagents-tab.tsxonly treats a subagent as active when its status isrunning, and an idle subagent waiting on its own background work doesn't match.The parent also shows "↳ General finished" while the child's shell is still running. That's the core-side problem tracked in #48826. Related reports, most closely related first:
recording.mp4
Reproduction script (drive.ts)
Run it with opencode-drive:
opencode-drive run ./drive.ts. It drivesopencodefrom yourPATH; setOC_DEVto the path of an OpenCode checkout to run that from source instead.