declare type CreateTaskOptions = { workspaceId?: string; title: string; description?: string; status?: MiniAppTaskStatus; priority?: MiniAppTaskPriority; assignees?: MiniAppTaskAssignee[]; channelIds?: string[]; dueDate?: number; }; declare type CreateTaskResult = { task: MiniAppTask; }; declare type DeleteTaskOptions = { workspaceId?: string; taskId: string; }; /** Delete is a soft archive in the tasks silo. */ declare type DeleteTaskResult = { taskId: string; archived: true; }; declare type ListTasksOptions = { workspaceId?: string; includeArchived?: boolean; /** Page size. Defaults to 25 and must be between 1 and 50. */ limit?: number; /** Opaque continuation from the preceding page. */ cursor?: string; }; declare type ListTasksResult = { tasks: MiniAppTask[]; /** Opaque continuation when more tasks are available. */ nextCursor?: string; }; /** Durable outcome of one narrow host action, recoverable after interruption. */ declare type MiniAppActionReceipt = { receiptId: string; /** Caller-supplied stable key; replaying it returns the same receipt. */ idempotencyKey: string; /** Stable host action vocabulary, for example `tasks.create-with-receipt`. */ action: string; status: 'completed' | 'duplicate-suppressed' | 'pending' | 'failed'; workspaceId: string; /** Host-stamped actor identity; never package-supplied. */ actorUserId: string; createdAt: number; /** Action-specific outcome, for example `{ taskId }` or `{ issueUrl }`. */ result: MiniAppJsonValue | null; error: string | null; }; declare type MiniAppCreateSpecialistOptions = { name: string; domain: string; description: string | null; configuration: MiniAppJsonValue; }; declare type MiniAppCreateSpecialistResult = { id: string; name: string; domain: string; description: string | null; isActive: boolean; }; /** JSON-compatible values accepted by public miniapp operations. */ declare type MiniAppJsonValue = null | boolean | number | string | MiniAppJsonValue[] | { [key: string]: MiniAppJsonValue; }; /** * Author-controlled manifest accepted by the host-managed specialist * persistence operation. Ownership, visibility, installation, and verification * metadata are derived by the host and cannot be supplied by a miniapp. */ declare type MiniAppManagedSpecialist = { id: string; slug: string; name: string; publisher: string; description: string; icon: string; category?: string; categoryDisplayName?: string; version?: string; schemaVersion?: string; displayName?: string; maintainers?: Array<{ name: string; email: string; url?: string; }>; license?: string; lastUpdated?: string; fullDescription?: string; knowledgeSources?: MiniAppJsonValue[]; ownedKnowledgePlotId?: string; links?: { terms?: string; privacy?: string; website?: string; }; systemPrompt?: string; prompts?: MiniAppJsonValue; skills?: string[]; tooling?: MiniAppJsonValue; orchestration?: MiniAppJsonValue; taskModels?: Record; knowledgeTargeting?: MiniAppJsonValue; tasks?: MiniAppJsonValue[]; identity?: MiniAppJsonValue; audience?: MiniAppJsonValue; constraints?: MiniAppJsonValue; domainContext?: MiniAppJsonValue; purpose?: string; values?: MiniAppJsonValue[]; attributes?: string[]; techStack?: string[]; writingStyle?: MiniAppJsonValue; tags?: string[]; /** * Legacy singular spelling of the specialist default model. Honored by * the host as `preferredModels: [preferredModel]`; prefer `preferredModels` * for the ordered plural form the manifest consumes. When both are * present, `preferredModels` wins. */ preferredModel?: string; /** Ordered soft model preferences for the specialist's default lane. */ preferredModels?: string[]; supportsLocal?: boolean; requiresNetwork?: boolean; knowledgeGardens?: string[]; }; declare type MiniAppManagedSpecialistResult = { specialistId: string; }; declare type MiniAppMaybePromise = T | Promise; declare type MiniAppProject = { id: string; name: string; workspaceId: string; discoverable: boolean; }; declare type MiniAppSpecialistApi = { joinToChannel(channelId: string, specialistId: string): MiniAppMaybePromise; prepareChannel(options: { channelId: string; workspaceId?: string; specialistIds: readonly string[]; }): MiniAppMaybePromise[]; }>>; listWorkspace(workspaceId: string): MiniAppMaybePromise; create(options: MiniAppCreateSpecialistOptions): MiniAppMaybePromise; upsertManaged?(specialist: MiniAppManagedSpecialist): MiniAppMaybePromise; runTurnWithTools?(options: MiniAppSpecialistTurnOptions): MiniAppMaybePromise; streamTurnWithTools?(options: MiniAppSpecialistTurnOptions, observer: MiniAppSpecialistTurnObserver): MiniAppMaybePromise; }; declare type MiniAppSpecialistConversationPart = { type: 'text'; content: string; } | { type: 'tool'; toolCallId: string; toolName: string; arguments: MiniAppJsonValue; toolIntent: string | null; success: boolean; content: MiniAppJsonValue; mediaCost?: MiniAppJsonValue | null; error?: string | null; executionTimeMs: number; } | { type: 'stepEnd'; iteration: number; }; declare type MiniAppSpecialistInteractionMode = 'conversational' | 'agentic' | 'planning' | 'background' | 'longRunning' | 'inlineEdit' | 'focus'; declare type MiniAppSpecialistMessageSnapshot = Readonly<{ type: 'messageSnapshot'; channelId: string; messageId: string; streamVersion: number; body: string; }>; declare type MiniAppSpecialistSummary = { id: string; slug: string; displayName: string; description: string; tags: string[]; version: string; availability: 'public' | 'internal' | 'private' | 'restricted'; canRunLocally: boolean; category: string; categoryDisplayName: string; requiredCapabilities: { inputModalities: string[]; toolUse?: boolean | null; reasoning?: boolean | null; } | null; omnipresence?: { autoJoinChannels: boolean; includeDms: boolean; pinSidebar: boolean; } | null; displayIcon?: { type: 'bundled'; path: string; } | null; resolvedDisplayIconUrl?: string | null; }; declare type MiniAppSpecialistTurnObserver = Readonly<{ onSnapshot(snapshot: MiniAppSpecialistMessageSnapshot): void; }>; declare type MiniAppSpecialistTurnOptions = { /** Defaults to the surface's own workspace, like the rest of the SDK. */ workspaceId?: string; /** * Channel to run the turn in. * * Omit it to run without a channel. The host then resolves or creates a * **private room** of its own per (workspace, package, specialist) and runs * the turn there, so the turn needs only `specialists.invoke` and never any * `channels.*` permission — the guest neither creates nor joins a channel. * * That room is **persistent and keyed on the same triple**, so repeat calls * continue one conversation rather than starting fresh. This is deliberate: * it is what lets a surface offer regenerate or amend. Do not treat a * channel-less turn as fire-and-forget with no history. */ channelId?: string; /** * Opt in to a dispatched turn, and only meaningful alongside `channelId`. * * The host persists `content` into that channel as an ordinary message and * dispatches through routing, so the **specialist runtime writes the reply * itself**, under the provenance chat requires. The reply lands in the * channel timeline like any other specialist message rather than coming back * to you as loose completion parts, so read it from the timeline — the * returned completion is the turn's own record, not the thing to render. * * 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. * * The specialist must already be seated in the channel; joining one is * `channels.manage-specialists`, a separate grant. * * Omit it (or pass `false`) and a channelled turn stays silent: it commits no * room message and you get the reply only in the result. A channel-less turn * is always dispatched, so this says nothing there. */ dispatch?: boolean; specialistId: string; content: string; /** * Model to run with. Omit or pass `null` to use the workspace's choice, which * is what a surface normally wants — naming a model in app code pins it. */ modelOverride?: null | string; messageId: null; interactionMode: MiniAppSpecialistInteractionMode; timeoutMs: number; }; declare type MiniAppSpecialistTurnResult = { completionEvent: { parts: MiniAppSpecialistConversationPart[]; finishReason?: string; modelUsed?: string; }; }; declare type MiniAppTask = { id: string; title: string; description?: string; status: MiniAppTaskStatus; priority: MiniAppTaskPriority; assignees: MiniAppTaskAssignee[]; workspaceId: string; channelIds: string[]; createdAt: number; updatedAt: number; dueDate?: number; archived: boolean; }; declare type MiniAppTaskAssignee = { id: string; type: 'human' | 'specialist'; name: string; avatar?: string; specialistSlug?: string; }; declare type MiniAppTaskPriority = 'low' | 'medium' | 'high' | 'urgent'; /** Workspace task CRUD plus receipt-backed task creation. */ declare type MiniAppTasksApi = { create(options: CreateTaskOptions): CreateTaskResult | Promise; update(options: UpdateTaskOptions): UpdateTaskResult | Promise; delete(options: DeleteTaskOptions): DeleteTaskResult | Promise; list(options?: ListTasksOptions): ListTasksResult | Promise; /** * Create a task through the durable receipt journal. Replaying one * `idempotencyKey` returns the journaled receipt instead of creating a * second task. */ createWithReceipt(options: { workspaceId?: string; title: string; description?: string; projectId?: string; channelIds?: string[]; assigneeUserIds?: string[]; idempotencyKey: string; }): MiniAppMaybePromise<{ receipt: MiniAppActionReceipt; }>; }; declare type MiniAppTaskStatus = 'backlog' | 'toDo' | 'inProgress' | 'blocked' | 'done'; /** * The person using this surface, as the host knows them. * * Host-derived and not supplyable by a miniapp. Needs no permission and prompts * for nothing: the mount context already carries `userId`, so the name that goes * with that id is not new authority. Anyone *else's* identity is a different * question — it exposes people who never opened this package — and belongs behind * a directory capability with its own grant and consent. */ declare type MiniAppUser = { userId: string; /** * What the host calls this person. Empty when the signed-in profile has no * usable name, which a guest mount can produce — render a fallback rather than * an empty row. */ displayName: string; }; declare type MiniAppUserApi = { current(): MiniAppMaybePromise; }; /** * Permissioned workspace scope discovery so a package can resolve * workspace-, team-, and project-scoped configuration without inventing its * own organization model. */ declare type MiniAppWorkspaceApi = { listTeams(options?: { workspaceId?: string; }): MiniAppMaybePromise<{ teams: MiniAppWorkspaceTeam[]; }>; /** What this workspace is called. Requires `workspace.read`. */ current(options?: { workspaceId?: string; }): MiniAppMaybePromise; /** * The workspace roster. Requires `workspace.read`, the same authority as teams * and projects. */ listMembers(options?: { workspaceId?: string; }): MiniAppMaybePromise<{ members: MiniAppWorkspaceMember[]; }>; listProjects(options?: { workspaceId?: string; }): MiniAppMaybePromise<{ projects: MiniAppProject[]; }>; }; /** * One workspace member, reduced to what a package can justify knowing. * * The host's own roster carries email, role, title, timezone, invitation * timestamps and who invited whom. A miniapp gets a user id and a name: enough to * render a person, and not a workspace's contact list. Only joined members are * listed — an invitation is not a teammate, and pending invites would reveal * hiring before it is announced. */ declare type MiniAppWorkspaceMember = { userId: string; displayName: string; }; /** * The workspace a surface is mounted in. * * `displayName` falls back to the workspace id when the workspace has no name, so * it is never empty — a header reading nothing is worse than one reading something * opaque. */ declare type MiniAppWorkspaceProfile = { workspaceId: string; displayName: string; }; /** One canonical workspace team, as resolved by the host. */ declare type MiniAppWorkspaceTeam = { id: string; name: string; workspaceId: string; }; declare type RunSpecialistOptions = { /** * Defaults to `sdk.specialist`, so most callers omit it. * * Supply it to inject a fake in a test, or to pass a capability you already * hold. Typed as only the method this needs, so a caller that narrowed its own * dependency to `Pick` — the honest * shape for code that runs turns and nothing else — can pass it straight * through. */ specialist?: Pick | undefined; /** Defaults to the surface's own workspace. */ workspaceId?: string; /** * The specialist your package declares, in its resolved `@` * form — for example `standup-drafter@0.2.0`. */ specialistId: string; /** The prompt to send. */ content: string; /** * Channel to run in. **Omit it** to run channel-less: the host uses a private * room it owns for your `(workspace, package, specialist)`, which needs no * `channels.*` permission and never appears in the user's channel list. * * That room is persistent, so repeat calls continue one conversation. This is * what makes a regenerate affordance meaningful — and why a channel-less turn * is not fire-and-forget. */ channelId?: string; interactionMode?: MiniAppSpecialistInteractionMode; /** * Model to run with. Omit to use the workspace's choice, which is normally what * a surface wants — naming a model in app code pins it. */ modelOverride?: null | string; /** Host-enforced range is 1–90000 ms. Defaults to 60000. */ timeoutMs?: number; /** * Turn the answer text into your own type. * * Return `undefined` to reject the answer as `off-contract`. Omit `parse` and * the data is the raw text. */ /** * Turn the answer text into your type. Return `null` or `undefined` to reject * it as `off-contract`. * * Both rejection values are accepted because a parser returning `T | null` is * the common convention — a Zod-backed one especially — and demanding * `undefined` would make every such call site write `?? undefined`. */ parse?: (text: string) => TData | null | undefined; }; /** A failed turn, with copy safe to show and optional non-secret detail. */ export declare type SpecialistFailure = { reason: SpecialistFailureReason; /** One sentence, user-facing. Override it if your product voice differs. */ message: string; /** * Extra context for logs or a details affordance — the raw answer for * `off-contract`, the host's error message otherwise. Non-secret, but not * guaranteed to be friendly. */ detail?: string; /** * Stable recovery code from the host, when it set one — e.g. * `package-mcp-activation-required`, which means "activate the package's MCP * server in Settings", not "retry". * * Distinct from `reason`: `reason` is this SDK's enumerated classification, * `code` is the host's own routable identifier passed through untranslated. */ code?: string; }; /** * Why a specialist turn produced no usable answer. * * Each reason maps to a distinct cause, so a surface can say something accurate * instead of collapsing every failure into one retry message. The distinction * that matters most in practice is `empty-completion` (a model or provider * problem) versus `off-contract` (the model answered, but not in the shape the * app asked for) — identical from the outside, opposite fixes. */ export declare type SpecialistFailureReason = /** This host predates `runTurnWithTools`. Nothing to do but update the app. */ 'unsupported-host' /** A required grant is withheld for this workspace. */ | 'denied' /** The turn completed but carried no text at all. */ | 'empty-completion' /** Text came back, but `parse` rejected it. */ | 'off-contract' /** The turn itself failed — a backend, model, or host error. */ | 'turn-failed'; /** Discriminated outcome of one turn. */ export declare type SpecialistOutcome = { ok: true; data: TData; text: string; modelUsed?: string; } | { ok: false; failure: SpecialistFailure; text?: string; }; export declare type SpecialistStatus = /** The host cannot run specialist turns at all. */ 'unsupported' /** Nothing has run yet, or `reset()` was called. */ | 'idle' | 'running' | 'ready' | 'failed'; /** * Derives the public status from support plus stored state. * * Exported for tests: it is the one piece of hook behaviour that is pure, and * asserting it directly avoids a renderer just to check that a failure outranks a * stale answer. */ export declare function specialistStatus(input: { isSupported: boolean; state: { data?: TData; failure?: SpecialistFailure; running: boolean; }; }): SpecialistStatus; export declare type TaskFailure = { reason: TaskFailureReason; /** One sentence, user-facing. */ message: string; /** Host error text, for logs or a details affordance. */ detail?: string; }; /** Why a task read or write failed. */ export declare type TaskFailureReason = /** This host does not expose `sdk.tasks`. */ 'unsupported-host' /** A required grant is withheld for this workspace. */ | 'denied' /** The host rejected the request — validation, missing task, or a backend error. */ | 'request-failed'; declare type UpdateTaskOptions = { workspaceId?: string; taskId: string; title?: string; description?: string; status?: MiniAppTaskStatus; priority?: MiniAppTaskPriority; assignees?: MiniAppTaskAssignee[]; /** Pass `null` to clear the due date. */ dueDate?: number | null; }; declare type UpdateTaskResult = { task: MiniAppTask; }; export declare type UserFailure = { reason: UserFailureReason; /** One sentence, user-facing. */ message: string; /** Host error text, for logs or a details affordance. */ detail?: string; }; /** Why the user could not be read. */ export declare type UserFailureReason = /** This host does not expose `sdk.user`. */ 'unsupported-host' /** The host rejected or could not answer the request. */ | 'request-failed'; /** * Run a turn against one of your package's specialists, with the lifecycle * already handled: support detection, in-flight state, enumerated failures, * answer parsing, and regenerate. * * ```tsx * const turn = useSpecialist({ * specialist: sdk.specialist, * workspaceId, * specialistId: 'standup-drafter@0.2.0', * parse: (text) => Draft.safeParse(JSON.parse(text)).data, * }); * * if (!turn.isSupported) return null; * return ( * <> * * {turn.failure &&

{turn.failure.message}

} * {turn.data && } * * ); * ``` * * 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. */ export declare function useSpecialist(specialistIdOrOptions: string | UseSpecialistOptions): UseSpecialistResult; /** Everything `runSpecialist` takes except the per-run prompt. */ export declare type UseSpecialistOptions = Omit, 'content'>; export declare type UseSpecialistResult = { status: SpecialistStatus; /** `false` when the host cannot run specialist turns. Hide the affordance. */ isSupported: boolean; /** Convenience for disabling a submit control. */ isRunning: boolean; /** The parsed answer, once `status` is `ready`. */ data?: TData; /** The raw answer text, kept even when `parse` rejects it. */ text?: string; failure?: SpecialistFailure; /** The model the host actually used, when it reports one. */ modelUsed?: string; /** The prompt of the most recent run, for display or `regenerate`. */ lastPrompt?: string; /** * Run a turn. * * Resolves with the same outcome it stores, so a caller can act inline without * watching state. While a turn is in flight this is a no-op — repeat * submissions cannot stack up, which matters because the host serializes turns * on one room anyway, so a second click would only queue behind the first. */ run: (prompt: string) => Promise>; /** * Re-run the last prompt. * * Meaningful because a channel-less turn's room persists: the specialist sees * the earlier exchange, so this is "try again, knowing what you just said" * rather than a fresh request. Resolves as a failure before any run. */ regenerate: () => Promise>; /** Back to `idle`, clearing the answer, failure, and last prompt. */ reset: () => void; }; /** * Read and mutate workspace tasks. * * ```tsx * const { data: tasks, isLoading, failure, create } = useTasks(); * * if (failure) return

{failure.message}

; * return ( * <> * {isLoading ? : tasks.map((task) => )} * * * ); * ``` * * 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. */ export declare function useTasks(options?: UseTasksOptions): UseTasksResult; export declare type UseTasksOptions = { /** * Defaults to `sdk.tasks`, so most callers omit it. Supply it to inject a fake * in a test. */ tasks?: MiniAppTasksApi | undefined; /** Defaults to the surface's own workspace when the host supplies one. */ workspaceId?: string; includeArchived?: boolean; /** * Load on mount. Default `true`. Set `false` to defer until `reload()` — for a * panel behind a disclosure, say. */ loadOnMount?: boolean; }; export declare type UseTasksResult = { /** * The loaded collection. * * Named `data` rather than `tasks` so every resource hook returns the same * shape; rename it on destructure where a domain name reads better: * `const { data: tasks } = useTasks()`. */ data: readonly MiniAppTask[]; /** * Finds a loaded item by id, synchronously. * * Deliberately not `get`: there is no by-id read in the tasks API, so this * searches what `data` already holds and costs no request. A hook over a * resource that does have a by-id read (projects, for instance) would expose an * async `get` alongside this. */ find: (taskId: string) => MiniAppTask | undefined; /** `false` when the host does not expose tasks. Hide the affordance. */ isSupported: boolean; /** The first load, for showing a skeleton once. */ isLoading: boolean; /** Any read or write in flight, for disabling controls. */ isBusy: boolean; failure?: TaskFailure; reload: () => Promise; /** * Writes resolve with the affected item — or `undefined`/`false` on failure, * with the cause in `failure`. Each reloads on success rather than patching * local state, so the surface never shows something the host would describe * differently. */ create: (options: Omit) => Promise; update: (options: Omit) => Promise; /** `remove`, not `delete`: `delete` cannot be a destructured identifier. */ remove: (taskId: string) => Promise; }; /** * Reads the signed-in user once on mount. * * Never throws: a host without the capability reports `isSupported: false` and a * failure, so a surface can fall back to something impersonal rather than break. * An identity is not a subscription — it cannot change without a remount — so * this does not poll, and `reload` exists only for the rare caller that wants to * retry a failed first read. */ export declare function useUser(options?: UseUserOptions): UseUserResult; export declare type UseUserOptions = { /** Overrides the installed API. For tests and non-standard hosts. */ user?: MiniAppUserApi | undefined; }; export declare type UseUserResult = { /** The signed-in user, or undefined until the first read resolves. */ user?: MiniAppUser; /** False when this host has no `sdk.user` at all. */ isSupported: boolean; isLoading: boolean; failure?: UserFailure; /** Re-reads. Rarely needed: an identity does not change mid-mount. */ reload: () => Promise; }; /** * Reads the workspace once on mount. * * Never throws: a host without the capability, or a withheld grant, leaves * `workspace` undefined so a caller can fall back to its own title rather than * render an error where a name belongs. A workspace cannot be renamed out from * under a mounted surface often enough to justify polling, so this does not. */ export declare function useWorkspace(options?: UseWorkspaceOptions): UseWorkspaceResult; /** * Reads the roster on mount. * * Never throws. A withheld grant is reported as `denied` rather than as a generic * failure, because those want different words on screen: one is "ask an admin", * the other is "try again". */ export declare function useWorkspaceMembers(options?: UseWorkspaceMembersOptions): UseWorkspaceMembersResult; export declare type UseWorkspaceMembersOptions = { /** Defaults to the mounted workspace. */ workspaceId?: string; /** Overrides the installed API. For tests and non-standard hosts. */ workspace?: MiniAppWorkspaceApi | undefined; /** Skips the read entirely — for a surface that only needs it conditionally. */ enabled?: boolean; }; export declare type UseWorkspaceMembersResult = { members: readonly MiniAppWorkspaceMember[]; /** False when this host has no roster capability at all. */ isSupported: boolean; isLoading: boolean; failure?: WorkspaceMembersFailure; reload: () => Promise; }; export declare type UseWorkspaceOptions = { /** Overrides the installed API. For tests and non-standard hosts. */ workspace?: MiniAppWorkspaceApi | undefined; }; export declare type UseWorkspaceResult = { /** The workspace, or undefined until the first read resolves. */ workspace?: MiniAppWorkspaceProfile; isSupported: boolean; isLoading: boolean; failure?: WorkspaceFailure; reload: () => Promise; }; export declare type WorkspaceFailure = { reason: WorkspaceFailureReason; /** One sentence, user-facing. */ message: string; /** Host error text, for logs or a details affordance. */ detail?: string; }; export declare type WorkspaceFailureReason = /** This host does not expose `sdk.workspace.current`. */ 'unsupported-host' /** `workspace.read` is withheld for this workspace. */ | 'denied' /** The host rejected the request or could not answer it. */ | 'request-failed'; export declare type WorkspaceMembersFailure = { reason: WorkspaceMembersFailureReason; /** One sentence, user-facing. */ message: string; /** Host error text, for logs or a details affordance. */ detail?: string; }; export declare type WorkspaceMembersFailureReason = /** This host does not expose `sdk.workspace.listMembers`. */ 'unsupported-host' /** `workspace.read` is withheld for this workspace. */ | 'denied' /** The host rejected the request or could not answer it. */ | 'request-failed'; export { }