SDK API

Import sdk from the dedicated runtime entry point:

import { sdk } from '@theaiplatform/miniapp-sdk/sdk';

The sdk export is a lazy MiniAppPlatformApi. Importing it is safe in tests and build tools. Reading any property before The AI Platform installs the capability session throws an unsupported-environment error, so keep host access at a target or surface boundary.

Every host operation can cross a process or network boundary. Always await its result even when the type also permits a synchronous value through MiniAppMaybePromise.

Declare Permissions

Every authority-bearing host method must be declared before installation. Add each action ID you use to a permission.catalog, include it in a package level, and bind it from the calling contribution. Use authorization.allOf only when the action is required to project the contribution. Use authorization.onDemand when the contribution may mount without the action and checks it at the point of use. The autonomy value below is the minimum ceiling required by that method. Declarations are requests, not grants: installation review and current workspace policy decide whether a call is allowed, and a later revocation makes the operation reject. Metadata-only capability discovery, including sdk.terminal.v1.getCapabilities, does not require a persisted action.

Public methodPermission action IDRequired autonomy
sdk.channels.createchannels.createdo
sdk.channels.listchannels.listlisten
sdk.channels.sendMessagechannels.send-messagedo
sdk.channels.getAccesschannels.readlisten
sdk.channels.getTimelinechannels.readlisten
sdk.projects.createprojects.createdo
sdk.projects.getprojects.readlisten
sdk.projects.updateprojects.updatedo
sdk.workflows.listworkflows.listlisten
sdk.workflows.invokeSavedworkflows.invokedo
sdk.workflows.invokeworkflows.invokedo
sdk.navigation.opennavigation.opendo
sdk.navigation.openExternalnavigation.open-externaldo
sdk.navigation.subscribeDeepLinksnone — package-scoped deliveryn/a
sdk.chat.sendTextToChatchat.composedo
sdk.chat.stageDeepLinkchat.composedo
sdk.chat.stageDeepLinkWithRollbackchat.composedo
sdk.chat.unstageDeepLinkchat.composedo
sdk.chat.archiveConversationchannels.archivedo
sdk.auth.getUserProfileprofile.readlisten
sdk.vfs.provisionProjectChatvfs.provision-project-chatdo
sdk.vfs.writeFilevfs.writedo
sdk.vfs.writeFilesvfs.writedo
sdk.vfs.mkdirvfs.writedo
sdk.vfs.readFilevfs.readlisten
sdk.vfs.statvfs.readlisten
sdk.vfs.listvfs.readlisten
sdk.git.resolveRuntimegit.readlisten
sdk.git.snapshotgit.readlisten
sdk.git.changesgit.readlisten
sdk.git.diffgit.readlisten
sdk.git.pullRequestsgit.readlisten
sdk.git.worktreesgit.readlisten
sdk.git.subscribegit.readlisten
sdk.git.initializeRepositorygit.writedo
sdk.git.stagegit.writedo
sdk.git.approveStagegit.writedo
sdk.git.commitgit.writedo
sdk.git.createBranchgit.writedo
sdk.git.renameBranchgit.writedo
sdk.git.pushgit.publishdo
sdk.git.openPullRequestgit.publishdo
sdk.snapshot.statussnapshot.readlisten
sdk.snapshot.historysnapshot.readlisten
sdk.snapshot.subscribesnapshot.readlisten
sdk.snapshot.undosnapshot.undodo
sdk.files.pickOpenfiles.pick-opendo
sdk.files.pickOpen requesting recoveryfiles.retain-handledo
sdk.files.pickSavefiles.pick-savedo
sdk.files.pickSave requesting recoveryfiles.retain-handledo
sdk.files.metadatafiles.readlisten
sdk.files.readfiles.readlisten
sdk.files.readRangefiles.readlisten
sdk.files.createReadStreamfiles.readlisten
sdk.files.write after pickSavefiles.pick-savedo
sdk.files.write after pickOpenfiles.overwritedo
sdk.files.createWriteStream after pickSavefiles.pick-savedo
sdk.files.createWriteStream after pickOpenfiles.overwritedo
sdk.files.renamefiles.renamedo
sdk.files.deletefiles.deletedo
sdk.files.watchfiles.watchlisten
sdk.files.recoverfiles.retain-handledo
sdk.files.revokenone — revocation onlyn/a
sdk.inference.listModelsinference.listlisten
sdk.inference.sendinference.invokedo
sdk.embeddings.listModelsembeddings.models.readlisten
sdk.embeddings.recommendembeddings.models.readlisten
sdk.embeddings.embedembeddings.computedo
sdk.storage.profile.open file readsstorage.profile.files.readlisten
sdk.storage.profile.open file writesstorage.profile.files.writedo
sdk.storage.profile.open SQLite accessstorage.profile.sqlitedo
sdk.storage.profile.open zvec accessstorage.profile.zvecdo
sdk.storage.workspace.open file readsstorage.workspace.files.readlisten
sdk.storage.workspace.open file writesstorage.workspace.files.writedo
sdk.storage.workspace.open SQLite accessstorage.workspace.sqlitedo
sdk.storage.workspace.open zvec accessstorage.workspace.zvecdo
sdk.specialist.joinToChannelchannels.manage-specialistsdo
sdk.specialist.prepareChannelchannels.manage-specialistsdo
sdk.specialist.listWorkspacespecialists.listlisten
sdk.specialist.createspecialists.createdo
sdk.specialist.upsertManagedspecialists.managedo
sdk.specialist.runTurnWithToolsspecialists.invokedo
sdk.specialist.streamTurnWithToolsspecialists.invokedo
sdk.http.requestnetwork.requestdo
sdk.http.request with a credentialcredentials.usedo
sdk.credentials.listHttpcredentials.readlisten
sdk.session.getsession.managelisten
sdk.session.setsession.managedo
sdk.session.clearsession.managedo
sdk.printing.listPrintersprinting.receiptlisten
sdk.printing.getStatusprinting.receiptlisten
sdk.printing.submitprinting.receiptdo
sdk.notifications.shownotifications.showdo
sdk.terminal.v1.openterminal.session.opendo
sdk.terminal.v1.open with VFS read accessfilesystem.readdo
sdk.terminal.v1.open with VFS write accessfilesystem.writedo
openEditorProjecteditor.opendo
sdk.workflows.getRunworkflows.readlisten
sdk.codeIntel.getIndexStatuscode-intel.readlisten
sdk.codeIntel.searchcode-intel.readlisten
sdk.codeIntel.listCommunitiescode-intel.readlisten
sdk.codeIntel.getCommunitycode-intel.readlisten
sdk.codeIntel.listProcessescode-intel.readlisten
sdk.codeIntel.getProcesscode-intel.readlisten
sdk.codeIntel.getBranchDiffcode-intel.readlisten
sdk.codeIntel.getImpactAnalysiscode-intel.readlisten
sdk.codeIntel.getCoveragecode-intel.readlisten
sdk.codeIntel.getFragilitycode-intel.readlisten
sdk.codeIntel.getHistorycode-intel.readlisten
sdk.codeIntel.getSpecialistAffinitiescode-intel.readlisten
sdk.trr.getAggregatetrr.readlisten
sdk.trr.getMdTrrtrr.readlisten
sdk.trr.getEcrttrr.read-costlisten
sdk.trr.getDeathCausestrr.readlisten
sdk.trr.getRelationMixtrr.readlisten
sdk.trr.getSurvivalCountstrr.readlisten
sdk.trr.runSweeptrr.sweepdo
sdk.workspace.listTeamsworkspace.readlisten
sdk.workspace.listProjectsworkspace.readlisten
sdk.workspace.currentworkspace.readlisten
sdk.workspace.listMembersworkspace.read-memberslisten
sdk.user.currentnone — see belown/a
sdk.tasks.createtask.writedo
sdk.tasks.createWithReceipttask.writedo
sdk.tasks.updatetask.writedo
sdk.tasks.deletetask.writedo
sdk.tasks.listtask.readlisten
sdk.artifacts.resolveartifacts.readlisten

Every package built with SDK 0.12 or later requires compatibility.tapHost to exclude versions before 2.4.1. This package-wide floor covers packages that use only pre-existing APIs as well as packages that use SDK 0.12 workspace storage, embedding, batch VFS, or batch specialist actions.

SDK 0.13 packages require compatibility.tapHost to exclude versions before 2.5.5. SDK 0.12 packages retain their historical 2.4.1 floor.

A package that declares user-file authority must set compatibility.tapSdk to exclude versions before 0.14.0 and compatibility.tapHost to exclude versions before 2.9.0.

A package that declares an action.command must set compatibility.tapSdk to exclude versions before 0.15.0 and compatibility.tapHost to exclude versions before 2.9.0.

The browser-only openEditorProject helper appears in the table because it requests a host action even though it is imported from /web. Theme helpers, type exports, getPlatform, and capability-flag checks do not request a host action and therefore need no permission action.

sdk.storage, sdk.session, sdk.presence, sdk.http, sdk.credentials, sdk.notifications, sdk.printing, sdk.files, and sdk.terminal.v1.open use descriptor effects in addition to the calling contribution's ordinary permission binding. Declare a storage or presence effect whose resources contains each namespace the contribution uses. HTTP requires an external-network effect for each exact URL origin, such as https://api.vanta.com. Credential listing or use also requires { "kind": "credentials", "resources": ["http"] }. Secure installation sessions require { "kind": "credentials", "resources": ["package-session"] }. Receipt-printer discovery, status, and submission require { "kind": "physical-output", "resources": ["receipt-printer"] }. OS notifications require { "kind": "user-notification", "resources": ["os"] }. Terminal open requires a terminal effect whose resource is the exact selected profile (workspace-shell or neovim) and { "kind": "filesystem-mount", "resources": ["conversation-vfs:read-write"] }. User-selected file access requires exactly one user-file effect whose resources match the declared file actions: pick-open, pick-save, read, overwrite, rename, delete, watch, or retain-handle. Declare every file action exactly once in the desktop UI surface's authorization.onDemand; user-file authority is invalid in authorization.allOf, on a non-UI contribution, or on a non-desktop target. Declare printing.receipt at the consuming package level as a reusable, do, consequential action; listPrinters and getStatus consume listen authority while submit consumes do authority. Wildcards do not match an origin. The host derives workspace, package, instance, document, and participant identity from the verified frame; none of those are caller inputs.

The quickstart shows a complete catalog, level, role recommendation, and surface binding for channels.list. For a package that uses several methods, list each action once and bind only the actions needed by each contribution.

Use sdk.authorization.check to adapt the surface before a declared action is invoked. Pass the action ID bound to the exact mounted contribution and the autonomy needed by the planned operation. The returned decision is only a snapshot: keep handling rejection from the operation because policy or authority can change immediately afterward.

const access = await sdk.authorization.check({
  actionId: 'channels.create',
  autonomy: 'do',
});

createChannelButton.disabled = !access.allowed;

The check never executes the action, creates a grant, or prompts the human. For an ordinary production miniapp surface, a matching persisted grant can authorize actions whose consent is none, channel in the exact channel, or reusable. Actions declared with once or fresh-decision deliberately resolve to { allowed: false }, even when installation state retains a grant row: those policies require a call-bound consent attestation, and the public surface SDK does not currently expose a consent request API that can mint one. Calling the protected SDK operation does not prompt for that permission either.

Do not weaken a consequential action to reusable consent just to make this check pass. Keep the production control unavailable with an explanation until a supported host-mediated flow exists. Use the positive fixture row in the Miniapp Test Lab to exercise the intended allowed journey, and a denied row to verify the fallback. Fixture authority validates miniapp behavior; it is not evidence that production call-bound consent is available. Undeclared action IDs reject instead of revealing authority held by another contribution.

Namespaced Storage

sdk.storage stores bounded, non-secret JSON under a package-controlled namespace and key. The host prepends the authenticated workspace and exact package identity, so two packages cannot address each other's data. get returns a value and optimistic revision; a missing entry returns both as null. Pass that exact revision to set or delete. Pass null only to create a missing key.

const address = { namespace: 'canvas', key: 'scene/main' };
const current = await sdk.storage.get(address);
const saved = await sdk.storage.set({
  ...address,
  expectedRevision: current.revision,
  value: { title: 'Launch plan', nodes: [] },
});
console.log(saved.revision);

Values are limited to plain finite JSON and five MiB. Secrets, credentials, binary assets, and signed URLs do not belong in this API. A revision conflict rejects; reload, merge, and retry instead of silently overwriting another realm's update.

Native Embeddings

sdk.embeddings exposes host-native local text embeddings without giving the miniapp model-file paths or native runtime handles. Discover the catalog before embedding: entries report whether a model is installed or downloadable, its exact revision, dimensions, roles, normalization, input limits, resource estimates when known, source, gating, and upstream license metadata. License metadata is informational; TAP does not accept or manage an upstream license on the miniapp's behalf.

recommend() ranks models for a requested modality and locality policy. The 0.12 desktop host supplies BAAI/bge-small-en-v1.5 for role-aware local text retrieval. Callers pass the discovered model ID and revision back to embed(); the result includes the full embedding-space binding that must be stored with a new zvec vector field. Model discovery and compute require separate granular permissions, and both are always brokered by the host SDK boundary. Catalog maxInputBytes is enforced independently for each input. Host-generated vectors also carry an opaque attestation over the route, exact binding, and complete numeric payload; preserve it when writing a host-verified vector.

const embeddings = sdk.embeddings;
if (!embeddings) throw new Error('Native embeddings are unavailable.');

const recommendations = await embeddings.recommend({
  modality: 'text',
  locality: 'local-only',
});
const selected = recommendations[0]?.model;
if (!selected) throw new Error('No compatible local model is available.');

const result = await embeddings.embed({
  model: selected.id,
  revision: selected.revision,
  inputs: [{ kind: 'text', text: 'Ada Lovelace' }],
  role: 'document',
});
console.log(result.binding, result.vectors[0]);

Private Storage

Desktop hosts expose two opaque scopes with the same files, SQLite, and native zvec APIs:

  • sdk.storage.workspace is bound to the host-stamped current workspace plus signed publisher/package identity.
  • sdk.storage.profile is bound to the current local app profile plus signed publisher/package identity and is shared across workspaces.

Neither scope accepts a workspace, profile, or physical path from package code. Other packages and publishers cannot address it. Storage is plaintext unless the miniapp encrypts its own values; provider credentials belong in the host credential system.

const privateStorage = sdk.storage.workspace;
if (!privateStorage)
  throw new Error('Workspace storage requires the desktop host.');
const workspace = await privateStorage.open();

await workspace.files.write(
  'imports/customers.csv',
  new TextEncoder().encode(csv),
);

const database = await workspace.sqlite.open('contacts');
await database.migrate([
  {
    version: 1,
    sql: 'CREATE TABLE contacts (id INTEGER PRIMARY KEY, name TEXT NOT NULL)',
  },
]);

const models = await sdk.embeddings?.listModels();
const model = models?.find(
  (candidate) => candidate.availability === 'installed',
);
if (!model || !sdk.embeddings)
  throw new Error('No local embedding model is installed.');
const embedded = await sdk.embeddings.embed({
  model: model.id,
  revision: model.revision,
  inputs: [{ kind: 'text', text: 'Ada Lovelace' }],
  role: 'document',
});

const search = await workspace.zvec.open('contact-search', {
  fields: [
    { name: 'name', dataType: 'STRING', index: { type: 'INVERT' } },
    {
      name: 'embedding',
      dataType: 'VECTOR_FP32',
      dimension: embedded.binding.dimensions,
      index: { type: 'HNSW', metric: 'COSINE' },
      binding: embedded.binding,
    },
  ],
});
await search.upsert([
  {
    pk: 'contact-1',
    fields: { name: 'Ada', embedding: embedded.vectors[0]! },
  },
]);
const matches = await search.query({
  fieldName: 'embedding',
  vector: embedded.vectors[0]!,
  topK: 10,
  filter: { op: 'eq', field: 'name', value: 'Ada' },
});

Declare only the granular access a contribution needs. All four actions for a scope can be granted together at installation. Read-only file callers can open with { filesRead: true, filesWrite: false, sqlite: false, zvec: false }. Profile and workspace routes have independent quotas and share a host-wide safety cap. The manifest may request profileStorageQuotaBytes and workspaceStorageQuotaBytes up to the host-controlled per-route ceiling.

File replacement, range writes, database commits, migrations, and checkpoints preserve the last complete snapshot. SQLite is parameterized and serialized across package surfaces. zvec uses its native on-disk format. Filters are a typed AST; arbitrary native filter strings are not accepted. Every new vector field pins an exact model revision and full embedding-space fingerprint. A write or query with another binding rejects even when dimensions match. A host-verified write also rejects if its vector payload or opaque attestation was altered. Collections created before SDK 0.12 remain valid as explicitly unbound legacy collections and are not rewritten.

Raw typed SQLite and zvec APIs remain available. reciprocalRankFusion is a pure SDK utility for combining their ranked results with optional weights.

Both scopes retain data by default across updates, disablement, uninstall, and reinstall. A package can instead set the matching profileStorageRetention or workspaceStorageRetention lifecycle value to delete-on-verified-revocation. Missing authority never triggers deletion. Post-revocation cleanup is durably queued and resumes after an I/O failure or restart. Installed Miniapp settings can clear profile data or data for the current workspace only.

Desktop Test Lab operates through the same opaque native capability and never reveals a physical path.

Package-runtime MCP context

Feature-detect sdk.mcp inside a package-runtime MCP tool. Its getExecutionContext() method returns host-stamped, call-scoped identity: userId is nullable, and channelId is nullable for workspace- or user-scoped execution. The host never fabricates a channel. A handler that selects channel-specific state must reject null before reading storage.

const context = sdk.mcp?.getExecutionContext();
if (!context) {
  throw new Error('This tool requires a package-runtime MCP execution.');
}
if (context.channelId === null) {
  throw new Error('This tool requires a trusted channel context.');
}

const state = await sdk.storage.get({
  namespace: 'brainrot-td',
  key: `channels/${context.channelId}/index`,
});

During this call, sdk.storage.get reads an immutable point-in-time snapshot. The host reloads the active verified descriptor, revalidates the exact server and tool, current consumer lease, declared permission actions, and persisted grants, then exposes only namespaces present in all three storage declarations: the mcp.server authorization effects, the mcp.tool authorization effects, and the tool's options.effects. A missing declaration contributes no namespace. Data declared only by a sibling tool is invisible, and missing keys still return { value: null, revision: null }.

Each invocation runs in a fresh, capability-minimal QuickJS realm, so module globals cannot carry storage values or identity into a sibling tool or later workspace call. The snapshot and identity are cleared after every success, rejection, deadline interruption, or non-settling promise. Snapshot values are recursively frozen. sdk.storage.set and sdk.storage.delete always reject in this realm; MCP handlers must use a separately authorized host workflow for mutations.

Secure Workspace Installation Session

sdk.session stores one small JSON session object in the operating system credential store. The host derives the active TAP account, active workspace, immutable installation ID, and canonical package ID. Channel, contribution, frame, document, and release are excluded, so standalone and channel surfaces of one installation share a login only when they belong to the same workspace, and package updates retain it. Another workspace gets a separate login. A reinstall gets a new installation ID and cannot recover the previous session.

const current = await sdk.session.get();
if (current.value === null) {
  await sdk.session.set({ email, token });
}

// Map partner sign-out to the complete installation session.
await sdk.session.clear();

The serialized value is limited to about two KiB for cross-platform credential store compatibility. get intentionally returns the value to package JavaScript; the keyring protects it only at rest. Do not put TAP's own bearer or another host-managed integration credential here. Use the opaque HTTP credential path instead. The descriptor must request credentials:package-session, and the package must declare the dedicated session.manage action. A stale release, switched account or workspace, revoked grant, missing effect, disabled installation, or uninstalled package fails closed.

Identity and Workspace

Three reads, three different authorities, because the answers expose different people.

const me = await sdk.user?.current();
// { userId: 'google-oauth2|…', displayName: 'Ada Lovelace' }

const here = await sdk.workspace?.current();
// { workspaceId: 'org_…', displayName: 'Acme Engineering' }

const { members } = (await sdk.workspace?.listMembers()) ?? { members: [] };
// [{ userId: 'google-oauth2|…', displayName: 'Ada Lovelace' }, …]

sdk.user.current() needs no permission and prompts for nothing. Your mount context already carries userId; the name attached to that id is not additional authority. displayName is host-derived and cannot be supplied by a package. It is empty when the profile has no usable name — a guest mount can do that — so render a fallback.

Both workspace reads require a persisted workspace.read action with listen autonomy, the same authority as listTeams and listProjects:

{
  "id": "workspace.read",
  "resource": "tap.workspace:read",
  "scopes": ["workspace"],
  "directActors": ["human"],
  "autonomyCeiling": "listen",
  "consent": "reusable",
  "risk": "read"
}

listMembers() returns joined members only. An invitation is not a teammate, and listing pending invites would reveal hiring before it is announced. Each member is a user id and a display name; the host's roster also holds email, role, title, timezone, invitation timestamps and who invited whom, and none of that crosses the boundary. The result contract is closed, so a field added upstream cannot begin flowing to packages without a deliberate change here.

Feature-detect all three — a host older than this capability does not install them — and treat a denial as "render without names" rather than an error. A withheld grant is a normal state.

There is no avatar in any of these. The generated surface CSP is img-src 'self' data:, so a remote image cannot load whatever the manifest declares; draw initials, or inline bytes from your own backend as a data: URI.

React callers should use useUser, useWorkspace, and useWorkspaceMembers instead of calling these directly, since render cannot await.

Presence

sdk.presence carries bounded ephemeral JSON in a host-scoped namespace and room. Call subscribe before join, refresh state with update, and call leave during explicit teardown. The host also removes a participant when its document or frame is retired.

const address = { namespace: 'canvas', room: 'scene/main' };
const unsubscribe = sdk.presence.subscribe(address, (snapshot) => {
  const collaborators = snapshot.participants.filter(
    (participant) => participant.participantId !== snapshot.selfParticipantId,
  );
  renderCollaborators(collaborators);
});

await sdk.presence.join({
  ...address,
  state: { cursor: { x: 120, y: 80 }, selection: ['node-1'] },
});

Participant IDs, display names, and timestamps are host-stamped. App state cannot replace them. Presence is not durable storage or a permission grant; participants expire after missed heartbeats and must be prepared to rejoin.

HTTP and credentials

Feature-detect sdk.http, sdk.credentials, and hasHostHttpRequest === true because non-desktop targets may omit these capabilities. sdk.http.request sends bounded HTTP(S) through the native transport, so it is not subject to the miniapp iframe's browser CORS path. The host validates the URL and limits, requires persisted package grants, and asks the signed-in human for origin consent. Credential-backed requests additionally revalidate the active workspace and user before resolving a secret. Use the reserved platform-session credential reference when the destination accepts the active TAP account bearer; the host obtains and injects that bearer after authorization without exposing it to miniapp JavaScript. It uses the same declared effect, package grant, and human origin consent as other host-managed credentials; the host does not maintain a separate destination list.

Surface Test Lab runs use the run-scoped exact-origin list instead of persisted interactive consent and never read the host credential vault. A Surface profile may explicitly expose metadata-only HTTP credential fixtures bound to selected run aliases; aliases without a declaration remain invisible, and no credential material enters the fixture. Those origins authorize host-mediated sdk.http.request; they are not a browser-wide network sandbox for Playwright test code.

if (!sdk.http || !sdk.credentials || sdk.hasHostHttpRequest !== true) {
  throw new Error('Host-mediated HTTP is unavailable in this target.');
}

const credentials = await sdk.credentials.listHttp();
const credential = credentials.find(
  (candidate) => candidate.credentialType === 'http_bearer',
);
if (!credential) throw new Error('Configure an HTTP bearer credential first.');

const response = await sdk.http.request(
  { method: 'GET', url: 'https://api.vanta.com/v1/controls' },
  { credentialRef: credential.id },
);

const tapResponse = await sdk.http.request(
  { method: 'GET', url: 'https://api.example.tap.dev/v1/profile' },
  { credentialRef: 'platform-session' },
);

listHttp returns IDs, types, display names, and non-secret metadata only. A miniapp cannot read credential values. The host injects the selected secret, redacts credential material from reflected response fields, suppresses binary bodies on credential-backed requests, and rejects destination conflicts. Request timeouts are capped at 120 seconds after consent; the SDK itself does not race the native human-decision prompt with a shorter client timeout.

OS Notifications

Feature-detect sdk.notifications because compatible desktop and mobile hosts provide it, while older and portable hosts can omit it. Package code supplies only a non-empty message of at most 512 Unicode scalar values. The host prefixes the message with the registered surface application name, owns all native presentation metadata, and never accepts a package-supplied title, subtitle, icon, urgency, sound, action, or deep link. Messages and registered attribution names reject Unicode control, format, line-separator, and paragraph-separator characters. The registered attribution name is limited to 128 Unicode scalar values and is validated before package installation.

const notifications = sdk.notifications;
if (notifications) {
  const result = await notifications.show({
    message: 'Export completed',
  });

  if (result.disposition === 'suppressed') {
    console.log(`Notification suppressed: ${result.reason}`);
  }
}

A shown notification is rendered as Design File Viewer: Export completed when the registered application name is Design File Viewer. The current user's display name is not used for this attribution.

show returns { disposition: 'shown' } when the native notification API accepts the notification. It returns suppressed with notifications-disabled, permission-denied, or rate-limited when the host does not present it. The host respects the user's The AI Platform notification preference and the current OS permission without prompting. Do not retry a suppressed call in a loop or ask the user for OS permission from package code. The host rate limit is scoped to the exact package installation and mounted document.

Declare the effect on each contribution that calls show:

{
  "authorization": {
    "onDemand": ["notifications.show"],
    "effects": [
      {
        "kind": "user-notification",
        "resources": ["os"]
      }
    ]
  }
}

Define the action in the package's permission catalog and include it in an assignable level:

{
  "id": "notifications.show",
  "resource": "os",
  "scopes": ["workspace"],
  "directActors": ["human"],
  "delegatedActors": [],
  "autonomyCeiling": "do",
  "consent": "reusable",
  "risk": "consequential"
}

Receipt Printing

Feature-detect sdk.printing because only compatible desktop hosts provide it. listPrinters returns bounded machine-local printer names, the system-default marker, and the host-supported 58 mm and 80 mm paper profiles. getStatus and submit both require the exact selected printer/profile. submit accepts only a bounded semantic version-1 receipt whose text fields contain printable ASCII. The host revalidates the destination on every call and owns rendering, wrapping, feed, cut, and OS spooler access.

const printing = sdk.printing;
const discovery = await printing?.listPrinters();
const printer = discovery?.printers.find((candidate) => candidate.isDefault);
const paperProfile = discovery?.paperProfiles.find(
  (candidate) => candidate.id === 'receipt-80mm',
);
const profile = paperProfile?.id;
const selection =
  printer && profile ? { printerName: printer.name, profile } : null;
if (
  printing &&
  selection &&
  (await printing.getStatus(selection)).availability === 'ready'
) {
  const result = await printing.submit({
    jobKey: `order-${orderId}`,
    selection,
    document: {
      version: 1,
      lines: [
        { kind: 'text', text: 'Order receipt', weight: 'bold' },
        { kind: 'key-value', label: 'Order', value: orderId },
        { kind: 'divider' },
        { kind: 'text', text: 'Thank you', alignment: 'center' },
      ],
    },
  });
  console.log(result.disposition, result.physicalExactlyOnce);
}

MiniAppReceiptLine excludes raw ESC/POS bytes and arbitrary markup. A stable jobKey lets the host suppress repeat submissions within its installation, workspace, and selected-destination journal. Spooler acknowledgement cannot prove physical exactly-once output, so every result reports physicalExactlyOnce: false; an uncertain submission can return indeterminate.

Terminal Sessions

Feature-detect sdk.terminal?.v1 because portable and mobile targets omit the terminal capability. getCapabilities reports availability for the two fixed runtime profiles and the current host limits. It is metadata-only; availability does not grant permission to open a session.

The initial desktop host reports both profiles unavailable. workspace-shell remains closed until the sandbox can positively restrict readable roots to the conversation grant plus fixed runtime files. neovim also requires a signed, integrity-locked runtime with clean configuration. Do not substitute a PATH binary or another profile when discovery reports one unavailable.

const terminal = sdk.terminal?.v1;
if (!terminal) throw new Error('Terminal sessions are unavailable.');

const capabilities = await terminal.getCapabilities();
const neovim = capabilities.profiles.find((profile) => profile.id === 'neovim');
if (!neovim?.available) {
  throw new Error(neovim?.unavailableReason ?? 'Neovim is unavailable.');
}

const session = await terminal.open({
  profile: 'neovim',
  cols: 100,
  rows: 30,
});

const reader = session.events.getReader();
try {
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    if (value.type === 'data') renderTerminalBytes(value.data);
    else handleTerminalExit(value);
  }
} finally {
  reader.releaseLock();
  await session.close();
}

write accepts one non-empty Uint8Array of at most 64 KiB and resolves only after the host acknowledges that command. resize is bounded by the reported column and row limits. The events stream is strictly ordered and uses a 256-KiB byte-sized high-water mark; consuming data replenishes host output credit. Cancelling the stream initiates session close. A terminal exit is the last event and reports its sequence, exit code or signal, and whether the session exited, was closed, was revoked, or failed.

Opening a session checks terminal.session.open, filesystem.read, and filesystem.write with do authority. Port operations inherit that exact owner- and document-bound lease; they do not prompt independently. The host derives the conversation VFS mount and owns process cleanup. Miniapp code never supplies an executable, argument vector, environment, working directory, filesystem path, or native PTY identifier.

Declare the authorization on the contribution that opens the session. Define the same three actions in the package's permission.catalog and include them in an assignable level. This excerpt selects neovim; use workspace-shell instead to request that profile.

{
  "authorization": {
    "allOf": ["terminal.session.open", "filesystem.read", "filesystem.write"],
    "effects": [
      {
        "kind": "terminal",
        "resources": ["neovim"]
      },
      {
        "kind": "filesystem-mount",
        "resources": ["conversation-vfs:read-write"]
      }
    ]
  }
}
{
  "kind": "permission.catalog",
  "id": "permissions",
  "apiVersion": 1,
  "options": {
    "actions": [
      {
        "id": "terminal.session.open",
        "resource": "terminal-session",
        "scopes": ["workspace"],
        "directActors": ["human"],
        "delegatedActors": [],
        "autonomyCeiling": "do",
        "consent": "reusable",
        "risk": "consequential"
      },
      {
        "id": "filesystem.read",
        "resource": "conversation-vfs",
        "scopes": ["workspace"],
        "directActors": ["human"],
        "delegatedActors": [],
        "autonomyCeiling": "do",
        "consent": "reusable",
        "risk": "read"
      },
      {
        "id": "filesystem.write",
        "resource": "conversation-vfs",
        "scopes": ["workspace"],
        "directActors": ["human"],
        "delegatedActors": [],
        "autonomyCeiling": "do",
        "consent": "reusable",
        "risk": "write"
      }
    ],
    "levels": [
      {
        "id": "terminal-operator",
        "actions": [
          "terminal.session.open",
          "filesystem.read",
          "filesystem.write"
        ],
        "assignableTo": ["human"]
      }
    ],
    "roleRecommendations": []
  }
}

Local Services

Desktop package surfaces expose the optional sdk.services.v1 contract. Portable package code must still feature-detect sdk.services?.v1, because mobile hosts and older desktop hosts do not install it.

const services = sdk.services?.v1;
if (services) {
  const service = await services.ensureRunning({
    contributionId: 'document-indexer',
  });
  const response = await fetch(`${service.endpoint.origin}/health`);
}

A package may address only a local.service contribution declared in its signed manifest. The host owns installation, integrity verification, executable selection, arguments, environment, port allocation, readiness checks, restart policy, and process cleanup.

See Local services for the complete manifest authority, packaging, Live TAP, diagnostics, and restart workflow.

ensureRunning will idempotently install and start the declared service, then return its opaque generation and exact loopback origin. Its deadline comes from the signed manifest; callers cannot provide a timeout or any process controls. getStatus is read-only and returns one of unavailable, stopped, installing, starting, running, or failed. A running generation can change after a restart, so do not retain its endpoint across status changes.

Starting a service requires the contribution's exact local-service.run authorization and matching local-service effect. Failure codes distinguish unsupported hosts, denied permission, integrity or sandbox failures, resource exhaustion, readiness timeouts, crash loops, and host failures. Treat unknown codes from newer hosts as ordinary operation failures.

Channels

sdk.channels provides five operations:

MethodInputResult
createCreateChannelOptionsCreateChannelResult
listOptional ListChannelsOptionsListChannelsResult
sendMessageSendChannelMessageOptionsSendChannelMessageResult
getAccessGetChannelAccessOptionsGetChannelAccessResult
getTimelineGetChannelTimelineOptionsGetChannelTimelineResult

MiniAppChannel describes a visible channel. MiniAppChannelMessage is intentionally opaque, bounded MiniAppJsonValue: the host versions timeline-row shapes independently, so narrow and validate a row before reading any fields. The timeline result also supplies the visible sequence. A former participant can remain readable through GetChannelAccessResult.visibleUntilSequence; do not interpret that as permission to write.

const access = await sdk.channels.getAccess({ channelId });
if (access.capabilities.includes('message:create')) {
  await sdk.channels.sendMessage({
    channelId,
    content: 'The report is ready.',
    body: 'The report is ready.',
  });
}

Access can change after a check. Handle rejection from the operation itself and do not infer authority from cached channel data.

Projects

sdk.projects uses CreateProjectOptions, GetProjectOptions, and UpdateProjectOptions. The corresponding CreateProjectResult, GetProjectResult, and UpdateProjectResult return the project ID or a MiniAppProject snapshot.

const result = await sdk.projects.get({ projectId });
if (result.project) {
  await sdk.projects.update({
    projectId,
    name: `${result.project.name} copy`,
  });
}

GetProjectResult.project can be null when the project is missing or outside the current capability scope.

Tasks

In React, useTasks from @theaiplatform/miniapp-sdk/react handles the list, loading and busy state, enumerated failures, and reloading after a write:

const {
  data: tasks,
  isLoading,
  failure,
  create,
} = useTasks({
  tasks: sdk.tasks,
});

Writes reload rather than patching local state — the host owns task shape (status normalization, assignee resolution, archived transitions), so echoing a locally-mutated task risks showing something the host would describe differently.

sdk.tasks is an optional MiniAppTasksApi backed by the same task silo as the built-in Tasks view. Feature-detect it because older hosts omit the capability. create, update, delete, and list accept the matching task option types and return task snapshots or archive results.

Use createWithReceipt when an interrupted workflow must safely replay task creation. It accepts a stable idempotencyKey, optional project and assignee IDs, and returns a durable MiniAppActionReceipt. The tasks silo journals the key inside the canonical CRDT document, so a replayed key returns the original task with a duplicate-suppressed receipt instead of writing a second one — the exactly-once contract is the canonical create_task mutation itself, not a second path layered over it.

const tasks = sdk.tasks;
if (tasks) {
  const existing = [];
  let cursor: string | undefined;
  do {
    const page = await tasks.list({
      limit: 50,
      ...(cursor === undefined ? {} : { cursor }),
    });
    existing.push(...page.tasks);
    cursor = page.nextCursor;
  } while (cursor !== undefined);
  console.log(`Workspace has ${existing.length} visible tasks.`);

  const { task } = await tasks.create({
    title: 'Draft launch checklist',
    status: 'toDo',
    priority: 'medium',
  });

  const { task: completed } = await tasks.update({
    taskId: task.id,
    status: 'done',
  });
  console.log(`${completed.title} is now ${completed.status}.`);

  await tasks.delete({ taskId: task.id });
}

delete is a soft archive: DeleteTaskResult reports the archived task ID rather than removing the record. Pass includeArchived to list to include archived tasks, and pass null to UpdateTaskOptions.dueDate to clear an existing due date. Task snapshots can become stale between calls, so handle rejection from each operation instead of trusting cached data.

list returns 25 tasks by default. Set limit to an integer from 1 through 50. Pass nextCursor as the next call's cursor, and keep the same workspace, includeArchived value, and limit. Treat cursors as opaque. Pagination is stable when task data does not change. Pagination is not a snapshot across concurrent changes, so a task that moves in the ordering can be omitted or returned again.

Workflows

sdk.workflows.list accepts optional ListWorkflowsOptions and returns ListWorkflowsResult, whose entries are MiniAppWorkflow values. invokeSaved accepts InvokeSavedWorkflowOptions; the optional invoke method accepts InvokeWorkflowOptions. Both return InvokeWorkflowResult.

const result = await sdk.workflows.invokeSaved({
  workflowId,
  payload: { source: 'miniapp' },
});
if (!result.success) {
  throw new Error(result.error ?? result.message);
}

Feature-detect the optional inline invoke method. A successful request reports status and may include a run ID; it does not imply that unrelated follow-up operations are authorized.

Authentication

sdk.auth is an optional MiniAppAuthApi. Its getUserProfile method returns a MiniAppUserProfile or null. The profile exposes a subject when available and host-approved public fields; it never contains raw platform credentials.

const profile = (await sdk.auth?.getUserProfile()) ?? null;
if (profile) {
  console.log(profile.sub, profile.email ?? 'No email was shared');
}

Treat a missing capability and a signed-out profile as normal states. Request the profile again after an account or scope change.

Virtual Files

sdk.vfs is an optional, desktop-only MiniAppVfsApi with provisionProjectChat, mkdir, writeFile, and writeFiles. Desktop hosts may additionally provide the optional readFile, stat, and list methods. Mobile hosts omit the namespace because they do not install the VFS host-action rail. File paths are relative to the selected conversation storage, not operating-system paths. readFile returns the file bytes, stat returns file-or-directory metadata, and list returns directory entries; pass an empty string to list to read the root. Reads are bound to the conversation of the mounting surface.

readFile rejects files larger than 16 MiB before the native read begins. The desktop host also resolves the final target against the authorized conversation and mounted roots, so symlinks that leave those roots are rejected. Read methods are feature-detected separately from the write methods and are not advertised on mobile targets or older hosts without the desktop VFS authority.

VFS mutations apply the same canonical-root check to existing symlink components. A symlink cannot redirect a write, directory creation, delete, or rename outside the authorized conversation or mounted roots.

import { isMiniAppHostActionError, sdk } from '@theaiplatform/miniapp-sdk/sdk';

const vfs = sdk.vfs;
if (vfs) {
  try {
    const provisioned = await vfs.provisionProjectChat({
      conversationId,
      projectId,
      baseBranch: 'main',
      workingBranch: 'tap/feature/project-notes',
    });
    console.log(provisioned.mountedRoots);
    await vfs.mkdir(conversationId, 'notes');
    await vfs.writeFile(
      conversationId,
      'notes/README.md',
      new TextEncoder().encode('# Notes\n'),
    );

    await vfs.writeFiles(conversationId, [
      {
        path: 'notes/plan.md',
        data: new TextEncoder().encode('# Plan\n'),
      },
      {
        path: 'notes/status.md',
        data: new TextEncoder().encode('# Status\n'),
      },
    ]);
  } catch (error) {
    if (!isMiniAppHostActionError(error)) {
      throw error;
    }
    switch (error.code) {
      case 'project_mount_not_ready':
        console.error('Reconnect the selected project folder before retrying.');
        return;
      case 'project_full_disk_access_required':
        console.error('Grant Full Disk Access in the app before retrying.');
        return;
      case 'project_provision_failed':
        console.error('Finish local project setup in the app before retrying.');
        return;
      default:
        throw error;
    }
  }
}

writeFiles accepts 1 to 64 relative paths that remain unique after case-folding, with at most 16 MiB in the whole request. The host validates and authorizes the request once, creates the required parent directories, then writes the files. It is not a transaction; a provider failure can leave a prefix of the files written, so retries must use content that is safe to write again.

The VFS API does not expose raw host filesystem access or setup details. project_mount_not_ready means the expected folder is unavailable. It remains latched until the user reconnects the folder and selects Retry in the app. project_full_disk_access_required means macOS denied that native provisioning attempt. The host does not infer this code from the current system status after another failure. Follow the app's Full Disk Access prompt and restart the app before trying again. project_provision_failed means another local setup step could not finish. Follow the app's recovery prompt, then try provisioning again.

Folder setup failed warning with a Retry button for reconnecting the selected project folder.
Retry is an explicit app action after the expected folder is available again.

Miniapps cannot promote that state. Handle unavailable scope, conflicts, and deletion as recoverable failures.

Conversation Git

sdk.git is an optional, desktop-only MiniAppGitApi for the conversation's repository. Every method is bound to the conversation of the mounting surface, and no host filesystem path crosses the boundary.

  • resolveRuntime reports whether the host uses its embedded git or the system git.
  • initializeRepository creates an empty repository in the conversation's VFS project root with the main branch. It refuses to overwrite an existing repository.
  • snapshot reports branch, head, dirty, staged, upstream, and remotes.
  • changes reports uncommitted-change counters.
  • diff returns bounded staged and unstaged unified diffs for selected paths.
  • stage stages explicitly selected paths and returns the staged diff plus an opaque stagedTree review fence.
  • approveStage requires a fresh user gesture; the host selects the latest staged result captured by stage, displays that exact staged diff, and returns a review receipt only after host confirmation. The package does not choose the tree being approved.
  • commit requires both the staged-tree fence and the host-owned review receipt, so a package cannot commit content without an explicit approval step.
  • createBranch creates and checks out a branch from an exact reviewed branch and head.
  • renameBranch renames the conversation's branch.
  • push pushes the conversation's committed branches through the host's connected GitHub authority.
  • openPullRequest opens or recovers a pull request; omitted as opens a draft, 'open' marks it ready for review.
  • pullRequests lists the pull-request records the host keeps for the conversation.
  • worktrees lists the worktrees registered for a project.
  • subscribe reports repository-state transitions; it returns an unsubscribe function.

A commit made here is a user commit. It records no specialist attribution, and undo rewinds only specialist turns.

import { sdk } from '@theaiplatform/miniapp-sdk/sdk';

const git = sdk.git;
if (git) {
  const staged = await git.stage({ conversationId, paths: ['src/index.ts'] });
  // The host displays and confirms staged.stagedDiff before returning.
  const approval = await git.approveStage({
    conversationId,
  });
  const committed = await git.commit({
    conversationId,
    message: 'Ship the reviewed change',
    stagedTree: staged.stagedTree,
    reviewReceipt: approval.reviewReceipt,
    expectedBranch: staged.branch,
    expectedHead: staged.headCommitSha,
  });
  await git.push({ conversationId });
}

Conversation Snapshots

sdk.snapshot is an optional, desktop-only MiniAppSnapshotApi for the conversation's specialist-turn save-point history. status reports the current and total turn counters and whether undo is available, history lists the per-turn entries, undo rewinds exactly the latest applied specialist turn, and subscribe reports save-point transitions. The host resolves the conversation's canonical project; callers may omit projectId or provide it as an ownership check. This is turn history, not git history.

import { sdk } from '@theaiplatform/miniapp-sdk/sdk';

const snapshot = sdk.snapshot;
if (snapshot) {
  const status = await snapshot.status({ conversationId, projectId });
  if (status.canUndo) {
    const undone = await snapshot.undo({ conversationId, projectId });
    if (undone.conflicts.length > 0) {
      console.warn('Files changed after the turn; resolve them in the app.');
    }
  }
}

User-selected Files

sdk.files is an optional desktop-only MiniAppFilesApi for files the human explicitly selects in a host-owned Open or Save dialog. It is separate from conversation VFS and private package storage. The Miniapp receives an opaque, owner-bound handle, safe metadata, and bytes; native paths and provider credentials never cross the SDK boundary. Feature-detect the namespace before showing file controls.

Call pickOpen or pickSave as the first asynchronous operation started by a current human gesture. Do not await unrelated work before opening a picker. pickOpen.accept takes lowercase, parameterless MIME types or dot-prefixed extensions. pickSave takes a required suggestedName and an optional mimeType. Cancelling either dialog rejects with file_cancelled.

import { isMiniAppHostActionError, sdk } from '@theaiplatform/miniapp-sdk/sdk';

const files = sdk.files;
if (!files) throw new Error('User-selected files require the desktop host.');

const reportFileError = (error: unknown) => {
  if (isMiniAppHostActionError(error) && error.code === 'file_cancelled')
    return;
  console.error(error);
};

const readSelectedText = async () => {
  const [handle] = await files.pickOpen({
    accept: ['text/plain', '.md'],
    multiple: false,
    recoverable: false,
  });
  if (!handle) return;

  const metadata = await files.metadata(handle);
  const bytes = await files.read(metadata.handle, {
    maxBytes: 16 * 1024 * 1024,
  });
  console.log(metadata.name, new TextDecoder().decode(bytes));
};

const saveText = async () => {
  const handle = await files.pickSave({
    suggestedName: 'notes.txt',
    mimeType: 'text/plain',
    recoverable: false,
  });
  const receipt = await files.write(
    handle,
    new TextEncoder().encode('Saved by my Miniapp.\n'),
    {
      expectedRevision: handle.revision,
      idempotencyKey: crypto.randomUUID(),
    },
  );
  console.log(receipt.handle, receipt.contentHash);
};

openButton.addEventListener(
  'click',
  () => void readSelectedText().catch(reportFileError),
);
saveButton.addEventListener(
  'click',
  () => void saveText().catch(reportFileError),
);

metadata, read, readRange, and createReadStream operate only on an issued handle. Metadata includes a host-issued handle refreshed to the returned revision, plus the selected basename, safe content fields, and provenance, but no path. Use metadata.handle for subsequent revision-fenced reads; never clone or edit an older handle to advance its revision. A whole-file read defaults to a 16 MiB maximum; lower it with maxBytes, or use bounded ranges and a readable stream for larger files. Read streams request 256 KiB ranges by default and accept a chunkBytes value from one byte through one MiB. Pass an AbortSignal to stop SDK reads or streaming work.

Both write and createWriteStream publish atomically. Pass the exact revision observed before the write and a caller-owned idempotency key. Generate one UUID for each logical write; reuse it only when retrying that same revision and byte sequence. A final revision conflict rejects with file_stale instead of overwriting an external edit. A successful write returns a receipt with the updated handle, revision, SHA-256 content hash, byte length, commit time, and idempotency key. Use receipt.handle for later operations. For a write stream, close its writable and await receipt; the receipt resolves only after the atomic commit. Cancellation applies until close() dispatches that commit. After that boundary, the SDK waits for the authoritative receipt or commit error because publication can no longer be safely canceled. Abort before the commit and failed commits leave the previous complete destination visible.

Idempotency receipt replay is limited to the current live host process. A hard host crash cannot publish a partial destination: the destination contains either the previous complete bytes or the atomically published replacement. Each in-flight stage lives in a transaction directory attributed by an owner-only app-data journal and a locked random marker. Journal records are installed from a synced private pending file with a crash-atomic, no-replace publication step. Before accepting bytes, the host also creates a pinned publication file and records the identities of the transaction directory, marker, staged content, and publication file. On restart, the host removes an owned transaction only when the recorded parent and directory identities match, the marker is unlocked and exact, and every remaining owned entry has its recorded identity. A completed publication that left only a stale record is retired without touching the destination.

Recovery fails closed when ownership proof is incomplete. An intent-only empty directory, partially written marker, replacement, symlink, mismatched entry, or unexpected entry stays untouched and journaled. A temporarily unavailable or renamed parent is retried when that same directory identity is selected again. This includes the narrow crash window after the private directory or its child files are created but before their identities become durable in the owned record. The host preserves that state instead of guessing from reserved names. The host never sweeps neighboring files merely because their names look like staging files. Cleanup revalidates every recorded identity immediately before removal and fails closed on an observed substitution. POSIX has no portable unlink-by-descriptor operation, so an uncooperative process running as the same OS user can still win the final gap between that identity read and the unlink system call. The API does not replay the lost in-memory receipt or guarantee strict compare-and-swap against a simultaneous uncooperative external writer.

rename changes only the selected file's basename and returns an updated handle. delete removes the selected file and permanently revokes that handle. Both require the exact revision the caller observed, the corresponding access bit on the host-issued handle, and their separately declared consequential permission. The mutation fence is independent of the revision at which the handle was issued, so a revision explicitly returned by metadata or watch is valid without forging a replacement handle. Prefer the refreshed handle those receipts return because revision-fenced reads use the handle's embedded revision. watch performs one bounded long poll for a revision change; call it again after each receipt. A timeout is a successful unchanged receipt, while revocation, provider loss, and external mutation retain their stable file error or revision result.

MiniAppFileRenameOptions contains expectedRevision, a basename-only newName, and an optional signal. A successful rename returns a MiniAppFileRenameReceipt with the refreshed handle, resulting name and revision, and numeric renamedAt timestamp. Keep the refreshed handle because the pre-rename handle is stale. The host keeps the file in its selected directory and rejects separators, traversal names, collisions, stale revisions, and symlink substitutions.

MiniAppFileDeleteOptions contains expectedRevision and an optional signal. A successful delete returns a MiniAppFileDeleteReceipt with the revoked handleId, terminal revision, and numeric deletedAt timestamp. Deletion cannot be undone through the handle. Any later operation with that handle rejects with file_revoked.

MiniAppFileWatchOptions contains previousRevision, waitMs, and an optional signal. waitMs must be from 0 through 30,000 milliseconds. The resulting MiniAppFileWatchReceipt returns a host-issued handle refreshed to the observed revision, repeats the handle ID and previous revision, and reports the observed revision, change (unchanged, created, modified, or deleted), numeric observedAt timestamp, and timedOut. A timeout sets timedOut: true and change: 'unchanged'; it is not an error.

const renamed = await files.rename(handle, {
  expectedRevision: handle.revision,
  newName: 'meeting-notes.md',
});

const observed = await files.watch(renamed.handle, {
  previousRevision: renamed.revision,
  waitMs: 30_000,
});

if (observed.change === 'deleted') {
  console.log('The selected file was removed outside the Miniapp.');
}

Picker and recovery actions run through the surface action broker. Metadata, file bytes, mutation, and watch requests use short-lived exact grants over the same-origin JSON Connect endpoint. They never travel through ordinary postMessage, and neither transport exposes a native path.

A destination returned by pickSave uses the files.pick-save action for one exact logical write. The host binds that picker provenance to the handle, picker-issued revision, and idempotency key before authorization, so an unavailable or lost grant response can be retried with those exact fields. Changed write fields and every write to a file returned by pickOpen require separately granted files.overwrite authority. The host tracks this provenance; callers cannot select the permission by changing the handle. revoke needs no new permission because it only reduces authority, and desktop teardown revokes the surface's handles even if guest cleanup does not run.

Current hosts issue only session-scoped handles with recoverable: false. Passing recoverable: true or calling recover rejects with file_unsupported. The files.retain-handle action and retain-handle effect resource reserve future recovery; that action requires fresh-decision consent, which the public surface SDK cannot currently request. Do not declare or request retained handles until a supporting host-mediated consent flow is available.

A file.handler registration follows its exact package installation and active release. Disabling, rolling back, or uninstalling that installation removes or replaces its active handler authority. This lifecycle never deletes a selected user file. Collaboration-owned artifacts remain subject to the collaboration owner's retention policy, independently of the handler package installation.

Each handler role requires the referenced desktop surface to declare its exact actions in authorization.onDemand. The manifest is rejected when any action in this table is missing.

File handler roleRequired surface actions
openfiles.read
importfiles.read and files.import-disclose
exportfiles.overwrite and files.export-artifact

Every file action that a desktop UI surface requests belongs exactly once in its authorization.onDemand. Its permission catalog entry uses scopes: ["user"], directActors: ["human"], and delegatedActors: []. Add one user-file effect whose resources are exactly the effect resources for that surface's requested actions.

Action IDPermission resourceEffect resourceAutonomyConsentRisk
files.pick-openuser-file-pickerpick-opendoreusableread
files.pick-saveuser-file-pickerpick-savedoreusablewrite
files.readuser-selected-filesreadlistenreusableread
files.overwriteuser-selected-filesoverwritedoreusablewrite
files.retain-handleuser-file-handlesretain-handledofresh-decisionconsequential
files.renameuser-selected-filesrenamedoreusableconsequential
files.deleteuser-selected-filesdeletedoreusableconsequential
files.watchuser-selected-fileswatchlistenreusableread
files.associateuser-file-associationsassociatedofresh-decisionconsequential
files.import-discloseuser-file-importsimport-disclosedofresh-decisionconsequential
files.export-artifactcollaborative-artifactsexport-artifactdofresh-decisionconsequential

The final three actions are owner-bound and are not generic sdk.files operations. The host owns default-handler settings; a package cannot assign itself as the default. Collaboration authorities must enforce import disclosure and artifact export at the boundary that owns the canonical artifact facts. Do not request these actions for ordinary picker, read, or write operations.

After picker admission, file operations can reject with a stable MiniAppFileErrorCode: file_denied, file_cancelled, file_stale, file_revoked, file_unavailable, file_too_large, file_malformed, file_encrypted, file_quota_exceeded, or file_unsupported. Picker admission can reject with user-gesture-required before the native dialog opens. Use isMiniAppHostActionError to distinguish that from file_denied, keep an unknown-code fallback, and do not parse message text.

Direct inference

sdk.inference is an optional, low-level generation API for isolated tasks such as comparing several candidate answers. It uses only host-managed or workspace-shared provider routes. A miniapp selects a canonical model, but it never receives provider credentials. Direct inference is available only to desktop UI surfaces whose package excludes host versions before 2.3.5 in compatibility.tapHost; continue to feature-detect the optional namespace.

Prefer a specialist when the task needs tools, durable conversational context, or product-specific behavior. Direct inference has no tools, attachments, or implicit history. Pass the conversation that owns the user action explicitly:

const inference = sdk.inference;
const vfs = sdk.vfs;

if (inference && vfs) {
  const models = await inference.listModels();
  const model = models.at(0);
  if (!model) throw new Error('No managed inference model is available.');

  const result = await inference.send({
    conversationId,
    model: model.canonicalName,
    messages: [
      { role: 'system', content: 'Return concise Markdown.' },
      { role: 'user', content: 'Compare the three proposed headlines.' },
    ],
    maxTokens: 600,
  });

  await vfs.mkdir(conversationId, 'comparisons');
  await vfs.writeFile(
    conversationId,
    `comparisons/${result.turnId}.md`,
    new TextEncoder().encode(result.text),
  );
}

Every send returns the effective model and provider, token and cost usage when the provider reports it, latency, and the host-generated turn ID. The host also records content-free turn telemetry. The response itself remains ephemeral: only content the miniapp deliberately writes to VFS becomes durable.

Specialists

sdk.specialist is an optional MiniAppSpecialistApi. It can run a turn against a specialist your package declares, join one to a channel, list a workspace, and create a specialist. Feature-detect each optional method before showing its action.

A specialist becomes invokable by being declared in your manifest, not by being registered at runtime. See Declaring a Specialist for the four required pieces and the resolved <name>@<version> ID form. Workspace visibility alone never grants authority: the host rejects an ID the current package release does not declare.

Running a turn

Most surfaces should use runSpecialist, or the useSpecialist hook that wraps it. They handle the parts every caller otherwise rewrites: feature detection, distinguishing the failure causes, extracting text from the completion parts, and validating the answer.

import { runSpecialist, sdk } from '@theaiplatform/miniapp-sdk/sdk';

const outcome = await runSpecialist({
  specialistId: 'standup-drafter@0.2.0',
  content: 'Draft my standup.',
  parse: (text) => Draft.safeParse(JSON.parse(text)).data,
});

if (outcome.ok) {
  render(outcome.data); // typed by `parse`
} else {
  show(outcome.failure.message); // accurate for the actual cause
}

It never rejects. Every failure resolves as { ok: false } with an enumerated SpecialistFailureReason, so a caller cannot accidentally treat "the workspace withheld a grant" and "the provider is down" the same way.

In React, useSpecialist from @theaiplatform/miniapp-sdk/react adds the state machine and a regenerate affordance:

import { useSpecialist } from '@theaiplatform/miniapp-sdk/react';

const turn = useSpecialist('standup-drafter@0.2.0');

if (!turn.isSupported) return null;
return (
  <>
    <button
      disabled={turn.isRunning}
      onClick={() => turn.run('Draft my standup.')}
    >
      {turn.isRunning ? 'Drafting…' : 'Draft'}
    </button>
    {turn.failure && <p role="alert">{turn.failure.message}</p>}
    {turn.data && <Draft value={turn.data} onRetry={turn.regenerate} />}
  </>
);

turn.status is unsupported, idle, running, ready, or failed. A failure outranks a previous answer, so a failed regenerate never leaves a stale result presented as current. While a turn is in flight run is a no-op — repeat clicks cannot stack up, which matches the host serializing turns on one room anyway.

Cancellation is not offered. The host exposes no way for a guest to stop a turn it started, and an abort() that only stopped the caller listening would imply otherwise while the turn kept running.

Calling the host method directly

runTurnWithTools accepts MiniAppSpecialistTurnOptions and resolves with MiniAppSpecialistTurnResult once the turn reaches a terminal event.

const specialists = sdk.specialist;
if (specialists?.runTurnWithTools) {
  const result = await specialists.runTurnWithTools({
    workspaceId,
    specialistId: 'standup-drafter@0.2.0',
    content: 'Draft my standup from my recent activity.',
    modelOverride: null,
    messageId: null,
    interactionMode: 'agentic',
    timeoutMs: 60_000,
    // channelId omitted — see below
  });
  const [part] = result.completionEvent.parts;
  console.log(part);
}

streamTurnWithTools(options, observer) has the same terminal result and authorization semantics. It additionally reports frozen full-body snapshots through observer.onSnapshot:

const result = await specialists.streamTurnWithTools?.(
  {
    workspaceId,
    channelId,
    dispatch: true,
    specialistId: 'interview-subject@0.2.0',
    content: 'Summarize the latest changes.',
    modelOverride: null,
    messageId: null,
    interactionMode: 'conversational',
    timeoutMs: 60_000,
  },
  {
    onSnapshot(snapshot) {
      // snapshot.body replaces the previous body for snapshot.messageId.
      renderDraft(snapshot.body);
    },
  },
);

Each snapshot has the exact shape { type: 'messageSnapshot', channelId, messageId, streamVersion, body }. Versions rise per message and body is a replacement, not a delta. Observer errors are isolated from the turn. Zero snapshots is valid: silent turns, channel-less turns in a hidden host-owned room, disconnected realtime sessions, and Test Lab specialist turns do not expose progress. In all cases the returned promise still follows the same terminal behavior as runTurnWithTools.

Omitting channelId is the channel-less form. The host then runs the turn in a private room it owns for your (workspace, package, specialist). That means:

  • The turn needs only specialists.invoke. It never needs a channels.* permission, because your app neither creates nor joins a channel — the host resolves its own room.
  • The room does not appear in the user's channel list. It is not a conversation they created.
  • The room is persistent and keyed on that triple, so repeat calls continue one conversation rather than starting fresh.

That last point is the one to design around. A channel-less turn is not fire-and-forget: because the session stays live, you can offer regenerate or amend, and the specialist sees what it answered before. If you need a clean slate, say so in the prompt — there is no per-call reset.

Supplying channelId keeps the ordinary behaviour: the turn runs in that channel, and the host checks the user's participation in it. By default it is still silent — no message is written to the channel, and the answer reaches you only through completionEvent.parts.

dispatch: true makes a channelled turn visible. The host persists your content into the channel as an ordinary message and routes it, so the specialist runtime writes the reply itself, with the provenance chat requires.

This mode requires channels.send-message with do autonomy in addition to the base specialists.invoke grant. The calling surface must declare both permissions, and the package must hold both grants.

await specialists.runTurnWithTools({
  workspaceId,
  channelId,
  dispatch: true,
  specialistId: 'interview-subject@0.2.0',
  content: '@[Maya](specialist:interview-subject) what changed last quarter?',
  modelOverride: null,
  messageId: null,
  interactionMode: 'conversational',
  timeoutMs: 60_000,
});

Design around two consequences:

  • Read the reply from the channel timeline, not the result. It lands as a real specialist message, so channels.getTimeline is what renders it. The returned completion is the turn's own record; treating it as the thing to display gives you a message the channel already has.
  • The specialist must already be seated in the channel. Joining one is channels.manage-specialists, a separate grant — this path mentions and claims an existing participant, it does not add one.

dispatch says nothing on a channel-less turn, which is always routed this way.

Rooms and channels

A room is the underlying primitive: a conversation with participants and a message timeline. A channel is a room presented to the user — listed, joinable, discoverable. Every specialist turn runs in a room, because a room's message lifecycle is what starts and tracks the turn. A channel-less turn simply runs in a room that is never presented as a channel.

Failures to handle

Reject paths are distinct on purpose; surface them distinctly rather than collapsing them into one retry message:

CauseWhat to tell the user
A required grant is withheldThe action is not permitted in this workspace
The host predates runTurnWithToolsThe app needs updating
The turn returns no textA model or provider problem, not their input
The output does not match your contractYour app could not parse the answer

A tool the specialist calls may need a credential the workspace has not configured. That surfaces as a completed turn whose content explains the tool failed — not as a rejection — so validate the answer against your own contract before trusting it.

Joining a specialist to a channel

joinToChannel adds one declared specialist to an existing channel. prepareChannel prepares 1 to 64 exact package-declared specialist IDs while sharing channel access, workspace catalog, and participant-roster reads. It does not create the channel and does not require specialists.list because the host uses the catalog only for internal identity resolution.

const specialists = sdk.specialist;
if (specialists) {
  const available = await specialists.listWorkspace(workspaceId);
  const declared = available.find((s) => s.id === 'standup-drafter@0.2.0');
  if (declared) {
    const sessionId = await specialists.joinToChannel(channelId, declared.id);
    console.log(`Joined specialist session ${sessionId}`);
  }
}

For several declared specialists, prepare them in one request:

const prepared = await sdk.specialist?.prepareChannel({
  workspaceId,
  channelId,
  specialistIds: ['reviewer@0.2.0', 'approver@0.2.0'],
});

console.log(prepared?.specialists);

IDs must be unique and the result preserves request order. The operation is not transactional: if a late step fails, some specialist runtime sessions may already exist even when chat participants were not updated. Do not blindly retry. Re-read channel state and recover through the domain flow appropriate to your miniapp.

Types

MiniAppCreateSpecialistOptions and MiniAppCreateSpecialistResult describe a basic created specialist. MiniAppSpecialistInteractionMode, MiniAppSpecialistConversationPart, and the turn option/result types describe the complete request and terminal response for a tool-enabled turn. Hosts reject invalid IDs, unsupported modes, out-of-range timeouts, and unauthorized channel access.

upsertManaged registers a package-owned custom specialist at runtime and can return MiniAppManagedSpecialistResult. It is not the way to make a specialist invokable — use manifest declaration. MiniAppManagedSpecialist is the bounded manifest it accepts; ownership, workspace, visibility, installation, and verification metadata are derived by the host and rejected if a miniapp supplies them.

Chat

sdk.chat is the required MiniAppChatApi. sendTextToChat selects the active conversation, reveals the shared composer, and places text there. Compatible hosts can also expose archiveConversation.

await sdk.chat.sendTextToChat('Summarize the current project.');

The method places text for the user; do not describe it as silently sending a user-authored message.

archiveConversation takes workspace, user, conversation, and project IDs and resolves with null after archival. It is optional and can reject when the current package session lacks authority. Use sdk.specialist.joinToChannel to add a specialist to a channel.

Compatible hosts expose sdk.chat.stageDeepLink so a miniapp can place a link to one of its own resources in Chat without constructing or exposing a TAP router URL. Declare chat.compose at do autonomy on the calling surface and invoke the method synchronously from a fresh explicit user gesture. The package supplies a display label and MiniAppDeepLinkTarget: a bounded JSON object with a required kind. The host derives and binds workspace, installation, package, release, digest, and surface provenance.

shareButton.addEventListener('click', () => {
  void sdk.chat.stageDeepLink?.({
    label: 'Open selected board',
    target: { kind: 'board.card.v1', cardId: selectedCardId },
  });
});

const stopDeepLinks = sdk.navigation.subscribeDeepLinks?.(
  ({ requestId, target }) => {
    if (target.kind === 'board.card.v1' && typeof target.cardId === 'string') {
      openCard(target.cardId, requestId);
    }
  },
);
// Call stopDeepLinks?.() during unmount.

Chat renders a host-owned button, never an anchor. Activation requires the same installed release and delivers MiniAppDeepLinkOpenRequest only to that package surface. sdk.navigation.subscribeDeepLinks needs no additional permission action because it receives only package-scoped targets; keep the subscription for the surface lifetime and clean it up during unmount. Release or generation drift fails closed.

Use stageDeepLinkWithRollback when staging is one step in a larger transaction. It resolves with an opaque MiniAppStagedDeepLink. If a later step fails, pass that exact handle to unstageDeepLink; rollback still requires the declared chat.compose action but does not require a new gesture.

const staged = await sdk.chat.stageDeepLinkWithRollback?.({
  label: 'Open selected board',
  target: { kind: 'board.card.v1', cardId: selectedCardId },
});

if (staged) {
  try {
    await persistShareReceipt();
  } catch (error) {
    await sdk.chat.unstageDeepLink?.(staged);
    throw error;
  }
}

All four deep-link methods are optional for compatibility with older hosts. Feature-detect them, reject malformed or unknown targets in the package, and never treat the target or requestId as authority.

Retention Reporting

sdk.trr is a MiniAppTrrApi with getAggregate, getMdTrr, and getEcrt, which take a MiniAppTrrScope naming the cohort dimension to slice by, plus getDeathCauses, getRelationMix, and getSurvivalCounts, which name no cohort and take at most a workspace and a horizon. Every read reports only the calling principal's own local ledger. Declare trr.read for each of those reads except getEcrt, which needs the separate trr.read-cost. runSweep is not a read: it recomputes the verdicts those reads report and needs its own trr.sweep permission at do autonomy, so a package that declares only trr.read is refused.

The object is always present, so a property check is not a capability check — a host that does not support these reads installs methods that reject. Detect support by handling the rejection.

try {
  const report = await sdk.trr.getAggregate({ dimension: 'project' });
  if (report.state === 'ok') {
    console.log(report.horizonSeconds, report.cells.length);
  }
} catch (error) {
  console.log('Retention reporting is unavailable here.', error);
}

Branch on state rather than on cells.length: ok carries cells, withheld means the host suppressed cohorts, and no-data means the ledger holds nothing for that scope. Treat withheld as a normal outcome — a personal ledger commonly has too few distinct contributors to publish.

getEcrt is the exception to reading withheld as privacy suppression. Cohorts the host could not price are returned in cells carrying unpriced: true, while state reflects only the priced ones, so an all-unpriced answer arrives as withheld with a non-empty cells array. Inspect the cells before telling a user their cohort was too small.

Every cell carries cohortKeyHash, a content-free key, and may carry cohortLabel — the cohort's name (a project's title, or a specialist, model, or harness id) resolved by the host from local workspace state. Render the label when it is present and the hash when it is not; a labeled read names which project or specialist a number belongs to, so treat it as workspace data rather than as anonymous statistics.

Cells are MiniAppJsonValue because the host owns their shape and strips its research-only fields before a guest sees them, so it can add a field without republishing this package. getEcrt reports modeled spend per surviving code unit, never per provider token.

runSweep is the only write on this surface: it recomputes the retention verdicts the reads above report, needs the separate trr.sweep permission at do autonomy, and is throttled by the host so a rejection means "try later" rather than "failed". It returns no counts — the sweep tallies every principal's rows in the ledger while the reads are scoped to you — so re-read getSurvivalCounts once it resolves.

getDeathCauses and getRelationMix are the counted reads, and both carry window: 'all-time' because they span the whole ledger rather than a horizon — do not place them beside a horizon-scoped ratio without showing that label, and note that getDeathCauses counts edit charges rather than messages, so its totalDeaths legitimately exceeds deadCount from getSurvivalCounts. A relation absent from getRelationMix had no countable charge, which is not the same as zero, and no severity is reported because severity scores the relation and not the count. All three counted reads are scoped to the reader's own rows, so their state is only ok or no-data — no floor can withhold them.

sdk.navigation.open accepts OpenNavigationOptions with a platform-relative path. It is not a general URL or script launcher.

Desktop hosts may also expose sdk.navigation.openExternal. Feature-detect the method, then call it synchronously from a user click. It accepts OpenExternalNavigationOptions containing an absolute HTTPS URL, rejects credentials, and opens only the operating-system browser. The URL's exact canonical origin must appear in the calling workspace-scoped UI contribution's external-navigation effect, and that contribution must declare the on-demand navigation.open-external action. User-scoped surfaces cannot declare this authority, and packages that do must set compatibility.tapHost to a range that excludes versions before 2.3.4. There is no platform-wide origin allowlist, and external-navigation effects do not grant SDK HTTP access.

Declare the authority on the desktop surface that makes the call, together with the canonical permission action:

{
  "kind": "ui.surface",
  "id": "account-settings",
  "apiVersion": 1,
  "targets": {
    "desktop": { "expose": "./ui/account-settings", "runtime": "webview" }
  },
  "authorization": {
    "onDemand": ["navigation.open-external"],
    "effects": [
      {
        "kind": "external-navigation",
        "resources": ["https://auth.labor0.com", "https://app.labor0.com"]
      }
    ]
  },
  "options": {
    "placement": "workspace-left",
    "scope": "workspace"
  }
}
{
  "kind": "permission.catalog",
  "id": "permissions",
  "apiVersion": 1,
  "options": {
    "actions": [
      {
        "id": "navigation.open-external",
        "resource": "external-navigation",
        "scopes": ["workspace"],
        "directActors": ["human"],
        "delegatedActors": [],
        "autonomyCeiling": "do",
        "consent": "reusable",
        "risk": "consequential"
      }
    ]
  }
}

hasEditorView and hasHostHttpRequest are optional boolean feature flags. Treat values other than true as unavailable. When hasHostHttpRequest is true, the desktop host also supplies sdk.http and sdk.credentials; portable code should still check the objects before calling them.

await sdk.navigation.open({
  path: `/workspace/${workspaceId}/channels/${channelId}`,
});

if (typeof sdk.navigation.openExternal === 'function') {
  await sdk.navigation.openExternal({
    url: 'https://github.com/example/repository',
  });
}

if (sdk.hasEditorView === true) {
  // Render an action that uses the documented web editor helper.
}

Navigation rejects malformed or out-of-scope paths. Feature flags are snapshots; re-check them after a new surface realm mounts.

MiniAppOpenExternalErrorCode enumerates the bounded external-navigation failures: unsupported-host, authorization-denied, authorization-unavailable, user-gesture-required, stale-installation, origin-rejected, request-expired, and native-open-failed. Treat authorization-unavailable as retryable; it means the host could not reach or read the permission authority, not that the user denied access. Paths, query strings, fragments, credentials, and complete URLs are never included in host logs.

Host Action Errors

Host-backed operations can reject with MiniAppHostActionError. Its code is a stable, non-secret machine-readable identifier; its message is safe to show to the user. Use isMiniAppHostActionError to narrow an unknown rejection instead of matching message text. The guard also validates the public error shape, including the canonical code format.

import { isMiniAppHostActionError, sdk } from '@theaiplatform/miniapp-sdk/sdk';

try {
  await sdk.http?.request({
    method: 'GET',
    url: 'https://api.example.com/report',
  });
} catch (error) {
  if (isMiniAppHostActionError(error)) {
    console.error(`${error.code}: ${error.message}`);
  } else {
    throw error;
  }
}

Codes are intended for branching, telemetry, and assertions. A code can be added by a newer host, so handle unknown values as ordinary operation failures.

Artifact Types

A package declares a durable collaborative artifact type with an artifact.type contribution. The contribution is host-declarative: the signed manifest supplies type metadata, per-document sync protocols, schemas, and bounded limits, while the platform owns transport, persistence, sessions, receipts, and authority. The host never inspects package-owned protocol payloads or domain types, so any package can register a board, design, or domain record through the same contract Compose uses for documents.

artifact.type requires apiVersion: 1, lifecycleScope: "installation", and exactly one desktop target with runtime: "host-declarative".

{
  "kind": "artifact.type",
  "id": "playground-document",
  "apiVersion": 1,
  "lifecycleScope": "installation",
  "targets": { "desktop": { "runtime": "host-declarative" } },
  "options": {
    // Package-qualified: "<package.namespace>.<name>.v<N>", N in 1 to 64.
    "typeId": "collaborative-artifact-test.document.v1",
    "displayName": "Playground Document",
    // One to 16 independently permissioned document lanes. Content and review
    // can require different write actions and different sync protocols.
    "documents": [
      {
        "id": "content",
        "displayName": "Document content",
        "syncProtocol": "collaborative-artifact-test.document-operations.v1",
        "snapshotSchema": "schemas/document-snapshot.v1.json",
        "operationSchema": "schemas/document-operation.v1.json",
        "writeAction": "artifact.document.edit",
        "maxOperationBytes": 262144,
        "maxSnapshotBytes": 16777216,
      },
      {
        "id": "review",
        "displayName": "Review comments",
        "syncProtocol": "collaborative-artifact-test.review-operations.v1",
        "snapshotSchema": "schemas/review-snapshot.v1.json",
        "operationSchema": "schemas/review-operation.v1.json",
        "writeAction": "artifact.document.review",
        "maxOperationBytes": 32768,
        "maxSnapshotBytes": 4194304,
      },
    ],
    "schemas": {
      "anchorSchema": "schemas/document-anchor.v1.json",
      "threadSchema": "schemas/document-thread.v1.json",
      "presenceSchema": "schemas/document-presence.v1.json",
      "previewSchema": "schemas/document-preview.v1.json",
    },
    // Same-package ui.renderer contribution that previews this artifact type.
    "previewRenderer": "artifact-preview",
    // Optional migration entry point: a same-package local.service or
    // workflow contribution. Deterministic, idempotent, receipt-backed.
    "migration": { "contributionId": "artifact-migrations" },
    "fileAssociations": [
      {
        "id": "document-file",
        "extensions": [".pdoc"],
        "mimeTypes": [],
        "direction": "export",
      },
    ],
    "hostResources": [
      "sync-transport",
      "snapshot-store",
      "presence-directory",
      "receipt-journal",
    ],
    "compatibility": { "minReaderVersion": 1, "maxWriterVersion": 1 },
  },
}

Validation is fail-closed at package build and install review:

  • typeId and every syncProtocol must be rooted at the package namespace and end in a canonical .v<N> suffix, so one package cannot claim another package's type or protocol IDs.
  • Each document lane's snapshotSchema and operationSchema (and the optional anchorSchema, threadSchema, presenceSchema, and previewSchema) must be safe package-relative paths ending in .json. Ship the referenced schema files as real package assets.
  • writeAction must name an action declared by the package's own permission.catalog contribution, with direct-human access, reusable consent, and autonomyCeiling: "do"; the action is dedicated to artifact-type writes, may be shared by artifact types, and must not authorize unrelated contributions.
  • maxOperationBytes is bounded at 1 MiB per operation and maxSnapshotBytes at 64 MiB per snapshot; the host enforces tighter effective ceilings at runtime.
  • previewRenderer must reference a same-package ui.renderer contribution, and migration.contributionId must reference a same-package local.service or workflow contribution so migrations stay outside any UI surface. When migration is present, hostResources must include receipt-journal so the declared migration can use the platform receipt authority.
  • File association extensions are lowercase .<alphanumeric> suffixes, directions are import, export, or import-export; extensions and MIME selectors must be unique across all artifact.type contributions in the package release because dispatch has no type-specific tie-breaker; and hostResources is a closed set (sync-transport, snapshot-store, presence-directory, receipt-journal) with no duplicates.
  • compatibility.minReaderVersion must not exceed maxWriterVersion, and neither may exceed the format version declared by the typeId suffix. Opening an older artifact negotiates against this range; downgrades fail explicitly when the installed release cannot read the artifact.
Info

Runtime collaboration transport and authority are provided by the platform's generic miniappCollaborativeArtifacts module. Until a host ships that module, the contribution registers type metadata and schemas at install time but no live sync session can start.

Artifact Context Resolution

An action.command launch carries one MiniAppArtifactReference through the target surface's context.launches subscription. The reference is an immutable, short-lived authority handle for exactly one channel-message, pull-request, task, or repository-issue. Artifact content never appears in the launch message.

The current end-to-end invocation and resolver path is available in the Tauri desktop host only. Package validation requires action.command to select exactly the desktop target, and the native mobile host does not install sdk.artifacts.

referenceId is the opaque host-minted bearer value used to redeem the reference. kind narrows the host-versioned snapshot. artifactId is a bounded display identity, such as a message ID, task ID, or canonical GitHub URL, and is not authority. workspaceId names the invocation workspace, while mintedAt and expiresAt bound the reference lifetime.

Do not construct, modify, persist, log, or place a reference in a URL. The host binds its opaque value to the exact principal, installation, package release, target, surface contribution, workspace, and local package generation that received it. Copying the visible coordinates into another object does not mint authority, and forwarding a valid object to another surface does not transfer authority.

resolve(options: { reference: MiniAppArtifactReference }) returns a MiniAppMaybePromise<{ artifact: MiniAppResolvedArtifact | null }>. Feature-detect sdk.artifacts, then pass the received object unchanged:

const artifacts = sdk.artifacts;
if (!artifacts) {
  throw new Error('Artifact resolution is unavailable on this host.');
}

const { artifact } = await artifacts.resolve({
  reference: launch.reference,
});

if (artifact === null) {
  renderUnavailable();
} else {
  switch (artifact.reference.kind) {
    case 'channel-message':
      renderMessage(artifact.snapshot, artifact.provenance);
      break;
    case 'pull-request':
    case 'repository-issue':
      renderRepositoryItem(artifact.snapshot, artifact.provenance);
      break;
    case 'task':
      renderTask(artifact.snapshot, artifact.provenance);
      break;
  }
  attachKnownPlots(artifact.linkedPlotIds);
}

resolve reads the owning source at call time. In the current Tauri host, artifact.snapshot contains at most 64 KiB of canonical JSON. The snapshot is sanitized, bounded, and host-versioned, so narrow it by reference.kind and tolerate additional fields. Do not treat it as a complete provider response or retain it as an authority-bearing record. provenance names the source, observation time, and nullable source revision used for that read.

linkedPlotIds contains at most 256 deduplicated IDs from the artifact owner's canonical plot relation. An empty array means the host knows of no authoritative relation. It does not prove that a plot does not exist, and packages must not infer links from URLs, chat previews, or snapshot text.

The host authorizes artifacts.read before the source read and checks it again after the read. A well-shaped request from the current workspace and an authorized surface returns { artifact: null } when the reference is expired, unknown, modified, bound to another surface, missing from its source, or reported unavailable by that source. Invalid options or reference shapes, a workspace mismatch, a permission denial or revocation, and a source read failure reject the operation instead. Treat both outcomes as expected and avoid automatic retries after expiresAt.

Generic plot and orchestration primitives

The desktop host currently installs sdk.codeIntel, sdk.workspace, sdk.tasks, sdk.artifacts, and workflow run observation. The SDK installs sdk.artifacts on every desktop target, so its presence does not prove that the mounted surface declares or holds artifacts.read. It does not install sdk.plots, sdk.home, or sdk.integrations, and it does not install a task-linking method. Feature detection for those namespaces therefore returns false. Their exported interfaces are reserved contract vocabulary for a host that later supplies the required authoritative backing; they are not usable runtime capabilities today. Direct raw host-action calls fail with capability-unavailable as a defensive boundary.

The manifest does not accept plot definitions. Context-bound actions use only the strict action.command contract and cannot declare or imply a plot definition.

sdk.codeIntel is the read-only repository-scoped Code Knowledge Graph capability. Callers pass a host-resolved project reference through MiniAppCodeIntelScope — never a local path — and every result carries a MiniAppCodeIntelProvenance envelope with the project id, graph build revision, source commit, and confidence, with explicit nulls where the rail publishes no value. Index status, semantic/intent/hybrid search, communities, processes, branch diff, impact analysis, coverage, fragility, symbol history, and specialist affinities share the MiniAppCodeIntelApi surface. The host validates project ownership before the first graph read and retries a query if the graph revision changes while it runs. Impact analysis returns one closure per distinct requested symbol or path. Coverage and fragility query every distinct path, while specialist affinity returns the highest score observed for each specialist across all requested symbols.

sdk.workspace lists canonical workspace teams and projects (MiniAppWorkspaceTeam and MiniAppProject) so a package can resolve workspace-, team-, and project-scoped policy without inventing its own organization model.

sdk.tasks.createWithReceipt accepts a stable idempotencyKey and returns a durable MiniAppActionReceipt. Receipt-backed task creation validates the project, channels, and assignees against authoritative workspace data before one atomic task write. The persisted task uses canonical assignee metadata and the validated project and channel identifiers.

sdk.workflows.getRun and sdk.workflows.subscribeRun observe one workflow run as MiniAppWorkflowRun, including status, resolved bounded output, failure detail, and the plot/revision correlation recorded for invokeSaved({ correlation }). A correlation-journal failure after a run starts is logged but does not report the successful start as failed. subscribeRun emits MiniAppWorkflowRunEvent only on real state transitions. Runs are short-lived executors; canonical lifecycle state belongs in the plot.

const codeIntel = sdk.codeIntel;
if (codeIntel) {
  const { provenance, results } = await codeIntel.search({
    projectId: 'proj_1',
    query: 'assurance policy evaluation',
    mode: 'hybrid',
  });
  console.log(provenance.graphBuildRevision, results);
}

const observed = await sdk.workflows.getRun?.({ runId: 'run_1' });
if (observed?.run) {
  console.log(observed.run.status, observed.run.result);
}

Public Export Contract

Every exported name below is public. “Type only” rows have no runtime lifecycle of their own; the linked working example shows where the contract is consumed.

ExportPurposeInputs and resultLifecycle and errorsWorking example
MiniAppChannelDescribes one channel visible to the package session.Contains identity, display, visibility, archive, and timestamp fields.Type only; channel snapshots can become stale and operations can still reject.Channels
CreateChannelOptionsSupplies fields for creating a channel.Accepts a name plus optional workspace, description, project, and visibility; creation returns CreateChannelResult.Type only; the host rejects invalid fields or missing authority.Channels
CreateChannelResultReports the created channel identity.Contains the resulting roomId.Type only; it exists only after a successful create operation.Channels
ListChannelsOptionsSelects the workspace used for channel listing.Accepts an optional workspace ID; listing returns ListChannelsResult.Type only; omitted scope uses the current authorized workspace.Channels
ListChannelsResultReturns visible channels and the applied read mode.Contains rooms and readMode.Type only; results are snapshots and do not grant write access.Channels
SendChannelMessageOptionsDescribes a user-visible channel message write.Accepts channel, content, and optional display or structured fields; returns SendChannelMessageResult.Type only; duplicate IDs, invalid content, or lost authority can reject.Channels
SendChannelMessageResultIdentifies a persisted channel message.Contains server and client message IDs.Type only; returned only after persistence succeeds.Channels
GetChannelAccessOptionsSelects a channel for an access snapshot.Accepts channel and optional workspace IDs; returns GetChannelAccessResult.Type only; access can change immediately after the read.Channels
GetChannelAccessResultDescribes current channel participation and capabilities.Returns archive, participation, capabilities, and optional retained sequence.Type only; callers must still handle operation-level rejection.Channels
GetChannelTimelineOptionsSelects a channel timeline.Accepts channel and optional workspace IDs; returns GetChannelTimelineResult.Type only; unreadable channels reject and retained reads may be bounded.Channels
MiniAppChannelMessageRepresents one opaque host-versioned timeline row.Provides bounded MiniAppJsonValue that callers narrow to a known row shape.Type only; validate every field before rendering or acting on it.Channels
GetChannelTimelineResultReturns a timeline snapshot and sequence.Contains messages and the last visible sequence.Type only; later writes or revocation do not mutate the snapshot.Channels
MiniAppProjectDescribes a project and its channel membership.Contains identity, name, workspace, discovery, and channel lists.Type only; project state can change between calls.Projects
CreateProjectOptionsSupplies fields for creating a project.Accepts a name plus optional identity, workspace, and discovery flag.Type only; invalid identity or missing authority can reject.Projects
CreateProjectResultReports the created project identity.Contains projectId.Type only; returned after successful creation.Projects
GetProjectOptionsSelects a project snapshot.Accepts project and optional workspace IDs; returns GetProjectResult.Type only; an unavailable project produces null rather than authority.Projects
GetProjectResultWraps an optional project snapshot.Contains a MiniAppProject or null.Type only; callers must handle deletion and scope changes.Projects
UpdateProjectOptionsDescribes mutable project fields.Accepts project identity and optional name, discovery, and channel lists.Type only; stale or unauthorized updates reject.Projects
UpdateProjectResultReturns the updated project snapshot.Contains the resulting MiniAppProject.Type only; returned after the host commits the update.Projects
InvokeWorkflowOptionsSupplies an inline workflow and optional payload.Accepts serialized workflow JSON and a typed payload; returns InvokeWorkflowResult.Type only; the optional operation can be absent or reject invalid workflow input.Workflows
MiniAppWorkflowDescribes a saved workflow.Contains identity, name, type, and timestamps.Type only; listed workflows are point-in-time snapshots.Workflows
MiniAppWorkflowRunDescribes one observed workflow run.Contains run and workflow IDs, workspace, status, timing, bounded result, failure, and plot correlation.Type only; run state changes after the read.Generic plot and orchestration primitives
MiniAppWorkflowRunEventReports one run state transition.Contains a MiniAppWorkflowRun and its observation time.Type only; emitted only on real transitions, never on a timer.Generic plot and orchestration primitives
GetWorkflowRunOptionsSelects one workflow run by ID.Accepts a run ID and optional workspace ID; returns GetWorkflowRunResult.Type only; unknown or cross-workspace runs return null.Generic plot and orchestration primitives
GetWorkflowRunResultWraps an optional observed run.Contains a MiniAppWorkflowRun or null.Type only; callers must handle deletion and scope changes.Generic plot and orchestration primitives
MiniAppPlotBackingEnumerates admitted plot backing providers.Accepts managed-artifacts or connected-git; the first admitted backing is the default.Type only; migration is explicit and single-authority.Generic plot and orchestration primitives
MiniAppPlotDescribes one app-defined plot instance.Contains identity, definition ID, backing, head revision, sync state, and timestamps.Type only; head revision moves with every committed write.Generic plot and orchestration primitives
MiniAppPlotSyncStateReports host-observed plot synchronization state.Discriminates clean, syncing, conflicted, migrating, and unavailable states.Type only; state is a snapshot and can change after the read.Generic plot and orchestration primitives
MiniAppPlotEntryDescribes one plot tree entry.Contains path, kind, size, and last-changing revision.Type only; listings are revision-bound snapshots.Generic plot and orchestration primitives
MiniAppPlotFileReturns one plot file body.Contains path, bounded text content, and revision.Type only; binary payloads are out of contract.Generic plot and orchestration primitives
MiniAppPlotRevisionDescribes one immutable plot commit.Contains revision ID, parents, host-stamped actor, time, and message.Type only; history is append-only.Generic plot and orchestration primitives
MiniAppPlotDiffEntryDescribes one changed path in a revision comparison.Contains path, change kind, and optional source path for moves.Type only; compare results are revision-bound.Generic plot and orchestration primitives
MiniAppPlotDiffReturns a revision-to-revision plot comparison.Contains base and head revisions plus changed entries.Type only; the compared revisions must belong to the same plot.Generic plot and orchestration primitives
MiniAppPlotsApiGroups provider-neutral Git-like plot operations.Instance CRUD, file read/list/write/move/delete, compare, history, revision watch, and backing migration.Reserved type vocabulary; the current host does not install this namespace.Generic plot and orchestration primitives
MiniAppArtifactKindEnumerates host artifact contexts.Accepts channel-message, pull-request, task, or repository-issue.Type only; the kind narrows a host-versioned snapshot rather than selecting authority.Artifact context resolution
MiniAppArtifactReferenceIdentifies one host-minted immutable artifact authority.Contains opaque reference and display IDs, kind, workspace, mint time, and expiration time.Short-lived and exact-surface bound; constructing or changing coordinates cannot mint authority.Artifact context resolution
MiniAppResolvedArtifactReturns a permissioned canonical artifact snapshot.Contains the reference, bounded host-versioned snapshot, provenance, and linked plot IDs.Vault misses and authority mismatches return null; invalid requests and permission failures reject.Artifact context resolution
MiniAppArtifactsApiGroups immutable artifact reference resolution.resolve({ reference }) returns { artifact }; its value is a current snapshot or null.Installed on every desktop target; successful use requires the exact surface's artifacts.read grant.Artifact context resolution
MiniAppAttentionKindEnumerates normalized Home attention kinds.Accepts approval, assignment, reassessment, or failure.Type only; the host renders natively from this closed set.Generic plot and orchestration primitives
MiniAppAttentionItemSupplies one revision-bound Home attention item.Contains stable package-scoped ID, kind, title, optional summary, deep link, and optional assignee.Type only; republishing an ID replaces it; arbitrary HTML is never mounted.Generic plot and orchestration primitives
MiniAppHomeApiGroups Home attention projection operations.publishAttention replaces a source-revision projection; clearAttention removes it.Reserved type vocabulary; the current host does not install this namespace.Generic plot and orchestration primitives
MiniAppCodeIntelScopeSelects the project a code knowledge operation reads.Contains a host-resolved projectId and optional workspace ID.Type only; arbitrary filesystem paths are never accepted.Generic plot and orchestration primitives
MiniAppCodeIntelProvenanceStamps every code knowledge result.Contains project ID, graph build revision, source commit, and confidence, each nullable.Type only; missing values read as explicit nulls, never fabricated.Generic plot and orchestration primitives
MiniAppCodeIntelApiGroups read-only repository-scoped Code Knowledge Graph operations.Index status, search, communities, processes, branch diff, impact, coverage, fragility, history, and affinities.Optional per target; payloads are bounded host-versioned JSON the caller narrows.Generic plot and orchestration primitives
MiniAppWorkspaceTeamDescribes one canonical workspace team.Contains team ID, name, and workspace ID.Type only; rosters can change between calls.Generic plot and orchestration primitives
MiniAppUserDescribes the person using this surface.Contains a host-derived user ID and display name.Needs no permission: the mount context already carries the user ID. Display name may be empty on a guest mount.Identity and Workspace
MiniAppUserApiGroups the caller's own identity read.current returns the signed-in user.Feature-detect per host; a package cannot supply or influence the display name.Identity and Workspace
MiniAppWorkspaceProfileDescribes the workspace a surface is mounted in.Contains the workspace ID and display name.Display name falls back to the workspace ID, so it is never empty.Identity and Workspace
MiniAppWorkspaceMemberDescribes one joined workspace member.Contains a user ID and display name, and nothing else.Joined members only; email, role, title, and timezone never cross the boundary.Identity and Workspace
MiniAppWorkspaceApiGroups permissioned workspace scope discovery.listTeams and listProjects return canonical team and project rows.Scope is host-derived; cross-workspace reads return empty rather than leaking.Generic plot and orchestration primitives
MiniAppActionReceiptRecords the durable outcome of one narrow host action.Contains receipt and idempotency IDs, action, status, workspace, host-stamped actor, time, result, and error.Type only; replays of one key return the journaled receipt.Generic plot and orchestration primitives
MiniAppTaskDescribes one workspace task in the host tasks silo.Contains identity, title, status, priority, assignees, workspace, channels, timestamps, and optional due date.Type only; task snapshots can become stale as the silo updates.Tasks
MiniAppTaskAssigneeDescribes one human or specialist assigned to a task.Contains an ID, actor type, display name, and optional avatar or specialist slug.Type only; assignee identity is resolved and stamped by the host.Tasks
MiniAppTaskPriorityEnumerates the supported task priority levels.Accepts low, medium, high, or urgent.Type only; priorities are fixed canonical values.Tasks
MiniAppTaskStatusEnumerates the supported task workflow statuses.Accepts backlog, toDo, inProgress, blocked, or done.Type only; statuses are fixed canonical values.Tasks
MiniAppTasksApiGroups workspace task CRUD and receipt-backed creation.create, update, delete, and list return task results; createWithReceipt returns an action receipt.Feature-detect per host; receipt-backed creation suppresses duplicate idempotency keys.Tasks
CreateTaskOptionsSupplies fields for creating a workspace task.Accepts a title plus optional workspace, description, status, priority, assignees, channels, and due date.Type only; invalid fields or missing authority reject.Tasks
CreateTaskResultReports the created task snapshot.Contains the resulting MiniAppTask.Type only; returned only after a successful create operation.Tasks
UpdateTaskOptionsDescribes mutable task fields for an update.Accepts a task ID plus optional title, description, status, priority, assignees, and nullable due date.Type only; stale or unauthorized updates reject.Tasks
UpdateTaskResultReturns the updated task snapshot.Contains the resulting MiniAppTask.Type only; returned after the host commits the update.Tasks
DeleteTaskOptionsSelects one task to soft-archive.Accepts a task ID plus an optional workspace ID.Type only; unknown tasks or missing authority reject.Tasks
DeleteTaskResultReports the soft-archived task identity.Contains the archived task ID and a constant archived flag.Type only; delete is a soft archive, not a hard removal.Tasks
ListTasksOptionsSelects one page of workspace tasks.Accepts optional workspace, include-archived, limit, and opaque cursor fields.Limit defaults to 25 and accepts 1 through 50; a cursor is bound to the normalized options.Tasks
ListTasksResultReturns one page of visible workspace tasks.Contains a tasks array and an optional opaque nextCursor.Pagination is stable for unchanged data but is not a snapshot across concurrent changes.Tasks
MiniAppIntegrationsApiGroups typed connected-integration actions.createRepositoryIssue and linkRepositoryIssue accept host-resolved repository IDs plus idempotencyKey.Reserved type vocabulary; the current host does not install this namespace.Generic plot and orchestration primitives
ListWorkflowsOptionsSelects the workspace for saved workflows.Accepts an optional workspace ID; returns ListWorkflowsResult.Type only; the host filters by the active package scope.Workflows
ListWorkflowsResultReturns saved workflow summaries.Contains a workflows array.Type only; entries can disappear or become unauthorized later.Workflows
InvokeSavedWorkflowOptionsSelects a saved workflow and payload.Accepts workflow ID and an optional typed payload; returns InvokeWorkflowResult.Type only; missing workflows and rejected payloads report failure or reject.Workflows
InvokeWorkflowResultReports workflow dispatch status.Contains success, status, message, and optional run or error data.Type only; success means accepted execution, not authority for later calls.Workflows
MiniAppMaybePromiseModels APIs that may complete immediately or asynchronously.Wraps one result type as a direct value or promise.Type only; callers should always await host operations to catch rejection.Channels
MiniAppAuthorizationAutonomyNames the authority strength requested by an authorization check.Accepts the canonical listen, plan, or do autonomy value.Type only; the requested value must fit the declared action ceiling and current policy.Authorization checks and consent
MiniAppAuthorizationCheckOptionsSelects one declared action and the autonomy needed by planned work.Contains an actionId and MiniAppAuthorizationAutonomy value.Type only; undeclared actions reject and a valid request can still resolve as denied.Authorization checks and consent
MiniAppAuthorizationCheckResultReports the current authorization decision without executing an action.Contains one boolean allowed snapshot.Type only; authority can change immediately, so the protected operation can still reject.Authorization checks and consent
MiniAppAuthorizationApiExposes read-only introspection for contribution-bound package actions.check accepts MiniAppAuthorizationCheckOptions and resolves to its result.It cannot prompt or mint the call-bound consent required by once or fresh-decision.Authorization checks and consent
MiniAppJsonValueConstrains public configuration and tool data to JSON values.Accepts null, scalar, array, or string-keyed JSON object values.Type only; cyclic, binary, and undefined values are invalid.Specialists
MiniAppHostActionErrorDescribes a bounded host-owned action rejection with a stable code.Extends Error with the canonical name and a non-empty machine-readable code.Type only; callers should handle unknown future codes without parsing message text.Host Action Errors
MiniAppFileErrorCodeEnumerates stable user-selected file failure categories.Covers denied, cancelled, stale, revoked, unavailable, oversized, malformed, encrypted, quota, and unsupported cases.Type only; callers should preserve an unknown-code fallback for later hosts.User-selected Files
MiniAppFileHandleCarries opaque owner-bound authority to one selected file.Contains an ID, optimistic revision, recovery flag, and nullable expiration time.Current hosts issue session-scoped handles; revoke or owner teardown invalidates them.User-selected Files
MiniAppFileMetadataDescribes a selected file without exposing its native path.Contains a host-refreshed handle, basename, safe content fields, byte length, revision, and provenance.Metadata is a snapshot; use its handle for reads at that exact revision.User-selected Files
MiniAppFilePickOpenOptionsConfigures a host-owned Open dialog for explicit file selection.Accepts lowercase MIME or extension filters plus multiple-selection and recovery flags.Picker cancellation rejects, and retained handles are unsupported by current hosts.User-selected Files
MiniAppFilePickSaveOptionsConfigures a host-owned Save dialog for one destination.Requires a suggested name and accepts nullable MIME and recovery options.Picker cancellation rejects, and retained handles are unsupported by current hosts.User-selected Files
MiniAppFileProvenanceIdentifies how the host obtained a selected file authority.Distinguishes user-selected, recovered, workspace, and provider provenance.Type only; provenance is host-owned and callers cannot use it to widen authority.User-selected Files
MiniAppFileReadOptionsBounds one whole-file read and makes it cancellable.Accepts an optional maximum byte count and AbortSignal; the default maximum is 16 MiB.Oversized, revoked, stale, unavailable, or aborted reads reject without returning partial data.User-selected Files
MiniAppFileReadRangeOptionsMakes one bounded range read cancellable.Accepts an optional AbortSignal; offset and length remain explicit method arguments.Type only; invalid ranges and unavailable or revoked handles reject.User-selected Files
MiniAppFileReadStreamOptionsConfigures bounded chunks for a readable file stream.Accepts one-byte through one-MiB chunks and an optional AbortSignal; the default is 256 KiB.Cancelling the stream stops SDK range work without transferring the handle.User-selected Files
MiniAppFileWriteOptionsFences and identifies one atomic logical file write.Requires an observed revision and caller-owned idempotency key, with an optional AbortSignal.Stale revisions or conflicting key reuse reject without replacing the last complete file.User-selected Files
MiniAppFileWriteStreamOptionsConfigures one fenced atomic streaming write.Extends write options with an optional maximum chunk size that defaults to 256 KiB.Invalid or oversized chunks reject, and commit still requires the expected revision.User-selected Files
MiniAppFileWriteReceiptAttests the result of one committed file replacement.Returns the updated handle, revision, content hash, byte length, commit time, and idempotency key.Type only; it is returned or replayed only after the atomic write commits.User-selected Files
MiniAppFileWriteStreamCouples a writable byte stream to its eventual commit receipt.Contains a WritableStream and a receipt promise that resolves after close commits.Abort or failed commit rejects the receipt and preserves the prior complete destination.User-selected Files
MiniAppFileRenameOptionsFences a same-directory basename change.Requires an observed revision and safe new basename, with an optional AbortSignal.Stale revisions, collisions, separators, traversal names, or revoked authority reject without renaming.User-selected Files
MiniAppFileRenameReceiptReports one committed selected-file rename.Returns the refreshed handle, resulting name and revision, and numeric rename time.The prior handle is stale; use the refreshed handle for every later operation.User-selected Files
MiniAppFileDeleteOptionsFences deletion of one selected file.Requires an observed revision and accepts an optional AbortSignal.A stale revision rejects without deleting; success permanently revokes the handle.User-selected Files
MiniAppFileDeleteReceiptReports one committed selected-file deletion.Returns the revoked handle ID, terminal revision, and numeric deletion time.No refreshed handle exists; later operations reject with file_revoked.User-selected Files
MiniAppFileWatchOptionsConfigures one bounded external-revision poll.Requires a previous revision, 0 to 30,000 millisecond wait, and optional AbortSignal.Cancellation rejects; timeout is a successful unchanged receipt.User-selected Files
MiniAppFileWatchReceiptReports the result of one selected-file revision poll.Returns a host-refreshed handle, revision identity, change kind, observation time, and timeout state.Use its handle for the observed revision; call watch again to continue observing changes.User-selected Files
MiniAppFilesApiGroups host-mediated operations for explicit user-selected files.Opens or saves, reads, streams, writes, renames, deletes, watches, revokes, and reserves recovery by opaque handle.Feature-detect on desktop; each authority-bearing operation checks its on-demand action.User-selected Files
MiniAppOpenExternalErrorCodeEnumerates stable failures from desktop external navigation.Includes unsupported host, authorization, gesture, installation, origin, and native-open failures.Type only; callers should still handle unknown future host-action codes.Navigation and feature flags
isMiniAppHostActionErrorNarrows an unknown rejection to MiniAppHostActionError.Accepts an unknown value and returns a type predicate after validating its public shape.It does not enumerate known codes or imply that retrying the failed action is safe.Host Action Errors
MiniAppStorageAddressAddresses one package-owned storage entry.Contains a namespace and key; the host prepends workspace and package identity.Type only; invalid or oversized partitions reject.Namespaced Storage
MiniAppStorageEntryReturns a stored JSON value and optimistic revision.Contains nullable value and revision; both are null for a missing key.Type only; snapshots can become stale immediately.Namespaced Storage
MiniAppStorageSetOptionsCreates or replaces one storage entry.Adds bounded JSON and an exact nullable expected revision to a storage address.Revision mismatch or invalid JSON rejects without overwriting.Namespaced Storage
MiniAppStorageDeleteOptionsDeletes one existing storage entry.Adds a required positive expected revision to a storage address.Missing or stale revisions reject without deleting.Namespaced Storage
MiniAppStorageMutationResultReports the new storage revision.Contains the positive revision produced by set.Type only; use it for the next optimistic mutation.Namespaced Storage
MiniAppStorageApiGroups namespaced get, set, and delete operations.Accepts the storage option types and returns entries, revisions, or void.Every operation is asynchronous and host-authorized.Namespaced Storage
MiniAppEmbeddingModalityEnumerates content kinds accepted by native embedding models.SDK 0.12 accepts the text modality; model entries list their supported modalities.Type only; later hosts may expose a broader catalog through a later SDK contract.Native Embeddings
MiniAppEmbeddingModelCapabilitiesDescribes one embedding model's operational limits and vector shape.Reports modalities, dimensions, batching and input limits, roles, normalization, and background support.Type only; callers must use the capabilities from the selected catalog revision.Native Embeddings
MiniAppEmbeddingModelDescribes one native embedding model.Reports source, exact revision, availability, capabilities, estimates, gating, and license metadata.Discovery metadata can change; existing vector fields remain pinned to their stored binding.Native Embeddings
MiniAppEmbeddingRecommendationReturns one scored model recommendation with human-readable reasons.Contains a complete model entry, numeric score, and ordered explanation strings.Type only; recommendations do not download a model or mutate an existing index.Native Embeddings
MiniAppEmbeddingInputSupplies one bounded item for native embedding computation.SDK 0.12 accepts a tagged text value and a separately selected query or document role.Type only; empty, oversized, or unsupported inputs reject before inference.Native Embeddings
MiniAppEmbeddingVectorCouples numeric vector values to their exact embedding-space binding.Contains a readonly numeric vector, MiniAppEmbeddingSpaceBinding, and host attestation when provenance is verified.Preserve the complete host-generated value; authenticated writes reject altered values or attestations.Native Embeddings
MiniAppEmbeddingSpaceBindingIdentifies one exact compatible vector space.Pins model, immutable revision, dimensions, full fingerprint, and provenance.Equal dimensions do not imply compatibility; zvec rejects a different binding.Native Embeddings
MiniAppEmbeddingsApiDiscovers, recommends, and invokes host-native embeddings.Separates model metadata reads from role-aware text compute.Feature-detect on desktop; every operation is permissioned and SDK-brokered.Native Embeddings
MiniAppPrivateStorageAccessSelects private storage capabilities requested by a contribution.Accepts optional file-read, file-write, SQLite, and zvec booleans; each defaults to enabled.Write access requires read access, and every selected capability still needs a grant.Private Storage
MiniAppPrivateStorageQuotaReports the default and effective private storage quotas.Contains byte counts for the host default and the signed, bounded effective quota.Type only; the host can cap a descriptor request below the requested value.Private Storage
MiniAppPrivateStorageUsageReports route and host-wide private storage use limits.Contains route use, route quota, and the host-wide safety limit in bytes.Usage is a snapshot and can change after another package surface writes.Private Storage
MiniAppPrivateFileMetadataDescribes one private virtual file or directory.Contains the entry kind and plaintext file size; directories report zero bytes.Type only; metadata can become stale and never exposes a physical path.Private Storage
MiniAppPrivateFileEntryDescribes one child in a private virtual directory.Contains a virtual name, entry kind, and physical bytes charged to quota.Type only; directory listings are snapshots and remain package-scoped.Private Storage
MiniAppPrivateFilesApiGroups private virtual file and directory operations.Reads, writes, ranges, streams, directories, listings, metadata, renames, and deletes by virtual path.Operations are bounded, permissioned, quota-checked, and never expose file descriptors.Private Storage
MiniAppSqlValueDefines values accepted by private SQLite statements.Accepts null, finite numbers, bigint, strings, or byte arrays as bound parameters and row values.Type only; callers pass parameters separately from SQL text.Private Storage
MiniAppSqlResultReports the outcome of a private SQLite write.Contains the affected row count and the last inserted row ID.Type only; returned only after the statement succeeds in the current database state.Private Storage
MiniAppSqlQueryResultReturns rows from a private SQLite query.Contains ordered column names and rows of MiniAppSqlValue values.Type only; the result is a point-in-time snapshot of serialized database state.Private Storage
MiniAppSqlMigrationDefines one ordered private SQLite schema migration.Contains a positive contiguous version and the SQL applied after the current version.Migrations reject gaps, forbidden SQL, and any failure without publishing a partial state.Private Storage
MiniAppPrivateSqlTransactionExposes parameterized statements inside one SQLite transaction.execute and query accept SQL plus optional readonly bound values.The transaction commits only when its callback succeeds; failures roll it back.Private Storage
MiniAppPrivateSqlDatabaseRepresents one open private SQLite database.Adds close, transaction, migrate, schema-version, checkpoint, and recovery operations to transaction methods.Serialized operations persist atomic snapshots and reject use after close.Private Storage
MiniAppZvecDocumentSupplies one document to a private zvec collection.Contains a string primary key plus JSON fields; bound vector fields carry MiniAppEmbeddingVector.Every bound vector write must match the collection's exact model-space binding.Private Storage
MiniAppZvecScalarDataTypeEnumerates scalar field encodings supported by the typed zvec schema.Covers binary, string, boolean, numeric, and array scalar forms accepted by the native collection.Type only; unsupported native encodings cannot be smuggled through a free-form schema.Private Storage
MiniAppZvecVectorDataTypeEnumerates dense vector encodings supported by the typed zvec schema.Covers floating-point, binary, and integer vector storage types admitted by the SDK.Type only; the selected encoding must match the supplied vector values and native support.Private Storage
MiniAppZvecMetricEnumerates distance metrics available to typed vector indexes.Accepts L2, inner-product, cosine, or MIPS-to-L2 metric selection.Type only; metric selection is fixed by the collection's index definition.Private Storage
MiniAppZvecScalarIndexDefines an optional typed index for one scalar field.Selects inverted or full-text search with bounded tokenizer and filter options.Type only; arbitrary native index JSON is not accepted by the SDK.Private Storage
MiniAppZvecVectorIndexDefines the native index and metric for one vector field.Selects FLAT, HNSW with optional tuning, or IVF configuration.Type only; index configuration is validated before collection creation.Private Storage
MiniAppZvecScalarFieldDefines one named scalar field in a typed zvec schema.Contains scalar data type, nullability, and an optional scalar index.Type only; field names and index options are bounded and validated.Private Storage
MiniAppZvecVectorFieldDefines one named vector field and its exact embedding space.Contains vector data type, dimensions, nullability, index, and mandatory embedding binding.New vector fields cannot be created without an exact model-space binding.Private Storage
MiniAppZvecSchemaDefines or validates a typed native zvec collection schema.Declares scalar/vector fields, index options, and an exact binding for every new vector field.Required when creating a missing collection; incompatible existing schemas reject.Private Storage
MiniAppZvecFilterValueDefines scalar literal values accepted by the typed zvec filter AST.Accepts boolean, finite number, or string values.Use isNull or isNotNull for null checks; binary values and arbitrary native expressions are excluded.Private Storage
MiniAppZvecFilterDefines a typed recursive scalar filter AST.Supports comparisons, membership, range, conjunction, disjunction, and negation.The SDK serializes the AST; arbitrary native filter strings are not accepted.Private Storage
MiniAppZvecQueryDefines a typed native zvec search request.Accepts field, bound vector, top-k, output fields, filter AST, and include-vector selection.A bound collection requires the exact model/revision/fingerprint on every vector query.Private Storage
MiniAppZvecWriteResultReports one native zvec document write.Contains the primary key, native result code, and bounded result message.Type only; inspect every row because a batch can report document-specific outcomes.Private Storage
MiniAppZvecMutationResultReports a native zvec insert, update, upsert, or delete.Contains per-document write results plus optional affected count and filter-delete marker.Type only; successful mutation still remains subject to route quota enforcement.Private Storage
MiniAppZvecSearchResultReturns one native zvec fetch or search hit.Contains the primary key, score, and requested JSON-compatible document fields.Type only; ordering and scores follow the collection's native index configuration.Private Storage
MiniAppZvecStatsReports native zvec collection size and index readiness.Contains document count, stored bytes, and named index completeness values.Statistics are snapshots; flush returns the state after the requested native flush.Private Storage
MiniAppPrivateZvecCollectionRepresents one open native zvec collection.Inserts, upserts, updates, deletes, queries, fetches, inspects, flushes, and closes package-scoped data.Every operation is permissioned and quota-accounted; calls reject after close.Private Storage
MiniAppPrivateStorageHandleGroups capabilities opened for one private route.Exposes quota, files, SQLite, zvec, usage, and close through opaque package-scoped handles.Close releases the session; physical paths and native database handles are never exposed.Private Storage
MiniAppPrivateStorageApiOpens either the profile or host-stamped current-workspace route.open accepts optional MiniAppPrivateStorageAccess and returns a storage handle.The owning SDK property selects scope; package code cannot supply another workspace.Private Storage
MiniAppRankedItemSupplies one stable identity and value to the rank-fusion utility.Ranked lists contain these items; the result adds a deterministic reciprocal-rank score.Type only; duplicate IDs inside one input list contribute only at their first rank.Private Storage
reciprocalRankFusionCombines caller-owned ranked result lists without taking storage control.Accepts ranked items, optional weights, rank constant, and limit; returns scored items in deterministic order.Pure utility; it performs no host calls and leaves raw SQLite and zvec use available.Private Storage
MiniAppMcpExecutionContextDescribes trusted identity for one package-runtime MCP call.Contains nullable host-stamped channelId and userId; neither value is package input.Type only; the context exists only during the exact invocation and is cleared afterward.Package-runtime MCP context
MiniAppMcpApiExposes package-runtime MCP execution metadata.getExecutionContext returns the call-scoped MiniAppMcpExecutionContext.Feature-detect per realm; use outside an active package MCP invocation rejects.Package-runtime MCP context
MiniAppSessionValueDefines the bounded JSON object stored for one secure session.Accepts string-keyed JSON values that fit within the host session payload limit.Type only; returned session data is readable by package JavaScript.Secure Workspace Installation Session
MiniAppSessionEntryReturns the workspace installation's secure session value.Contains nullable bounded JSON; null means no session exists.The snapshot can become stale and is readable by package JavaScript.Secure Workspace Installation Session
MiniAppSessionApiGroups workspace-installation-scoped get, set, and clear operations.Stores one small JSON object for the active account, workspace, and exact package installation.Keyring-backed, permissioned, release-fenced, and isolated by account and workspace.Secure Workspace Installation Session
MiniAppPresenceAddressAddresses one ephemeral presence room.Contains a namespace and room inside the host-derived workspace/package scope.Type only; it carries no durable or authorization state.Presence
MiniAppPresenceParticipantDescribes one host-stamped participant.Contains participant ID, display name, bounded state, and host timestamp.Type only; entries expire and app state cannot replace identity fields.Presence
MiniAppPresenceSnapshotReports a room's current participant snapshot.Contains address, self participant ID, and participants.Snapshots are ephemeral and can change between callbacks.Presence
MiniAppPresenceUpdateOptionsSupplies bounded app-owned presence state.Adds JSON state to a presence address.Join and update reject invalid, oversized, or unauthorized state.Presence
MiniAppPresenceListenerReceives presence snapshots.Accepts one MiniAppPresenceSnapshot and returns void.Observer failures are isolated; unsubscribe during teardown.Presence
MiniAppPresenceApiGroups join, update, leave, and subscribe operations.Accepts presence addresses/state and returns snapshots, void, or an unsubscribe callback.Presence is ephemeral, host-stamped, and removed with the frame.Presence
MiniAppHttpHeaderInputSupplies one ordered request header.Contains name, value, and an optional enabled flag.Type only; native validation rejects invalid or oversized headers.HTTP and credentials
MiniAppHttpQueryInputSupplies one ordered request query row.Contains name, value, and an optional enabled flag.Type only; native validation rejects invalid or oversized query data.HTTP and credentials
MiniAppHttpRequestInputDescribes one bounded host-mediated request.Accepts method, URL, query, headers, body, timeout, response limit, and redirect policy.Only HTTP(S) is accepted; native limits and origin consent apply.HTTP and credentials
MiniAppHttpRequestOptionsSelects optional host-managed request authentication.Accepts an opaque stored credentialRef or the reserved platform-session reference.Secret material is resolved natively and never returned to JavaScript.HTTP and credentials
MiniAppHttpHeaderDescribes one ordered response header.Contains name and value.Type only; credential-derived material is redacted by the host.HTTP and credentials
MiniAppHttpResponseReturns a bounded native HTTP response.Contains URL, status, headers, text or base64 body, truncation, size, timing, and content type.Invalid host responses reject; credential-backed binary bodies are suppressed.HTTP and credentials
MiniAppHttpCredentialTypeEnumerates supported stored HTTP credential kinds.Bearer, Basic, header-auth, and header/query API-key records are supported.Type only; OAuth and raw keychain reads are excluded.HTTP and credentials
MiniAppHttpCredentialMetadataDescribes one safe stored credential reference.Contains opaque ID, type, display name, and non-secret metadata fields.Metadata can become stale; use is reauthorized at request time.HTTP and credentials
MiniAppHttpApiGroups host-mediated HTTP operations.request accepts a request plus optional opaque credential reference and returns MiniAppHttpResponse.Optional per target; effects, grants, consent, and native bounds apply.HTTP and credentials
MiniAppCredentialsApiGroups metadata-only credential discovery.listHttp returns MiniAppHttpCredentialMetadata[].Optional per target; requires an active workspace, human, effect, and grant.HTTP and credentials
MiniAppUserProfileDescribes host-approved public identity claims.Contains a required subject and optional standard profile fields.Type only; fields can be absent and the profile can become null after account changes.Authentication
MiniAppProvisionProjectChatOptionsSelects a conversation work area to provision.Accepts conversation, project, and optional base and working branches.Type only; invalid scope, branch, or project state can reject.Virtual files
MiniAppProvisionProjectChatResultReports mounted roots and optional worktree metadata.Returns root paths, branch, and base commit fields.Type only; values identify the provisioned conversation realm.Virtual files
MiniAppReceiptDocumentDescribes one bounded semantic version-1 receipt.Contains 1 to 200 semantic lines plus optional bounded feed and cut choices.Type only; malformed, oversized, or unsupported documents reject before spooling.Receipt Printing
MiniAppReceiptLineEnumerates safe semantic receipt rows.Supports text, key-value, divider, and blank rows with bounded text styling.Type only; raw printer commands, markup, and destination data are excluded.Receipt Printing
MiniAppReceiptPaperProfileDescribes one host-supported receipt paper profile.Contains the profile ID, paper width in millimetres, and printable column count.Type only; hosts may change their supported profile set between discovery calls.Receipt Printing
MiniAppReceiptPrintOptionsSupplies a destination, replay key, and semantic receipt for submission.Contains a selected printer/profile, stable jobKey, and MiniAppReceiptDocument.Type only; the host scopes deduplication to installation, workspace, and destination.Receipt Printing
MiniAppReceiptPrintResultReports the host's submission disposition.Returns submitted, duplicate-suppressed, or indeterminate, plus physicalExactlyOnce: false.Physical exactly-once output is impossible to prove after spooler acknowledgement.Receipt Printing
MiniAppReceiptPrinterDescribes one machine-local printer returned by discovery.Contains a bounded printer name and whether the OS marks it as the default destination.Type only; discovery is a snapshot and does not prove that the printer remains ready.Receipt Printing
MiniAppReceiptPrinterDiscoveryReports available printers and host paper capabilities.Returns bounded printer names/default state plus supported width and column profiles.Discovery can become stale; status and submission revalidate the selected destination.Receipt Printing
MiniAppReceiptPrinterProfileEnumerates supported semantic receipt profiles.Accepts receipt-58mm or receipt-80mm as a host rendering profile identifier.Type only; callers should choose only an ID returned by the latest discovery result.Receipt Printing
MiniAppReceiptPrinterSelectionNames the miniapp-selected destination and paper profile.Contains printerName and a supported receipt profile ID.Type only; arbitrary output paths and raw printer commands remain unavailable.Receipt Printing
MiniAppReceiptPrinterStatusReports selected machine-local printer readiness.Returns ready or unavailable for the supplied selection.Type only; a removed printer rejects or reports unavailable instead of being substituted.Receipt Printing
MiniAppReceiptPrintingApiGroups desktop printer discovery, status, and submission.listPrinters discovers capabilities; getStatus and submit accept an explicit selection.Feature-detect per target; exact-frame effects and persisted grants gate every call.Receipt Printing
MiniAppReceiptTextAlignmentEnumerates supported receipt text alignment.Accepts left, center, or right.Type only; the host maps alignment to the selected printer profile.Receipt Printing
MiniAppReceiptTextWeightEnumerates supported receipt text weight.Accepts normal or bold.Type only; the host renders the semantic weight for the destination.Receipt Printing
MiniAppNotificationResultReports whether the host presented an OS notification.Returns shown or suppressed with a stable optional reason.Suppression is final for the call; callers must not loop or prompt for OS permission.OS Notifications
MiniAppNotificationsApiExposes host-mediated OS notification presentation.show accepts only a bounded message and returns MiniAppNotificationResult.Feature-detect per target; the host owns attribution, presentation, policy, and limits.OS Notifications
MiniAppLocalServiceErrorCodeNamespaces known and future local-service failures.Identifies permission, integrity, sandbox, startup, crash-loop, or host failures.Type only; handle unknown future codes as ordinary failures.Local Services
MiniAppLocalServiceKnownErrorCodeEnumerates failures defined by this SDK release.Supports special handling for currently documented local-service failures.Type only; do not assume newer hosts are limited to this set.Local Services
MiniAppLocalServiceRunningDescribes one ready service generation.Contains its contribution ID, opaque generation, and exact loopback origin.Type only; the endpoint belongs to that generation.Local Services
MiniAppLocalServiceStatusReports a declared service's lifecycle state.Discriminates unavailable, stopped, installing, starting, running, and failed.Type only; status can change after the read.Local Services
MiniAppServicesV1ApiGroups service startup and status inspection.ensureRunning returns a ready generation; getStatus returns its status.Desktop only; launch details come from the signed manifest.Local Services
MiniAppServicesApiExposes the versioned service namespace.Contains MiniAppServicesV1Api under the required v1 member.Optional per target; feature-detect before use.Local Services
MiniAppTerminalV1ProfileIdEnumerates the fixed host-owned terminal profiles.Accepts only workspace-shell or neovim.Type only; callers cannot supply arbitrary executables or profiles.Terminal Sessions
MiniAppTerminalV1ProfileDescribes availability for one fixed terminal profile.Contains the profile ID, availability flag, and nullable reason.Type only; availability is metadata and can change with host state.Terminal Sessions
MiniAppTerminalV1LimitsReports the host bounds for terminal sessions and I/O.Contains session, write, output-credit, column, and row limits.Type only; validate operations against the latest capability snapshot.Terminal Sessions
MiniAppTerminalV1CapabilitiesReturns terminal profile availability and current limits.Contains MiniAppTerminalV1Profile[] and MiniAppTerminalV1Limits.Discovery is metadata-only and does not authorize opening a session.Terminal Sessions
MiniAppTerminalV1OpenOptionsSelects a fixed profile and initial terminal dimensions.Contains a profile ID plus bounded cols and rows.Type only; opening rejects unavailable profiles, invalid bounds, or missing grants.Terminal Sessions
MiniAppTerminalV1ResizeOptionsSupplies new dimensions for an open terminal session.Contains bounded cols and rows values.Type only; invalid dimensions or a closed session reject.Terminal Sessions
MiniAppTerminalV1DataEventCarries one ordered chunk of terminal output bytes.Contains a sequence number and non-empty Uint8Array data.Type only; consuming bytes replenishes the host-owned output credit.Terminal Sessions
MiniAppTerminalV1ExitEventReports the final ordered terminal session event.Contains sequence, nullable code and signal, and a stable exit reason.Type only; it is terminal and no data event follows it.Terminal Sessions
MiniAppTerminalV1EventDiscriminates terminal data and exit stream events.Unites MiniAppTerminalV1DataEvent and MiniAppTerminalV1ExitEvent.Type only; narrow on type before reading event-specific fields.Terminal Sessions
MiniAppTerminalV1SessionControls one owner-bound host terminal session.Exposes opaque identity, profile, event stream, write, resize, and close.The host orders operations, applies backpressure, and cleans up on owner retirement.Terminal Sessions
MiniAppTrrScopeSelects the cohort one retention read reports on.Requires a dimension and accepts an optional workspace and non-default horizon in seconds.Type only; the host rejects a dimension it does not offer for the granted permission.Retention Reporting
MiniAppTrrApiGroups the read-only retention reporting operations.getAggregate, getMdTrr, and getEcrt each take a MiniAppTrrScope and resolve with cells plus a state.Always installed; an unsupporting host rejects the call rather than omitting the method.Retention Reporting
MiniAppTerminalV1ApiGroups terminal capability discovery and session opening.getCapabilities returns metadata; open returns a bounded terminal session.Desktop only; feature-detect it and treat unavailable profiles as final.Terminal Sessions
MiniAppTerminalApiExposes the versioned terminal API namespace.Contains the MiniAppTerminalV1Api under the required v1 member.Optional per target; feature-detect before reading the versioned API.Terminal Sessions
MiniAppSpecialistInteractionModeEnumerates supported specialist turn modes.Supplies one documented mode to a turn request.Type only; unsupported modes are rejected before dispatch.Specialists
MiniAppSpecialistSummaryDescribes a specialist visible in the workspace catalog.Contains public identity, presentation, availability, and capability fields.Type only; summaries are scoped snapshots with no machine-local source data.Specialists
MiniAppCreateSpecialistOptionsSupplies a basic specialist definition.Accepts name, domain, nullable description, and JSON configuration.Type only; malformed or unauthorized definitions reject.Specialists
MiniAppCreateSpecialistResultReports the created specialist.Contains identity, display fields, and active state.Type only; returned after successful creation.Specialists
MiniAppManagedSpecialistSupplies a bounded author-controlled specialist manifest.Accepts identity, presentation, and documented optional JSON metadata; host-stamped authority fields are forbidden.Type only; unknown, malformed, or differently owned manifests reject.Specialists
MiniAppManagedSpecialistResultReports the effective managed specialist identity.Contains a required specialistId.Type only; returned after create or reconciliation succeeds.Specialists
MiniAppSpecialistConversationPartModels text, tool, and step-end turn output.Returns discriminated terminal parts with JSON-safe tool data.Type only; validate the type discriminator before reading fields.Specialists
MiniAppSpecialistMessageSnapshotDescribes one canonical full-body specialist stream update.Contains the channel, message, monotonic stream version, and complete replacement body.Type only; versions are scoped per message and zero snapshots is a valid outcome.Specialists
MiniAppSpecialistTurnOptionsDescribes one bounded tool-enabled specialist turn.Accepts workspace, channel, specialist, content, model, mode, null message ID, and timeout.Type only; invalid bounds, access, or unavailable methods reject.Specialists
MiniAppSpecialistTurnObserverReceives observational specialist message snapshots during a turn.Supplies one onSnapshot callback that receives MiniAppSpecialistMessageSnapshot values.Callback failures are isolated and never cancel or change the terminal specialist turn.Specialists
MiniAppSpecialistTurnResultReturns the terminal specialist completion.Contains typed parts plus optional finish reason and model name.Type only; malformed host results reject instead of crossing the public boundary.Specialists
runSpecialistRuns one specialist turn and resolves a discriminated outcome.Handles support detection, failure classification, text extraction, and parsing.Never rejects; an absent capability resolves as unsupported-host.Specialists
RunSpecialistOptionsDescribes one runSpecialist call.Omit channelId to run channel-less in a host-owned room; parse types the result.Type only; workspaceId and modelOverride default to the surface and workspace.Specialists
SpecialistOutcomeDiscriminates a successful turn from a failed one.Success carries parsed data, raw text, and the model used; failure carries a reason.Type only; narrow on ok before reading either side.Specialists
SpecialistFailureCarries a failed turn's reason, user-facing message, and detail.message is safe to show; detail holds the raw answer or host error.Type only; detail is non-secret but not guaranteed friendly.Specialists
SpecialistFailureReasonEnumerates why a turn produced no usable answer.unsupported-host, denied, empty-completion, off-contract, turn-failed.Type only; empty-completion and off-contract have opposite fixes.Specialists
MiniAppAuthApiGroups the optional public profile operation.getUserProfile returns MiniAppUserProfile or null.Feature-detect per realm; account and authorization changes can alter the result.Authentication
MiniAppVfsApiGroups conversation-scoped provision, directory, file writes, and bounded reads.Methods accept relative paths and return typed provision, metadata, directory-entry, or Uint8Array results.Feature-detect per realm; invalid paths, oversized files, and unavailable scope reject.Virtual files
MiniAppVfsStatDescribes one conversation VFS file or directory.Contains file/directory flags, byte size, and timestamps as strings.Type only; paths and host roots stay host-owned.Virtual files
MiniAppVfsEntryDescribes one entry returned by a conversation VFS directory listing.Contains the entry name, file/directory flags, and symlink flag.Type only; paths and host roots stay host-owned.Virtual files
MiniAppGitRuntimeReports which git runtime backs the host git commands.Contains source: embedded or system.Type only; no executable path crosses the boundary.Conversation Git
MiniAppGitRemoteDescribes one configured git remote.Contains the remote name, fetch and push URLs, and default branch.Type only; read the URLs to display remote targets without credentials.Conversation Git
MiniAppGitRepositoryLocationLocates the conversation repository as a checkout or a worktree.localCheckout or localWorktree.Type only; the host resolves the location.Conversation Git
MiniAppGitRepositorySnapshotReports repository state for the conversation's worktree.Contains branch, head, dirty, staged, upstream, and remotes.Type only; no filesystem path is included.Conversation Git
MiniAppGitChangesReports uncommitted-change counters for the worktree.Contains hasUncommittedChanges and dirtyFileCount.Type only; poll or subscribe instead of watching files individually.Conversation Git
MiniAppGitDiffReturns bounded staged and unstaged diffs.Contains path lists, unified diff text, and completeness flags per side.Large repositories can truncate; check the completeness flags.Conversation Git
MiniAppGitInitializeRepositoryResultReports the branch created by repository initialization.Contains the initialized branch name.Type only; initialization refuses an existing repository.Conversation Git
MiniAppGitStageResultReturns the staged content and the review fence for it.Contains the staged diff plus the opaque stagedTree commit requires.Pass the fence to commit unchanged; never send stale content.Conversation Git
MiniAppGitReviewReceiptReturns host-owned approval for one staged tree.Contains the opaque reviewReceipt required by commit.Minted only from a fresh user gesture and explicit host confirmation, and bound to the staged tree.Conversation Git
MiniAppGitCommitResultReports one committed user change.Contains branch, commit SHA, committed paths, and the remote sync guard.Type only; a package commit records no specialist attribution.Conversation Git
MiniAppGitCreateBranchResultReports one created and checked-out branch.Contains the previous branch, the new branch, head, and sync guard.Type only; the previous branch identifies what the conversation moved from.Conversation Git
MiniAppGitPushFailureDescribes one branch that failed to push.Contains source index, branch name, and error.Type only; read error for the recovery path.Conversation Git
MiniAppGitPushResultReports the conversation's pushed branches and failures.Contains pushed branches plus per-source failures and configuration failures.Partial success is possible; report failures individually.Conversation Git
MiniAppGitPullRequestDescribes one pull-request record the host keeps for the conversation.Contains repository, numbers, URLs, branches, SHAs, state, and change counters.Type only; AI attribution counters stay host-side.Conversation Git
MiniAppGitWorktreeDescribes one worktree registered for a project.Contains conversation, project, source, branch, and snapshot fields.Type only; no filesystem path is included.Conversation Git
MiniAppGitOpenPullRequestOptionsDescribes one pull-request creation through connected GitHub authority.Contains title, body, base, optional target selectors, and as: draft or open.Omitted as opens a draft; provider credentials never cross into the package.Conversation Git
MiniAppGitApiGroups conversation-scoped git operations over the review-fenced flow.Read methods report state; stage then commit enforce the review fence; publish methods use host GitHub authority.Desktop only; feature-detect and bind to the mounting conversation.Conversation Git
MiniAppSnapshotStatusReports save-point counters for the conversation.Contains current and total turn counters and canUndo.Type only; canUndo false means no agent turn can rewind.Conversation Snapshots
MiniAppSnapshotHistoryEntryDescribes one specialist-turn save point.Contains sequence, agent, date, changed counts, and current/undone flags.Type only; entries with isUndone no longer match the worktree.Conversation Snapshots
MiniAppSnapshotUndoResultReports one undo of the latest applied turn.Contains success, sequences, and conflicting paths when the worktree moved on.A refused undo is safe; resolve the conflicts before retrying.Conversation Snapshots
MiniAppSnapshotApiGroups conversation save-point history reads and undo.status and history read; undo rewinds the latest applied turn; subscribe reports transitions.Desktop only; the host resolves the conversation's canonical project and rejects a mismatched optional id.Conversation Snapshots
MiniAppInferenceMessageSupplies one role-tagged prompt message.Accepts system, user, or assistant plus non-empty text.Type only; direct inference has no implicit history.Direct inference
MiniAppInferenceModelDescribes one canonical model with an eligible managed route.Contains display metadata, provider IDs, and nullable token limits.Catalog results are snapshots and expose no credentials.Direct inference
MiniAppInferenceRequestDescribes one isolated generation.Requires a conversation, canonical model, and messages; temperature, output limit, and timeout are optional.The host bounds input and clamps model-specific options.Direct inference
MiniAppInferenceUsageReports provider-supplied usage for one generation.Contains nullable input, output, reasoning, cache, total-token, and cost values.Missing provider measurements remain null; they are never estimated.Direct inference
MiniAppInferenceResultReturns one isolated generation and its attribution.Contains text, route, finish reason, usage, latency, retention mode, and turn identity.The response is ephemeral until explicitly written to VFS.Direct inference
MiniAppInferenceApiGroups canonical model discovery and isolated generation.listModels returns eligible models; send returns MiniAppInferenceResult.Feature-detect per realm; both methods require their exact permissions.Direct inference
MiniAppSpecialistApiGroups workspace specialist discovery and actions.Methods return session IDs, public summaries, created specialists, or terminal turns.Feature-detect optional methods; ownership, access, and timeout failures reject.Specialists
MiniAppDeepLinkTargetDescribes a package-owned resource locator that the host can persist.Requires a kind and accepts additional bounded MiniAppJsonValue fields.Type only; the host binds package provenance instead of trusting caller-supplied identity.Package-owned deep links
MiniAppStageDeepLinkOptionsSupplies a display label and package-owned target for chat staging.Contains a label and MiniAppDeepLinkTarget consumed by either staging method.Type only; malformed, unbounded, or unauthorized input rejects before staging.Package-owned deep links
MiniAppStagedDeepLinkIdentifies one package-owned deep link staged for transactional rollback.Contains the opaque host-issued id returned by stageDeepLinkWithRollback.Type only; only the exact owning package surface can use the handle for rollback.Package-owned deep links
MiniAppDeepLinkOpenRequestDelivers one host-routed activation to the owning package surface.Contains an opaque requestId and the sealed MiniAppDeepLinkTarget.Type only; package, release, generation, or surface drift prevents delivery.Package-owned deep links
MiniAppChatApiGroups composer, package deep-link, roster, and archive operations.Accepts text, deep-link targets or handles, and exact resource IDs; returns void, a handle, or null.The base composer method is required; optional methods can be absent or reject.Chat
MiniAppPlatformApiDefines the complete public API installed for a miniapp realm.Groups storage, presence, channels, projects, workflows, inference, navigation, chat, and optional host capabilities.One proxy lives for the module; each property read requires an installed host session.SDK API
OpenNavigationOptionsSupplies a platform-relative navigation path.Accepts one path; navigation resolves without a result.Paths outside the authorized platform route space reject.Navigation and feature flags
OpenExternalNavigationOptionsSupplies one canonical external HTTPS URL for desktop navigation.Accepts one url whose exact origin is declared by the calling contribution.Desktop only; feature-detect and call during a fresh explicit user gesture.Navigation and feature flags
sdkProvides the lazy public API proxy.Exposes MiniAppPlatformApi; operations return the results documented above.Import is safe anywhere; property use before host installation throws.SDK API