# 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](./plugin-authoring.md) 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:.`. 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`](#workspacereadcontext) | `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`](#terminalsendtext) | `terminal:send` | worker | yes | 1.0 | Types text into one terminal named by id, optionally pressing Enter. | | [`notifications.show`](#notificationsshow) | `notifications:show` | worker, panel, editor | yes | 1.0 | Shows a desktop notification. | | [`storage.get`](#storageget) | `storage:own` | worker, panel, editor | no | 1.0 | Reads a JSON value from the plugin's private store; null when absent. | | [`storage.set`](#storageset) | `storage:own` | worker, panel, editor | yes | 1.0 | Writes a JSON value to the plugin's private store. | | [`storage.delete`](#storagedelete) | `storage:own` | worker, panel, editor | yes | 1.0 | Removes a key from the plugin's private store. | | [`storage.keys`](#storagekeys) | `storage:own` | worker, panel, editor | no | 1.0 | Lists the keys in the plugin's private store. | | [`secrets.get`](#secretsget) | `secrets:own` | worker, panel, editor | no | 1.0 | Reads a secret from the plugin's encrypted secrets file; null when absent. | | [`secrets.set`](#secretsset) | `secrets:own` | worker, panel, editor | yes | 1.0 | Stores a secret in the plugin's encrypted secrets file. | | [`secrets.delete`](#secretsdelete) | `secrets:own` | worker, panel, editor | yes | 1.0 | Removes a secret from the plugin's encrypted secrets file. | | [`secrets.protection`](#secretsprotection) | `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`](#settingsget) | `settings:own` | worker, panel, editor | no | 1.0 | Reads every setting the plugin owns. | | [`settings.set`](#settingsset) | `settings:own` | worker, panel, editor | yes | 1.0 | Writes one setting the plugin owns. | | [`shell.openExternal`](#shellopenexternal) | 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`](#filessaveas) | 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`](#pluginrequest) | 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`](#agentslist) | `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`](#eventssubscribe) | 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`](#statusbarupdate) | 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. ```ts (params?: {}) => { branch: string; displayName: string; terminals: { id: string; title?: string }[] } | null ``` ### `terminal.sendText` Types text into one terminal named by id, optionally pressing Enter. ```ts (params: { terminalId: string; text: string; enter?: boolean }) => { accepted: boolean } ``` ### `notifications.show` Shows a desktop notification. ```ts (params: { title: string; body?: string }) => { delivered: boolean } ``` ### `storage.get` Reads a JSON value from the plugin's private store; null when absent. ```ts (params: { key: string }) => { value: JSON } ``` ### `storage.set` Writes a JSON value to the plugin's private store. ```ts (params: { key: string; value: JSON }) => { ok: true } ``` ### `storage.delete` Removes a key from the plugin's private store. ```ts (params: { key: string }) => { ok: true } ``` ### `storage.keys` Lists the keys in the plugin's private store. ```ts (params?: {}) => { keys: string[] } ``` ### `secrets.get` Reads a secret from the plugin's encrypted secrets file; null when absent. ```ts (params: { key: string }) => { value: string | null } ``` ### `secrets.set` Stores a secret in the plugin's encrypted secrets file. ```ts (params: { key: string; value: string }) => { ok: true } ``` ### `secrets.delete` Removes a secret from the plugin's encrypted secrets file. ```ts (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. ```ts (params?: {}) => { status: "os-keyring" | "unavailable" } ``` ### `settings.get` Reads every setting the plugin owns. ```ts (params?: {}) => { settings: Record } ``` ### `settings.set` Writes one setting the plugin owns. ```ts (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. ```ts (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. ```ts (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. ```ts (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. ```ts (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. ```ts (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. ```ts (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](./plugin-authoring.md#stability) 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`.