Skip to content
Logo

Plugin System

Boo has an extensible plugin architecture for sidebar panels, status bar segments, and terminal lifecycle hooks. A plugin can contribute a sidebar tab, a status bar segment, or both — a sidebar tab is not required.

Plugin Types

  1. Built-in — Swift classes in Boo/Plugins/ conforming to BooPluginProtocol
  2. External — JavaScript in ~/.boo/plugins/ with a plugin.json manifest, hot-loaded at runtime

Built-in Plugins

PluginIDDescription
Filesfile-tree-local, file-tree-remoteFile explorer with local FSEvents and remote browsing
Gitgit-panelBranch, staged/unstaged/untracked files, ahead/behind counts
AgentsagentsAgent Center for Claude Code, Codex, OpenCode, and AI CLI sessions
SnippetssnippetsSaved code snippets with syntax highlighting and quick insertion
DockerdockerContainer list with exec, logs, start/stop/restart
BookmarksbookmarksSaved directory shortcuts with per-host namespacing
Systemsystem-infoCPU, memory, disk — reference example for plugin patterns
DebugdebugLive lifecycle event log and terminal state inspector

Plugin Lifecycle

Every terminal state change triggers a plugin cycle with a PluginCycleReason:

ReasonTriggered by
.focusChangedPane focus moved
.cwdChangedWorking directory changed
.titleChangedTerminal title changed
.processChangedForeground process changed
.remoteSessionChangedRemote session started or ended
.workspaceSwitchedActive workspace switched

The cycle phases (total budget: <16ms):

  1. Enrich — Plugins write shared data to a mutable EnrichmentContext
  2. Freeze — Produces an immutable TerminalContext snapshot
  3. React — Plugins receive the frozen context
  4. Evaluate — When-clauses determine visibility; status bar content is collected
  5. Rebuild — Sidebar and status bar are updated

Call onRequestCycleRerun?() when plugin data changes externally (e.g., Docker events, git commit) to trigger a refresh.

TerminalContext

Immutable snapshot passed to all plugin methods:

FieldTypeDescription
terminalIDUUIDActive terminal identifier
cwdStringCurrent working directory
remoteSessionRemoteSessionType?Remote session info, if active
remoteCwdString?Remote working directory
environmentLabelStringDisplay label for the terminal session
gitContextGitContext?Branch, dirty state, file counts
processNameStringForeground process name
paneCountIntPanes in workspace
tabCountIntTabs in active pane
isRemoteBoolComputed: remoteSession != nil

GitContext fields: branch, repoRoot, isDirty, changedFileCount, stagedCount, aheadCount, behindCount, lastCommitShort.

PluginActions

Unified action dispatch for plugins:

pluginActions.exec("make build")     // Send command to terminal
pluginActions.cd(to: "/some/path")   // cd + Enter
pluginActions.pastePath("/foo/bar")  // Insert path without executing
pluginActions.copy("text")           // Copy to clipboard
pluginActions.reveal("/some/file")   // Show in Finder
pluginActions.openInEditor("/file")  // Open with default app
pluginActions.openDirectoryInNewTab?("/some/dir")   // Open dir in new tab
pluginActions.openDirectoryInNewPane?("/some/dir")  // Open dir in new pane

Also exposes closures: sendToTerminal, openDirectoryInNewTab, openDirectoryInNewPane, displayImageInTerminal, isTerminalBusy, registerMultiContentTab, openMultiContentTab, setAgentSessionID, getAgentSessionID.

Capabilities

Manifest capability flags that control where a plugin appears:

FlagDescription
capabilities.sidebarTabContribute a dedicated full-height sidebar tab (Swift plugins)
capabilities.statusBarSegmentContribute a segment to the status bar (can be the sole capability)

External JS plugins automatically get a sidebar tab — no capabilities field needed in plugin.json. Use statusBarSegment: true only when adding a status bar segment.

See Plugin Development for makeSidebarTab details.

When-Clauses

Control plugin visibility via the when manifest field:

ExpressionMeaning
nullAlways visible
"git.active"Only in git repos
"!remote"Only local sessions
"remote"Only remote sessions
"env.ssh"SSH or Mosh
"env.docker"Docker sessions
"env.container"Any container/VM/device shell
"env.type == 'kubectl'"Specific tool match
"git.active && !remote"Combined conditions

Operators: &&, ||, !, ==, !=, ().

DSL Actions

Interactive elements dispatch these actions:

ActionParametersEffect
"cd"pathChange terminal dir
"open"pathOpen in $EDITOR
"exec"commandSend command to terminal
"copy"text or pathCopy to clipboard
"reveal"pathOpen in Finder
"url"url or textOpens URL in browser
"newTab"path (optional)Opens new terminal tab
"newPane"path (optional)Opens new split pane
"paste"textInserts text at cursor
"notification"text, title (optional)Shows notification

Plugin Settings

Plugins declare settings in their manifest. The Settings window renders controls automatically.

AppSettings.shared.pluginBool("my-plugin", "myKey", default: true)
AppSettings.shared.pluginString("my-plugin", "myKey", default: "")
AppSettings.shared.pluginDouble("my-plugin", "myKey", default: 12.0)
PluginKeyTypeDefaultDescription
FilesshowHiddenFilesBoolfalseShow hidden files
FilesshowIconsBooltrueShow file icons
FilesshowPathBooltrueShow path above tree
FilesshowProcessBooltrueShow running process
FilesshowFilterBarBooltrueShow filter bar (/ focuses it)
FilesgitDecorationsBooltrueShow git status badges
FilesdimIgnoredBooltrueDim git-ignored files
FileseditorFilePatternsStringbuilt-in listComma-separated patterns that open in the editor
FilesmarkdownOpenModeStringpreviewpreview, builtInEditor, editor (terminal), external
FilesimageOpenModeStringimageViewerimageViewer, kitty, external
FilestextOpenModeStringeditoreditor, terminalEditor, external
FileshtmlOpenInBrowserBoolfalseOpen HTML files in a browser tab
FilespdfOpenInBrowserBooltrueOpen PDF files in a browser tab
GitshowBranchBooltrueShow branch in status bar
GitdiffToolString""External diff command, {file} placeholder
DockersocketPathString""Docker socket path (empty = auto-detect)
SystemstatusBarMemoryBoolfalseShow memory in status bar
SystemstatusBarDiskBoolfalseShow disk in status bar
SystemstatusBarCPUBoolfalseShow CPU in status bar
SystemstatusBarBatteryBoolfalseShow battery in status bar
DebugmaxEntriesDouble200Max log entries

The Agents plugin uses its own custom settings page instead of manifest-rendered controls.

Status Bar

Built-in segments: Environment, Git Branch, Path, Process (left); File Tree toggle, Pane Info, Clock (right).

Sidebar plugins automatically get toggle icons in the status bar — no manual registration needed. Toggle segments in Settings → Status Bar.

External plugins contribute items to the "Plugins" menu bar via menus in plugin.json. See Plugin Development for details.

Swift plugins implement menuContributions() -> [PluginMenuItem] and handleMenuAction(_ action: String, context: TerminalContext) on BooPluginProtocol.

External Plugins

JavaScript plugins run in-process via JavaScriptCore. See the Plugin Development guide.