Skip to content

feat(tui): list active and recent subagents in the sidebar - #46109

Open
iceteaSA wants to merge 1 commit into
anomalyco:devfrom
iceteaSA:tui-subagents-sidebar
Open

iceteaSA wants to merge 1 commit into
anomalyco:devfrom
iceteaSA:tui-subagents-sidebar

Conversation

@iceteaSA

@iceteaSA iceteaSA commented Aug 29, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #41249. Supersedes #4865 by @franlol (open).

Type of change

  • New feature

Credit

The feature and the original implementation are @franlol's in #4865: subagents in the sidebar, click to navigate. This is that, rebased onto dev, with one change that came out of using it. In an orchestration session with hundreds of subagents, listing every one made the sidebar useless. So this shows the active subagents, plus a short, separate list of the last 10 finished ones. If @franlol revisits #4865, that split is the part worth lifting. If theirs lands, I'll close this. @giovannic96 requested the same feature in #41249 after shipping it as an external plugin, and #42369 asked for "running and optionally recently finished" subagents. The live activity text and the collapsible active list are @giovannic96's suggestions from their plugin, and they are credited as co-author on the commit.

Parent navigation and the return-to-parent keybind from #4865 are already on dev, so this adds just the lists.

What does this PR do?

Adds two sidebar sections. Select a row to open that child session.

  • Subagents: in-flight subagents (pending and running), deduped by child session id so a resumed task_id renders once. Each row shows what the subagent is doing right now, taken from its newest message: the running or queued tool with its title or target (read: src/foo.ts, bash: bun test), or retrying 2. The text clears when the subagent starts a new turn, a tool fails, or it moves on to thinking or writing after a tool. The section collapses when it holds more than one row, and shows the count while collapsed.
  • Recent subagents: up to 10 finished subagents, most recently active first, each marked Done or Failed with a relative time ("3m ago"). It collapses when long, like the file, LSP and MCP lists. A subagent never appears in both sections. The section is hidden when empty.

Both lists keep their collapsed state in KV (sidebar:subagents:open, sidebar:subagents:recent:open), so it holds across sessions, entering and leaving a subagent, and restarts. #51543 does the same for the MCP, LSP, Todo and Modified files sections; with both merged, sidebar_sections from #51543 can also move or hide this section by the name subagents.

Liveness comes from the child session's status, not the parent's task tool-part status. A background dispatch completes the parent's tool part the instant the child spawns, so that part reads completed while the child runs for minutes. On my machine, of the last 300 task parts, 270 were completed and zero were running, including a subagent that was executing at the time. Filtering on the parent part would leave the active list empty forever. api.state.session.status(childID) is the correct signal; idle sessions are absent from that map by design.

History is ordered by the child's latest activity: the newest of its session's update time, its newest message completion, and the parent task part's time. Session time.updated alone isn't enough, because it only moves when a prompt starts, so a subagent that ran for 20 minutes would sort by when it began.

Locale.relative moves from dialog-stash.tsx to util/locale.ts so both places share it. The stash dialog behaves the same.

How did you verify your code works?

  • packages/tui: 58 sidebar tests pass, 0 fail, plus the full TUI suite (230 pass). Tests cover the active filter, dedup, the background-completed-parent-with-busy-child case, the 10-row cap, ordering by child activity rather than dispatch order (with a case where the two disagree), a subagent that moves between sections when resumed, failure detection from the child's last reply, each activity rule (including stale-label cases: a newer user message, a queued or failed tool, and reasoning after a finished tool), a rendered test that clicks the header to collapse and expand the active list, and rendered tests that collapse each list, remount, and find it still collapsed.
  • Removing the cap, sorting by the parent part's time, dropping the activity boundary, disabling the collapse toggle, or writing either list's state to the wrong key each fails the tests.
  • bun typecheck clean in packages/tui.
  • The active list was confirmed live with a running background subagent. The history section, activity text and collapse are covered by tests and have not yet been checked in a live session.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Related PRs Found

#4865: feat: add subagents sidebar with clickable navigation and parent keybind

#14043: feat(web): Show subagents under parent session, allow intuitive navigation between

#25712: feat(tui): show subagent cost rollup in sidebar and task history

@giovannic96

Copy link
Copy Markdown

I'd built a similar section independently (referenced in #41249), same file path and plugin id even, so consider this a comparison rather than a competing submission.

Two things mine did differently that might be worth folding in here:

  1. Live per-row activity text. Instead of a static description, each row shows what the subagent is currently doing (reading file.ts, calling bash, retrying 2, etc.), sourced from the child session's own tool/part events. Useful for telling apart two subagents that look identical from their task description alone.
  2. Collapse when there are many. Once there's more than one subagent, the section header becomes clickable to collapse/expand while keeping the count visible. Might be worth pairing with your active-only filter for sessions that still end up with a lot of concurrent subagents.

Happy to open a small follow-up PR with just these two additions on top of your branch once/if this lands. Anyway, glad to see this moving, thanks for picking it up.

@iceteaSA
iceteaSA force-pushed the tui-subagents-sidebar branch from 1cda243 to b5bec4a Compare September 13, 2026 05:25
@github-actions github-actions Bot mentioned this pull request Sep 18, 2026
3 tasks done
@iceteaSA
iceteaSA force-pushed the tui-subagents-sidebar branch 2 times, most recently from 7825f3e to 4171bf3 Compare September 23, 2026 18:24
@iceteaSA iceteaSA changed the title feat(tui): list active session subagents in the sidebar feat(tui): list active and recent subagents in the sidebar Sep 23, 2026
@iceteaSA
iceteaSA force-pushed the tui-subagents-sidebar branch from 4171bf3 to 8ed7bfc Compare September 23, 2026 19:08
iceteaSA added a commit to iceteaSA/opencode that referenced this pull request Sep 23, 2026
Brings the updated anomalyco#46109 (live activity text on active rows, collapsible active section) onto the integration branch. The fork's per-row tokens-per-second suffix stays after the activity text.

Co-authored-by: Giovanni Calà <[email protected]>
@iceteaSA

Copy link
Copy Markdown
Author

@giovannic96 thanks, both were worth having, so I folded them into this PR rather than leaving them for a follow-up, and credited you as co-author on the commit.

  • Activity text on active rows, based on your getPartActivity: the running or queued tool with its title or target, or retrying N. I kept it to the child's newest message. Walking back through older messages left stale labels, e.g. read: old.ts still showing after the subagent had started a new turn, or had moved on to thinking after the tool finished.
  • Collapse on the active list once it has more than one row, with the count in the header, same pattern as the other sidebar lists.

If you spot anything your plugin handles that this misses, I'm glad to take it.

Upstream PR anomalyco#4865 by @franlol, reimplemented against the current TUI. That PR targeted packages/opencode/src/cli/cmd/tui/routes/session/, which no longer exists.

Its navigation and parent keybind have since landed upstream independently, so this adds only the missing sidebar section. It diverges from that PR deliberately: instead of every historical subagent, it shows the in-flight ones (pending and running) and, in a separate "Recent subagents" section, the last 10 finished ones, most recently active first. Real sessions accumulate hundreds of dispatched subagents, and a complete list is unusable.

Background dispatches complete the parent tool part immediately, so liveness comes from child-session status. History is ordered by the child's latest activity: the newest of its session update time, its newest message completion, and the parent task part's time, since a session's update time only marks when its last prompt started.

Active rows show what the subagent is doing now, from its newest message: the running or queued tool, a retry count, or nothing once it starts a new turn or writes after a tool. The active list collapses when it holds more than one row, and the recent list when it holds more than two; both remember their collapsed state across sessions and restarts. Activity and collapsing follow @giovannic96's opencode-subagents-view plugin.

Co-authored-by: Giovanni Calà <[email protected]>

This branch has not been deployed

No deployments
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.

[FEATURE]: Live Subagents sidebar section in the TUI

2 participants