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
[FEATURE]: TUI plugin API: let plugins add a tab to the composer picker #59650
I have verified this feature I'm about to request hasn't been suggested before.
Describe the enhancement you want to request
In the V2 TUI, the Down key opens the composer picker (session.child.first, "Toggle subagent picker"). The picker has three tabs: Subagents, Shells and Terminals. Left and Right move between the tabs.
A TUI plugin cannot add a tab to this picker:
The composer adds its tabs through ComposerContext.register (packages/tui/src/routes/session/composer/index.tsx:47, composer/context.ts:8-18). This context is internal to the TUI.
The same file sets the three tab components (composer/index.tsx:127-130).
The TUI plugin API has no slot or registry for the picker. The slot map has session.composer.top and session.panel, but no slot in the picker (packages/plugin/src/tui/context.ts:191-202).
I checked these files at the v2.2.0 tag. They are the same in 2.1.4.
Request: let a TUI plugin add a tab to the composer picker.
Example: a plugin sends messages and notices to sessions, for example messages from other sessions, subagent results and scheduled reminders. The TUI shows each one as a one-line synthetic message. A plugin tab in the picker can list these items with their sender and type, and expand one item to show its full text. Users then find these items in the same area as subagents and shells.
Possible API (a suggestion only):
constremove=ctx.ui.composer.tab({id: "mail",label: "Mail",order: 40,hints: ()=>[{label: "expand",shortcut: "enter"}],render: (input: {sessionID: string;active: boolean})=><MailTab{...input}/>,})// remove() takes the tab out of the picker
The host keeps the picker layout, the Left and Right tab keys, and the focus.
The plugin tab gets the Up, Down and Enter keys while it is the active tab, the same as the built-in tabs.
The host removes the tab when the plugin stops.
This API uses the current ComposerTab fields (id, label, hints) and adds order and render.
Current workaround: the session.panel slot with ui.panel.open(name). It works, but it opens a different view with a different key. Users must then look in two areas for related items.
Related:#59432 (render synthetic messages with a plugin component), #51209 (expose the V2 TUI composer to plugins), #51903 (composer tabs are not clickable).
Thanks for the detailed request, @iceteaSA! You're asking for a TUI plugin API that lets a plugin add its own tab to the composer picker, next to Subagents, Shells and Terminals. The host would keep the layout, the Left/Right tab keys and focus, and the plugin tab would get Up/Down/Enter while it is active.
I checked the code and you're right: tabs are registered through the internal ComposerContext, and the plugin SlotMap has no slot or registry inside the picker. So this can't be built as a plugin today. It would need a new plugin API, something like the ctx.ui.composer.tab(...) you sketched, so maintainers will consider it as an addition to the plugin API.
+1, I built this on my fork as ui.composerTab({ id, title, hints?, render }): the tab goes after the host's, its content mounts only while it's the active tab of an open panel (so a mode: "composer" keymap layer it creates only acts then), and the panel keeps ←/→ and Escape. render gets { sessionID, close }. cevr@2d74252 (+ cevr@4e03533), with a test. Happy to send a PR.
Activity
opencode-agent commentedon Oct 27, 2026
Thanks for the detailed request, @iceteaSA! You're asking for a TUI plugin API that lets a plugin add its own tab to the composer picker, next to Subagents, Shells and Terminals. The host would keep the layout, the Left/Right tab keys and focus, and the plugin tab would get Up/Down/Enter while it is active.
I checked the code and you're right: tabs are registered through the internal
ComposerContext, and the pluginSlotMaphas no slot or registry inside the picker. So this can't be built as a plugin today. It would need a new plugin API, something like thectx.ui.composer.tab(...)you sketched, so maintainers will consider it as an addition to the plugin API.Related issues:
cevr commentedon Nov 11, 2026
+1, I built this on my fork as
ui.composerTab({ id, title, hints?, render }): the tab goes after the host's, its content mounts only while it's the active tab of an open panel (so amode: "composer"keymap layer it creates only acts then), and the panel keeps ←/→ and Escape.rendergets{ sessionID, close }. cevr@2d74252 (+ cevr@4e03533), with a test. Happy to send a PR.