Files
orca/docs/reference/plugin-host-api.md
T
Neil a9b1041ecc feat(plugins): status bar items plugins can update live (#37291)
* plugins: contributes.statusBarItems with worker updates (statusBar.update)

A plugin declares status bar items { id, text?, icon?, tone?, tooltip?,
command? } (declarative profile, engines >=1.4.247); pressing one runs
its own command. A trusted worker changes them with the new worker-only
host method statusBar.update; main keeps the session's changes and
pushes snapshots to desktop windows over plugins:statusBarChanged.
Regenerates schemas, references, typings and the authoring skill.

* plugins: statusBarItems ship in 1.4.248, beside contributes.hooks

* plugins: clear a plugin's status bar changes when it is disabled, removed or updated

* plugins: list status bar items in the plugin page's Adds section

* plugins: count statusBarItems' since in the host's newest readable version

* i18n: add the plugin page's status bar row label to en.json

* plugins: status bar items respect workspace commands, dev reloads and catalog summaries

- An item whose command needs a workspace is disabled with no open workspace.
- A dev code edit (new devRevision) drops the old worker's status bar changes.
- Catalog summaries list status bar items, and marketplace details show them.

* plugins: authoring skill lists status bar items as buildable; approval lists them

The skill no longer calls status bar items reserved and gains a row for them. The
dev-load/inspect approval already lists them via the contribution summary; a test pins
that and the fingerprint binding.

* chore(plugins): regenerate the testing bundle after rebasing on main
2026-11-02 04:26:55 +00:00

13 KiB

Orca plugin host API reference

Host API 1.2 ("pluginApi": 1). Workers call a method with await orca.host.call(name, params); panels and custom editors call the same methods through window.orca.host.call(name, params). Each method lists the surfaces allowed to call it; any other surface gets not_permitted. orca.host.has(name) answers synchronously whether this Orca offers a method on the current surface, and orca.api is { major, minor }. See Plugin authoring for the frame API.

Every call is checked against the capabilities the user approved, and params are validated before Orca runs anything: params are strict, so a field this Orca does not know is refused with invalid_params instead of being dropped. Mutations are recorded in the audit log as plugin:<publisher>.<id>.

Methods whose capability is none need no capability but still need the plugin enabled and approved. shell.openExternal and files.saveAs also need transient user activation (a click or key press in the calling frame, within a few seconds), are rate-limited, and run only in the desktop app; frames also reach them as orca.shell.openExternal(url) and orca.files.saveAs({ suggestedName, mimeType, data }), which resolves with { status: "saved" }, or { status: "cancelled" } when the person cancels the dialog. Saved files carry the OS mark for downloaded files.

Methods

Method Capability Surfaces Mutation Since Summary
workspace.readContext workspace:read worker, panel, editor no 1.0 Branch, name and terminal ids of the focused workspace, or null when none is focused.
terminal.sendText terminal:send worker yes 1.0 Types text into one terminal named by id, optionally pressing Enter.
notifications.show notifications:show worker, panel, editor yes 1.0 Shows a desktop notification.
storage.get storage:own worker, panel, editor no 1.0 Reads a JSON value from the plugin's private store; null when absent.
storage.set storage:own worker, panel, editor yes 1.0 Writes a JSON value to the plugin's private store.
storage.delete storage:own worker, panel, editor yes 1.0 Removes a key from the plugin's private store.
storage.keys storage:own worker, panel, editor no 1.0 Lists the keys in the plugin's private store.
secrets.get secrets:own worker, panel, editor no 1.0 Reads a secret from the plugin's encrypted secrets file; null when absent.
secrets.set secrets:own worker, panel, editor yes 1.0 Stores a secret in the plugin's encrypted secrets file.
secrets.delete secrets:own worker, panel, editor yes 1.0 Removes a secret from the plugin's encrypted secrets file.
secrets.protection secrets:own worker, panel, editor no 1.1 How secrets are protected at rest: os-keyring, or unavailable (no OS key store, or Linux basic_text), where secrets.set fails.
settings.get settings:own worker, panel, editor no 1.0 Reads every setting the plugin owns.
settings.set settings:own worker, panel, editor yes 1.0 Writes one setting the plugin owns.
shell.openExternal none panel, editor no 1.1 Opens an http:, https: or mailto: URL in the default browser. Needs a click or key press in the frame; desktop app only. Orca asks the person before an http(s) host the plugin was not allowed; opened is false if they cancel.
files.saveAs none panel, editor yes 1.1 Offers data (a string or ArrayBuffer, up to 64 MiB) in Orca's save dialog; the plugin never learns the path. Needs a click or key press in the frame; desktop app only.
plugin.request none panel, editor no 1.2 Asks the plugin's own worker to run the handler it registered with orca.panels.handle(name), starting the worker if needed; resolves with what the handler returned. unknown_method when no handler has that name.
agents.list agent:read worker, panel, editor no 1.2 The agents in the focused workspace: their terminal, title, agent kind and status. agent.status.changed reports each change after.
events.subscribe none panel, editor no 1.2 Delivers a workspace or agent event to this panel as orca.on(event); needs the event's read capability. The frame APIs call it for you.
statusBar.update none worker no 1.2 Changes one of the plugin's contributes.statusBarItems (named by id): fields given replace their current value, visible: false hides it. Desktop app only; lasts until Orca restarts, and is hidden while the plugin is disabled.

workspace.readContext

Branch, name and terminal ids of the focused workspace, or null when none is focused.

(params?: {}) => { branch: string; displayName: string; terminals: { id: string; title?: string }[] } | null

terminal.sendText

Types text into one terminal named by id, optionally pressing Enter.

(params: { terminalId: string; text: string; enter?: boolean }) => { accepted: boolean }

notifications.show

Shows a desktop notification.

(params: { title: string; body?: string }) => { delivered: boolean }

storage.get

Reads a JSON value from the plugin's private store; null when absent.

(params: { key: string }) => { value: JSON }

storage.set

Writes a JSON value to the plugin's private store.

(params: { key: string; value: JSON }) => { ok: true }

storage.delete

Removes a key from the plugin's private store.

(params: { key: string }) => { ok: true }

storage.keys

Lists the keys in the plugin's private store.

(params?: {}) => { keys: string[] }

secrets.get

Reads a secret from the plugin's encrypted secrets file; null when absent.

(params: { key: string }) => { value: string | null }

secrets.set

Stores a secret in the plugin's encrypted secrets file.

(params: { key: string; value: string }) => { ok: true }

secrets.delete

Removes a secret from the plugin's encrypted secrets file.

(params: { key: string }) => { ok: true }

secrets.protection

How secrets are protected at rest: os-keyring, or unavailable (no OS key store, or Linux basic_text), where secrets.set fails.

(params?: {}) => { status: "os-keyring" | "unavailable" }

settings.get

Reads every setting the plugin owns.

(params?: {}) => { settings: Record<string, JSON> }

settings.set

Writes one setting the plugin owns.

(params: { key: string; value: JSON }) => { ok: true }

shell.openExternal

Opens an http:, https: or mailto: URL in the default browser. Needs a click or key press in the frame; desktop app only. Orca asks the person before an http(s) host the plugin was not allowed; opened is false if they cancel.

(params: { url: string }) => { opened: boolean; reason?: "cancelled" | "consent-unavailable" }

files.saveAs

Offers data (a string or ArrayBuffer, up to 64 MiB) in Orca's save dialog; the plugin never learns the path. Needs a click or key press in the frame; desktop app only.

(params: { suggestedName?: string; mimeType?: string; data: string | ArrayBuffer }) => { status: "saved" | "cancelled" }

plugin.request

Asks the plugin's own worker to run the handler it registered with orca.panels.handle(name), starting the worker if needed; resolves with what the handler returned. unknown_method when no handler has that name.

(params: { name: string; input?: JSON; timeoutMs?: number }) => { output: JSON }

agents.list

The agents in the focused workspace: their terminal, title, agent kind and status. agent.status.changed reports each change after.

(params?: {}) => { agents: { terminalId: string | null; title: string | null; agent: string | null; state: "working" | "blocked" | "waiting" | "done"; stateStartedAt: number }[] }

events.subscribe

Delivers a workspace or agent event to this panel as orca.on(event); needs the event's read capability. The frame APIs call it for you.

(params: { event: "workspace.created" | "workspace.removed" | "agent.status.changed" | "workspace.changed" }) => { ok: true }

statusBar.update

Changes one of the plugin's contributes.statusBarItems (named by id): fields given replace their current value, visible: false hides it. Desktop app only; lasts until Orca restarts, and is hidden while the plugin is disabled.

(params: { id: string; text?: string; icon?: "activity" | "bar-chart-3" | "bell" | "blocks" | "book" | "bot" | "bug" | "calendar" | "cloud" | "code" | "database" | "file-text" | "flag" | "folder" | "gauge" | "globe" | "hammer" | "layers" | "lightbulb" | "package" | "plug" | "puzzle" | "rocket" | "star" | "terminal" | "wrench" | "zap" | "add" | "remove" | "delete" | "edit" | "refresh" | "search" | "settings" | "check" | "close" | "info" | "warning" | "error" | "open-external" | "copy" | "download" | "upload" | "play" | "pause" | "stop" | "more" | "expand" | "collapse" | "next" | "filter" | "branch" | "file" | "agent" | "link"; tone?: "neutral" | "accent" | "success" | "warning" | "danger"; tooltip?: string; visible?: boolean }) => { ok: true }

Events

A worker receives the events its manifest lists in contributes.events through orca.events.on(event, handler), which returns { dispose() }. Each needs main, the trusted-worker profile and its domain's capability (workspace:read or agent:read). orca plugin types writes the payloads as PluginEvents in orca/host.

Event Payload Summary
workspace.created { workspaceId: string; kind: "worktree" | "folder"; path: string; branch: string } A worktree workspace was created.
workspace.removed { workspaceId: string; kind: "worktree" | "folder"; path: string } A worktree workspace was removed.
agent.status.changed { workspaceId: string | null; paneKey: string; terminalId?: string; title?: string; state: "working" | "blocked" | "waiting" | "done"; receivedAt: number; mainAgent?: { state: "working" | "blocked" | "waiting" | "done"; outcome?: "success" | "failure" | "cancellation" | "superseded" | "interruption" | "unconfirmed"; stateStartedAt: number } } An agent in a terminal pane changed status; workspaceId is null when Orca cannot tie the pane to a workspace, and terminalId names its terminal when Orca lists it.
workspace.changed { context: { branch: string; displayName: string; terminals: { id: string; title?: string }[] } | null } The focused workspace changed, or its terminals were opened, closed or renamed; context is what workspace.readContext now answers. Each new subscriber first gets the current context.

Errors

A failed call rejects with an Error carrying code, message, retryable and, for rate_limited, retryAfterMs. Treat a code not listed here as action_failed:

  • invalid_request: the call itself is malformed.
  • invalid_params: params do not match the method, including a field this Orca does not know; the message names it.
  • unknown_method: the method does not exist in this Orca.
  • capability_denied: the manifest does not declare the capability.
  • consent_required: the plugin is disabled or the user has not approved this version.
  • not_permitted: the method or document is not available here, e.g. a worker-only method from a panel.
  • rate_limited: calls arrive faster than the budget; retryAfterMs says when to try again.
  • unavailable: the service behind the method is not running yet.
  • action_failed: the method ran and failed.
  • cancelled: the caller aborted the call through its signal.
  • timeout: Orca gave up waiting.
  • conflict: the call was made against a stale version, e.g. an editor edit after an outside change.
  • too_large: the message is larger than Orca accepts.

Stability and deprecation

Plugins are in Alpha: the manifest v2 format and catalog format are stable contracts; items listed as experimental in Plugin authoring may change.

  • Host API 1 is frozen. Within pluginApi 1, methods, params and results only grow: a new method or a new optional param arrives with a higher Since minor, and nothing listed here is removed, renamed or narrowed.
  • Deprecation. A method to be retired is marked deprecated in this table and keeps working for the rest of the major.
  • New majors. A breaking change ships as a new pluginApi major beside the old one. Orca refuses a manifest whose pluginApi names a major it does not implement, with "update Orca", instead of loading it against the wrong API.
  • Detect, do not assume. Check orca.host.has(name) or orca.api.minor before calling a method newer than the oldest Orca you support; a call that slips through fails with unknown_method.