Slot catalog
Every UI slot where a plugin can contribute interface — rail, command palette, settings, dock panels, pane banners, terminal menu, and the + New menu.
Slots are named places in the UI where a plugin contributes interface. You add to
a slot with ctx.slots.contribute(slot, item) from the
renderer context. Each contribution
is tracked and removed automatically when the plugin deactivates.
ctx.slots.contribute("commands", {
id: "my-plugin.do-thing",
title: "My Plugin: Do Thing",
keywords: "demo example",
run: () => ctx.log("did the thing"),
});
(ctx.commands.register(cmd) is sugar for contributing to the commands slot.)
Slots
SlotItemMap (src/renderer/plugins/slot-registry.ts):
| Slot | Item shape | Renders at |
|---|---|---|
sidebar.actions | { title, icon, onClick, testid?, badge? } | Left rail footer buttons (non-view actions) |
sidebar.sections | { id, render } | Left sidebar, between tab list and footer (expanded only) |
commands | { id, title, keywords?, run } | Command palette (also dispatchable by id) |
settings.sections | { title, render } | Settings panel, after built-in sections |
dock.panels | { id, title, icon?, render, useBadgeCount?, headerActions? } | The workspace dock, as a FIRST-CLASS panel: orders, collapses, drags between docks and persists like Files/Changes. Each also gets a multi-lit launcher button on the left rail (useBadgeCount? drives its badge; the button toggles the panel’s visibility — several can be lit at once) |
overlays | { id, render } | App overlay layer (manage your own visibility) |
pane.banners | { id, render(sessionId) } | Per-terminal-pane top strip (render null when idle) |
pane.footerBanners | { id, render(sessionId) } | Per-terminal-pane footer strip — home of the built-in connection-status banner (render null when idle) |
terminal.contextMenu | { label, run } | Terminal right-click menu, appended group |
workspace.cardAccessory | { id, render({ tabId }) } | Each workspace card’s trailing edge in the expanded left rail (e.g. an extra badge) |
workspace.flyoutSessionRow | { id, render({ tabId, paneId, paneTabId, sessionId }) } | Each session row in the workspace flyout |
newTab.entries | { id, label, glyph?, section?, order?, run?(target) | picker } | A tab kind in the + New dropdown (opened by the titlebar/rail + New and each pane +), beside the built-in local Terminal |
agents.rowActions | { id, label, run(sessionId) } | The Agents hub’s per-agent row overflow menu (an extra action on a listed agent, e.g. “open in editor”). sessionId is null for a not-yet-spawned tab |
Overlays vs. panels
Overlay contributions that should participate in the central Escape handler and
terminal focus-reclaim must report their open state via useReportOverlay from
src/renderer/plugins/overlay-authority.ts (the Sprites / SSH overlays show the
pattern).
Feature management surfaces (Sprites / SSH / Agents) are docked panels —
contribute them via dock.panels and toggle them from the multi-lit launcher
buttons on the left rail (several can be open at once); they are not overlays.
The overlays slot is for true modals only (e.g. the sprite chooser, the SSH
host-picker and connection manager). Modal overlays that should participate in the
central Escape handler / terminal focus-reclaim must still report their open state
via useReportOverlay.
The built-in Settings and Notifications panels remain right-edge slide-overs and
use useExclusiveRightPanel; plugin features no longer claim the right edge.
Plugins can also intercept new-session requests (New Tab, pane +) through
src/renderer/workspace/new-session-bridge.ts — registrations are plain
unregister functions, so wrap them with ctx.track.
The + New dropdown (newTab.entries)
A newTab.entries item adds a tab kind to the + New dropdown — opened by the
titlebar / rail + New and each pane +, beside the built-in local Terminal.
section:"local"(with Terminal) or"remote"(below a separator, default);ordersorts within a section.- Provide EITHER
run(target)(a leaf action — open + close) ORpicker(a drill-in{ render({ target, onClose, onBack }) }searchable panel; use the sharedNewTabPickerList). targetis{ kind: "newTab" }or{ kind: "paneTab", paneId }.
The Sprites / SSH plugins add Sprite / SSH drill-in pickers here.
For rendering whole pane-tabs and the dock-vs-grid movable panel helpers, see Pane surfaces & panels.