Host Command API Reference
The extension host command dispatcher exposes platform commands through window.isaExtensionBridge.invoke(command, args). Browser helpers may wrap these commands, but extensions can always call the canonical command names directly.
Capability Discovery
Use get_app_info to discover the surfaces enabled for the extension.
js
const appInfo = await window.isaExtensionBridge.invoke('get_app_info', {});
console.log(appInfo.filesystem.commands);
console.log(appInfo.projects);
console.log(appInfo.audioCapture);
console.log(appInfo.transcription);Do not infer capability support from the host version or from a manifest alone. Check enabled and the advertised command before showing an action.
This reference spans native and browser host adapters. A command listed below is not necessarily enabled in the browser gateway. The current verified launch's command arrays, manifest permissions, resource authorization and executor health remain authoritative.
Browser storage_* holds origin/account/extension-scoped JSON drafts independently of the chat-store lock. Browser filesystem capabilities report filesystem.persistence.mode = "dashboard-confirmed", offlineWrites = false, and authoritativeWrites only when upload is advertised. Atomic JSON capabilities report read and write separately. Browser uploads, deletes and atomic writes require dashboard acknowledgment, including for files whose server metadata is syncable. The native offline journal and indexed-cache events described below do not apply to the browser. Check implementation status for staged gateways and outstanding live verification.
The Filesystem API exposes workspace-file identity only as returned fileId metadata, always uses path for canonical filesystem selectors, and does not accept legacy storage-id aliases. Check the advertised command list for supported operations.
The public filesystem command list is:
filesystem_ensure_group_folderfilesystem_open_workspace_filefilesystem_open_workspace_folderfilesystem_list_dirfilesystem_get_filesfilesystem_query_indexfilesystem_upload_filesfilesystem_delete_filefilesystem_discard_pending_filefilesystem_get_download_link_file
The public shared-project command list is:
projects_listprojects_createprojects_set_archived
The atomic JSON command list is:
atomic_json_getatomic_json_apply
Implemented Host Commands
Common non-filesystem commands include:
get_app_infoget_extension_infoget_native_capabilitiesget_settingsset_settingsopen_file_dialogget_thread_listlist_extension_threadsget_full_thread_objectnew_threadcreate_extension_threadset_extension_thread_attachmentupdate_threadstorage_putstorage_getstorage_deletestorage_listprojects_listprojects_createprojects_set_archivedatomic_json_getatomic_json_applyupsert_document_snapshotsend_emailmcp_list_resourcesmcp_invoke_toolcalculatorweb_searchextract_webpage_textbrowse_and_extractdocuments_in_conversationsearch_documentsread_document
Atomic JSON workspace files
Atomic JSON commands provide operation-based updates to any valid JSON workspace file covered by the extension's ordinary exact-file or folder grant. The extension must declare atomic_json_read or atomic_json_write; the host supplies and enforces the immutable workspace, group, and extension scope. The target is an absolute canonical path, and traversal or access outside the granted scope is rejected.
atomic_json_get is the typed companion to atomic_json_apply. For a syncable target it materializes the strictly committed RIBLT copy plus all durable unacknowledged operations without using generic pending whole-file bytes. For a non-syncable target it reads the dashboard immediately. Its result distinguishes found, absent, and unavailable; malformed JSON is an error rather than absence. Any valid JSON root is accepted, including objects, arrays, scalars, and null. When pending is true, value includes the local operation overlay while revision, hash, and byte size still describe the committed generation.
atomic_json_apply accepts the same canonical target plus ordered operations. The optional boolean syncable is only a creation hint: exact true opts a missing file into durable local/RIBLT synchronization, while omission or false creates dashboard-first. An existing file always retains its authoritative persisted mode, even when the hint differs. Non-syncable applies succeed only after dashboard acceptance; a provisioned syncable target, or a missing target requested with exact true, can be saved durably while offline. Operation paths are arrays of literal object-key segments, so dots and slashes inside one key are not separators.
json
{
"path": "/groups/_group_ids/.../extensions/isa-match-rsx-to-quote/suppliers/enrichments.json",
"syncable": true,
"operations": [
{ "kind": "upsert", "path": ["supplier.example/id"], "value": { "rating": 4 } },
{ "kind": "remove", "path": ["supplier-456"] }
]
}For syncable files the host journals only unacknowledged operations, retries immutable batches through the ordinary file-sync worker, and emits scoped filesystem-index-changed events when pending or committed materialization changes. Dashboard acknowledgment durably removes the acknowledged batch immediately; until a later RIBLT generation arrives, a read can expose an older committed value or report unavailable with no accepted-operation overlay. There is no atomic tombstone or incarnation barrier: deletion removes the ordinary file, a later accepted apply recreates from {}, operations apply to the valid JSON present when they arrive, and the last dashboard write to arrive wins. The resulting JSON remains visible, downloadable, and manageable through normal dashboard file inventory.
Filesystem Authorization
Dashboard group links decide what a user can see in a workspace. Extension filesystem access is narrower and local to the running user profile.
filesystem_ensure_group_foldercreates or finds extension-owned storage for the selected launch group.filesystem_open_workspace_fileandfilesystem_open_workspace_folderrequire explicit user selection and persist a local grant.- Grants are scoped by extension id, workspace id, and launch group.
readgrants allow listing, reading, sync-index inspection, and signed download links.read_writegrants also allow upload, replacement, and delete.- A read-only grant must reject upload, replacement, and delete.
- The selected workspace and group are captured when the iframe starts and stay immutable until that iframe is deliberately reloaded.
- The host overwrites
workspaceIdandgroupIdon everyfilesystem_*request. Extension-supplied scope cannot retarget a mounted extension. - Delayed responses from a previous iframe generation are discarded.
get_app_info().extensionRuntime.launchContextId is the stable serialized identity of (workspaceId, groupId) and may key durable context-local recovery state. It does not change merely because the iframe reloads. The host's per-iframe generation token is separate and is not exposed to extensions.
filesystem_ensure_group_folder
Creates or finds the extension's group folder. The command must fail clearly if the extension was launched without a selected group.
Request:
json
{}Response:
json
{
"status": "ok",
"folderId": "workspace_file:...",
"path": "/groups/id-67726f75702d616c706861/extensions/id-7273782d62657374656b616e616c79736572",
}The host supplies the trusted workspace, group, and extension IDs to one atomic dashboard operation. Folder identity is link-backed and stable across group renames; the returned persisted path must be retained and must not be rebuilt from the display name. Concurrent ensure calls converge on the same real folder row. Structurally ambiguous legacy links fail closed with identifiers for administrator diagnosis.
filesystem_open_workspace_file
Opens a workspace-file picker and persists a local file grant if the user confirms.
Request:
json
{
"workspaceId": "workspace:...",
"access": "read",
"mode": "file"
}Response:
json
{
"status": "ok",
"fileId": "workspace_file:...",
"path": "/models/model.gguf",
"name": "model.gguf",
"kind": "file",
"access": "read"
}Cancellation returns a documented canceled result or rejects consistently, depending on the host implementation.
filesystem_open_workspace_folder
Opens a workspace-folder picker and persists a local folder grant.
Request:
json
{
"workspaceId": "workspace:...",
"access": "read_write",
"mode": "folder"
}Response:
json
{
"status": "ok",
"folderId": "workspace_file:...",
"path": "/project-inputs",
"name": "project-inputs",
"kind": "folder",
"access": "read_write"
}filesystem_list_dir
Lists files below one granted folder or extension group-folder path. Dashboard inventory and locally available syncable files share one response. Pending or otherwise locally newer syncable metadata replaces a dashboard entry at the same canonical path.
Request:
json
{
"path": "/groups/id-67726f75702d616c706861/extensions/id-7273782d62657374656b616e616c79736572"
"recursive": false
}Response:
json
{
"status": "ok",
"source": "dashboard+cache",
"authoritative": true,
"files": [
{
"path": "/groups/id-67726f75702d616c706861/extensions/id-7273782d62657374656b616e616c79736572/state.json",
"name": "state.json",
"kind": "file",
"fileId": "workspace_file:...",
"contentType": "application/json",
"fileSize": 1234,
"canRead": true,
"canWrite": true,
"availabilityStatus": "online",
"synced": true,
"lastSyncedAt": null
}
]
}Use exactly one of path or pathPrefix. recursive defaults to true; set it to false for direct children only. When the dashboard is unavailable, a non-empty local sync inventory is returned with source: "cache" and authoritative: false.
filesystem_get_files
Reads one or a bounded batch of granted files by canonical path. File IDs are returned as record-identity metadata but are not accepted as content-read selectors. The default local-first policy reads a complete clean synced cache entry for each syncable file, then retrieves only unresolved items from the dashboard. Use cachePolicy: "dashboard-required" when a canonical dashboard read is necessary before a CAS write, canonical application, or an authoritative absence decision.
Each request item selects exactly one canonical path. File IDs, duplicate paths, paths outside the extension's immutable granted root, unsupported encodings, and oversized requests are rejected. expectedSyncRevision and expectedContentHash are optional preconditions. A missing, incomplete, pending, corrupt, or mismatched cache entry causes a dashboard retrieval unless the policy prohibits it; it is never proof of remote absence.
Request:
json
{
"workspaceId": "workspace-alpha",
"files": [
{
"path": "/groups/id-67726f75702d616c706861/extensions/id-7273782d62657374656b616e616c79736572/enrichment/acme.json",
"expectedSyncRevision": "42",
"expectedContentHash": "4d14...64-hex-sha-256...b2"
}
]
}The response includes bounded items. Each item has path, status, and optional error; a successful item additionally returns text and coupled sync revision/content-hash metadata. An unsuccessful item does not fail unrelated items.
Response:
json
{
"status": "ok",
"items": [
{
"status": "ok",
"path": "/groups/id-67726f75702d616c706861/extensions/id-7273782d62657374656b616e616c79736572/state.json",
"fileId": "workspace_file:...",
"filename": "state.json",
"contentType": "application/json",
"fileSize": 1234,
"text": "{\"status\":\"complete\"}",
"bytesBase64": null
}
]
}filesystem_upload_files
Uploads one or more files to granted paths. This is the only upload command: uploading one file means sending a one-item files list. Each item's path includes its final filename, and each item independently selects dashboard-first behavior or the local sync queue through metadata.syncable.
Request:
json
{
"files": [
{
"path": "/groups/id-67726f75702d616c706861/extensions/id-7273782d62657374656b616e616c79736572/state.json",
"text": "{\"status\":\"complete\"}",
"contentType": "application/json",
"metadata": { "syncable": "true" },
"progressId": "upload-1"
}
]
}For idempotent online writes, metadata.client_operation_id may contain a stable lowercase or uppercase 64-hex operation identity. Retrying the same logical operation must reuse the exact path, content, and operation identity; the host forwards the value unchanged and the dashboard rejects reuse for a different request.
Progress event:
json
{
"event": "filesystem-upload-progress",
"extensionId": "rsx-bestekanalyser",
"workspaceId": "workspace-alpha",
"groupId": "group-alpha",
"progressId": "upload-1",
"filename": "state.json",
"bytesReceived": 12345,
"totalBytes": 50000,
"progress": 24.69,
"status": "uploading",
"isComplete": false
}An offline pending upload has the same shape but may return "fileId": null until the dashboard creates or resolves the real workspace-file row. fileId is never a backing object-storage ID and a path is never substituted as an ID.
Response:
json
{
"status": "ok",
"items": [
{
"status": "ok",
"path": "/groups/id-67726f75702d616c706861/extensions/id-7273782d62657374656b616e616c79736572/state.json",
"fileId": "workspace_file:...",
"filename": "state.json"
}
]
}filesystem_delete_file
Deletes a granted file or folder by canonical path. File IDs are rejected as request selectors, and read-only grants reject this command.
Optional request fields are recursive, expectedSyncRevision, and expectedContentHash. Recursive deletion requires a path and cannot delete the root of a persisted folder grant.
filesystem_discard_pending_file
Discards a conflicted local pending version by path. The extension, workspace, launch group, grant, and path must all match. The host returns either restored_committed_cache or removed_pending_cache.
filesystem_get_download_link_file
Creates a signed download URL for a granted file by canonical path. File IDs and legacy artifact-ID aliases are rejected as request selectors. A successful authoritative response may include fileId as record identity metadata. Syncable files do not require this operation: filesystem_get_files reads their complete local content directly when available.
Syncable Files
Set metadata.syncable = "true" for small files that should participate in the host sync queue. The host owns local caching, offline queueing, group-wide download, and conflict state. Extensions should not implement a second sync queue for these files.
The value must be the exact string "true". After the extension group folder and its read-write grant have been provisioned online, a syncable upload is first committed to the local synced-file store. A successful pending/local response means those bytes are durable and immediately available to offline filesystem_get_files and filesystem_list_dir calls, including after an app restart; it does not mean that the dashboard has accepted them yet. The host wakes its sync worker and uploads after reconnect. Pending state clears only after a reconciliation confirms the matching remote revision and hash.
The same contract applies to text, bytesBase64, and the snapshotted bytes from filePath, including empty content. Repeated local saves use the newest complete bytes. A conflict retains those bytes for resolution and is not silently retried. Invalid paths, missing authentication, read-only or revoked grants, and group-scope mismatches fail without creating a pending entry.
Creating the extension group folder and its initial grant remains online-only. Once provisioned, both replacements and new filenames below that folder can be queued offline. Uploads without the exact opt-in remain online-only.
The extension does not request or follow a dashboard download link for syncable files. filesystem_get_files reads complete local sync content first and the host obtains remote bytes only for unresolved items.
Shared Project Commands
These commands use the active launch group. Listing and creation require a dashboard advertising shared-projects-v1; archive and restore additionally require shared-projects-archive-v1. The host overwrites workspaceId and groupId; extensions cannot select another scope.
get_app_info().projects includes enabled, canRead, canWrite, and the available commands. projects_read enables projects_list; projects_write enables projects_create and projects_set_archived. Check the advertised command before rendering an archive or restore action.
projects_list
The extension sends no scope fields. includeArchived is optional and defaults to false:
js
const result = await window.isaExtensionBridge.invoke('projects_list', {});
const withArchive = await window.isaExtensionBridge.invoke('projects_list', {
includeArchived: true
});Response:
json
{
"status": "ok",
"projects": [
{
"id": "shared-projects-project-...",
"name": "Renovatie West",
"createdAt": "2026-07-22T19:00:00Z",
"updatedAt": "2026-07-22T19:00:00Z",
"canWrite": true,
"archived": false,
"archivedAt": null
}
]
}Results are sorted by most recent updatedAt, then name and id. Timestamps are RFC 3339/ISO-8601 strings. The default response omits archived projects; includeArchived: true returns active and archived projects so clients can offer restore without mistaking an archived id for a deleted or unknown project. archivedAt is null for an active project. canWrite is false when the extension lacks projects_write; it permits the dedicated project write commands and association of extension-owned data, but never raw mutation of the registry folder through the filesystem API.
projects_create
Request:
json
{
"name": "Renovatie West"
}Response:
json
{
"status": "ok",
"created": true,
"project": {
"id": "shared-projects-project-...",
"name": "Renovatie West",
"createdAt": "2026-07-22T19:00:00Z",
"updatedAt": "2026-07-22T19:00:00Z",
"canWrite": true,
"archived": false,
"archivedAt": null
}
}The name is trimmed, case-sensitive, and limited to 160 characters and 512 UTF-8 bytes. Empty names, traversal segments, separators, and control characters are rejected. Repeating the same canonical create returns the same project with created: false; no duplicate folder is made. A group supports at most 500 projects, including archived entries. Creating with the name of an archived project returns that same archived identity; use projects_set_archived to restore it explicitly.
projects_set_archived
This soft-archives or restores a project without deleting its registry identity or any extension-owned data.
Archive request:
json
{
"projectId": "shared-projects-project-...",
"archived": true
}Response:
json
{
"status": "ok",
"changed": true,
"project": {
"id": "shared-projects-project-...",
"name": "Renovatie West",
"createdAt": "2026-07-22T19:00:00Z",
"updatedAt": "2026-07-23T09:00:00Z",
"canWrite": true,
"archived": true,
"archivedAt": "2026-07-23T09:00:00Z"
}
}Restore the project by sending the same projectId with archived: false. Both transitions are idempotent: requesting the current state returns changed: false. The project id, name, parent, and canonical path remain unchanged. Files and records stored by extensions under their own group folders are not moved or removed.
The project id is a stable foreign key shared by extensions. Project registry folders are system-owned, read-only metadata and cannot be used as raw extension storage. Persist extension-owned files under the extension's group folder and include the project id in their schema or metadata.
Audio Capture Commands
These commands require audio_capture and a frozen workspace/group context:
audio_list_input_devicesaudio_get_active_recordingaudio_get_recordingaudio_list_recordingsaudio_start_recordingaudio_pause_recordingaudio_resume_recordingaudio_stop_recordingaudio_cancel_recordingaudio_delete_recording
The browser bridge supplies the frozen workspaceId, groupId, and extensionId; iframe arguments for those fields are discarded. The extension only supplies the fields shown below.
audio_list_input_devices returns:
json
[
{
"deviceId": "opaque-device-id",
"label": "Built-in Microphone",
"isDefault": true
}
]Start request:
json
{
"deviceId": "opaque-device-id",
"maxDurationMs": 14400000
}deviceId is optional and selects the host default when omitted. maxDurationMs is optional and is capped by the host. The response is an audio recording state:
json
{
"recordingId": "recording-...",
"status": "recording",
"device": {
"deviceId": "opaque-device-id",
"label": "Built-in Microphone",
"isDefault": true
},
"startedAt": "2026-07-22T19:00:00Z",
"updatedAt": "2026-07-22T19:00:02Z",
"durationMs": 2000,
"bytesWritten": 64000,
"mimeType": "audio/wav",
"sampleRateHz": 48000,
"channels": 1,
"peakLevel": 0.42,
"recovered": false,
"expiresAt": "2026-07-23T19:00:00Z",
"canPause": true,
"canResume": false,
"canStop": true,
"canCancel": true,
"errorCode": null,
"errorMessage": null
}Recording statuses are starting, recording, paused, stopped, cancelled, and failed. All recording-specific commands use { "recordingId": "..." }:
audio_get_recording,audio_pause_recording,audio_resume_recording,audio_stop_recording, andaudio_cancel_recordingreturn recording state.audio_get_active_recordingreturns the scoped active state ornull.audio_list_recordingsreturns all recording states in the launch scope.audio_delete_recordingreturns{ "recordingId": "...", "deleted": true }. An active recording must first be stopped or cancelled, and a recording leased by a transcription job cannot be deleted yet.
The response never includes audio bytes or a local path. Only one recording can be active in the app. A global host control remains available if the extension iframe is minimized. State changes arrive through audio-capture-state-changed; its payload contains sequence, the scoped IDs, and the latest state object.
Transcription Commands
These commands require transcribe_audio:
transcription_list_providerstranscription_starttranscription_gettranscription_canceltranscription_delete
transcription_list_providers returns only speech-to-text models linked to the exact launch group. Provider credentials and local model paths are removed:
json
[
{
"id": "model:...",
"name": "ggerganov/whisper.cpp · ggml-small",
"providerKind": "localWhisper",
"location": "local",
"modelType": "speechToText",
"supportsSpeakerLabels": false
}
]providerKind is localWhisper or openAiCompatible. A listed local provider is authorized for the group, but its model asset may still be downloading or not yet downloaded. supportsSpeakerLabels describes that exact model configuration; it is not implied by providerKind.
Start request:
json
{
"recordingId": "opaque-recording-id",
"modelId": "model:...",
"language": "nl",
"prompt": "Optional vocabulary hint"
}recordingId and modelId are required. Empty optional values are removed; language is limited to 32 characters and prompt to 16,000 characters. The recording must be stopped and belong to the same extension, workspace, and group.
Start response:
json
{
"jobId": "transcription-...",
"status": "queued"
}Persist jobId immediately. There is no command that lists transcription jobs, so it is required to recover state after the extension iframe is remounted.
Local model download handshake
The first transcription_start for a local provider also verifies the model asset. When the host starts downloading it, the bridge rejects before creating a job with the plain error message transcription_model_downloading. Keep the recording, show a waiting state, and retry that same request after a short delay. There is currently no public download-progress event.
transcription_model_not_downloaded means the host could not establish a downloaded or downloadable model and should be surfaced as a terminal setup problem. transcription_model_unavailable means the model is no longer present in the frozen launch group's resources. Refresh the provider list after group or dashboard changes and when the extension becomes visible again.
Remote provider consent
An OpenAI-compatible provider opens a host confirmation for every start. If the user declines, the bridge rejects with external_transcription_cancelled and no job is created. Consent fields, provider endpoints, and API keys sent by an iframe are ignored. The host resolves credentials and binds its single-use consent token to the exact extension, scope, recording, and model.
Speaker-aware remote providers
Provider request behavior is host-owned. An extension selects an authorized modelId; it cannot inject a response format, chunking mode, endpoint, or provider-specific multipart field into transcription_start.
An OpenAI-compatible speech-to-text model can be configured by a workspace administrator with:
json
{
"transcription": {
"responseFormat": "diarized_json",
"chunkingStrategy": "auto"
}
}The host then advertises supportsSpeakerLabels: true for that provider, asks for diarized output, and preserves each returned opaque speaker key on segments[].speaker. Extensions may display or explicitly map those keys, but must not infer a real identity from a label such as A.
When the host must divide one recording into independent provider uploads, it scopes returned speaker keys to their upload part before merging results. Provider-local labels are not assumed to identify the same person across separate uploads.
Query, cancel, and delete
All job commands use { "jobId": "transcription-..." }. transcription_get returns:
json
{
"job": {
"id": "transcription-...",
"sourceId": "recording-...",
"modelId": "model:...",
"providerKind": "localWhisper",
"status": "completed",
"phase": "completed",
"progressPct": 100,
"segmentCount": 1,
"requestedLanguage": "nl",
"detectedLanguage": "nl",
"errorCode": null,
"errorMessage": null,
"createdAt": "2026-07-22T19:01:00Z",
"updatedAt": "2026-07-22T19:01:08Z",
"completedAt": "2026-07-22T19:01:08Z"
},
"result": {
"id": "transcription-result-...",
"jobId": "transcription-...",
"sourceId": "recording-...",
"modelId": "model:...",
"providerKind": "localWhisper",
"text": "Welkom bij de vergadering.",
"language": "nl",
"durationMs": 8000,
"segments": [
{
"index": 0,
"startMs": 0,
"endMs": 8000,
"text": "Welkom bij de vergadering.",
"speaker": null,
"confidence": null
}
],
"createdAt": "2026-07-22T19:01:08Z"
}
}Job statuses are queued, running, completed, failed, cancelled, and interrupted. Phases are queued, openingRecording, preparingModel, transcribing, finalizing, completed, failed, and cancelled. A result is null until the job completes.
transcription_cancel is idempotent for terminal jobs and returns the job. transcription_delete accepts terminal jobs only and returns { "deleted": true, "jobId": "..." }. Cancel a running job before deleting it.
Transcription events and errors
The four browser events are transcription-progress, transcription-segment, transcription-completed, and transcription-failed. Their common payload is:
json
{
"extensionId": "meeting-warden",
"workspaceId": "workspace:...",
"groupId": "group:...",
"jobId": "transcription-...",
"status": "running",
"phase": "transcribing",
"progressPct": 45,
"segmentCount": 1,
"errorCode": null,
"errorMessage": null,
"segment": null
}Only transcription-segment carries a segment. Treat events as hints: an iframe can miss them while minimized, closed, or remounted, so reconcile each relevant event and restored jobId with transcription_get. Failed job views and events include a host-safe errorMessage in addition to the stable errorCode.
Host-command failures serialize { "code", "message", "retryable" } using snake_case codes. The current codes are cancelled, external_consent_required, group_required, internal, invalid_request, invalid_state, model_download_required, model_not_available, permission_denied, provider_error, provider_unavailable, scope_mismatch, source_not_found, and unsupported_audio.
The serialized object is normally carried inside the bridge Error.message. Bridge preflight failures described above are plain message sentinels, so robust code should normalize the message and must not assume every rejection has an error.code field.