Skip to main content
Miniapps let human members and agents put a native, interactive interface in Ando instead of asking people to read a long message or leave the conversation. Use them when a person needs to choose, review, approve, edit a small dataset, or use a connected app through a safe Ando surface. Human and agent MCP connections can use miniapps in four ways when their catalog exposes the miniapps capability and their grants permit the operation: Miniapps do not bypass conversation access, connected-app grants, or human consent. Ando checks the installer, provider account grants, and the miniapp release each time the miniapp runs.

Ask for an answer

Use $ando.question when the next step needs a clear human answer. It requires no installation or workspace command mapping.
  1. Call get_miniapp_command with command: "$ando.question" in the current catalog.
  2. Build inputs_json with a question, options, optional custom answer label, and replyMode.
  3. Send it with send_message.miniapp_command or reply_to_message.miniapp_command.
  4. Wait for the person’s answer before taking the dependent action.
Use a thread reply when the question belongs in an existing discussion. Use a DM when the answer is meant for one person. Do not infer consent from silence. For the full $ando.question contract, see Ask for an explicit answer.

Register a miniapp command

Publishing or installing an app does not register a $command. A workspace admin or owner registers it from the installed app:
  1. Open the installed miniapp and expand Manage app.
  2. Enter a lowercase command such as $approval in Command.
  3. Select Register command, review the app and version, then select Confirm command. If the name is already configured, the confirmation describes replacing its mapping.
  4. Have the agent call get_miniapp_command with command: "$approval" again. Use the returned revision and creation fields when posting it.
Names start with a letter and contain up to 32 lowercase letters, numbers, underscores, or hyphens, excluding the leading $. Built-in $ando.* commands cannot be replaced. The command pins the installed release. Updating the installation does not update its command automatically; register the same name again to adopt the new version. Each use creates a fresh instance, without copying stored records or account grants. Apps requiring external account connections cannot be command templates; use their ordinary installation flow instead. Source-conversation access still applies. If get_miniapp_command reports that a command is unavailable, check that it was registered in the agent’s workspace and has not been disabled. Installing an app alone is not enough. If an agent needs to fill different values for each instance, declare those fields in the manifest’s creation contract.

Create a configured miniapp

A configured miniapp is a named command, such as $poll or $crm, that creates a fresh instance from declared inputs.
  1. Call get_miniapp_command with the configured command name.
  2. Gather only the fields declared by the returned creation contract.
  3. Use send_message or reply_to_message with miniapp_command.
  4. Include an idempotency_key so retries do not create duplicate cards.
In the compact catalog, post through send_message.request. For example, after reading the command’s current revision and input contract:
Use the returned revision, not a hardcoded revision. Thread and direct-message destinations use their advertised kind and destination fields. Posting requires messages:write and access to the destination. Command-specific eligibility checks still apply. Legacy inline miniapp and app_card inputs are not enabled for human connections by this capability. Current compact catalogs do not require a separate client capability opt-in for miniapps. If these fields are absent, check the current identity, catalog version, and scopes, then refresh the host’s tool catalog after a server update. A legacy human catalog does not expose these command fields. Do not substitute a plain text list for a requested interactive tracker. Treat the created miniapp as conversation-scoped. Members who can read and write in that conversation can use the instance, subject to the app’s own permissions and provider grants.

Update an existing miniapp

When the user asks you to change an existing miniapp, update that instance instead of posting a replacement.
  1. Get the installation_id from the existing miniapp URL.
  2. Call get_miniapp_instance to read its current release, generation, scoped records, declared actions, and next_command_id.
  3. Choose one declared action and build input_json from the user’s request and authorized sources.
  4. Call the advertised typed mini_… action using its exact input schema and the returned release, generation, and command identifiers.
  5. Return the same miniapp URL after the update.
Preserve record IDs when editing existing records. Choose new IDs only for new records. If the release or generation changed, reread the instance before retrying.

Publish a reusable miniapp

A published miniapp is a versioned, code-free interface that Ando renders natively. Its manifest connects pages and controls to tools from apps the installer already has permission to use. Publishing creates an immutable release. It does not install the miniapp, connect an account, or grant access to provider data.

Before you publish

You need an authenticated human membership, connected agent, or managed agent with workspace write access, the miniapps:write scope, and the publish_miniapp tool. Human connections do not need an agent installation. The publisher is always the authenticated membership; callers cannot choose another publisher. Before authoring a manifest with provider connections:
  1. Call list_connections to find the intended connected app.
  2. Call list_tools and get_tool_schemas for that connection.
  3. Use the HTTPS server_url returned by list_connections, plus the tool names, argument schemas, and read/write metadata exactly as reported.
The package identity has two constrained fields:

Manifest shape

A version 1 manifest defines connections, operations, pages, and the first page to open. This example renders one provider result as native Ando content:
Connection aliases map to an exact HTTPS MCP serverUrl and a user-facing label. Do not put credentials in the URL. Each operation names its connection, provider tool, read or write effect, accepted input, and the arguments sent to the provider. Page queries may invoke only operations declared as read. A write operation must include confirmation with a title and description so Ando can show the actual action and account before execution. Pages render a native CardDocument version 1. Controls can navigate to another page, update page state, refresh queries, invoke an operation, or run a declared storage action. Expressions may read query results, page input, state, records, and event values with $get; use $map for collections and $op for bounded coalesce, eq, not, concat, or if expressions.

Card blocks

Each block in document.blocks has a unique id and one of these types: Publication rejects any other type and names the valid ones. An entry block sends { "value": ... } as the event to the control registered under its own id. A text_input is one line by default; add "multiline": true for a writing block, where people edit a draft of up to 4,096 characters in place. Return starts a new line, and the submit button (or Cmd/Ctrl+Return on the web) saves it. A record field holds up to 4,096 bytes, so very long non-Latin text may need to be split across fields. Clients released before multiline reject it and any entry value over 2,000 characters. Choose the writing block on { "$get": ["host", "multiline"] }, which a client that draws it sets. For any other client, offer a single-line entry only while the draft is empty, and show a saved draft as text (prefixed, since a text block cannot be blank and a draft may be saved as spaces), so that client neither fails on a long draft nor saves it back shortened. This draft card lets people edit text and save it to shared storage:
The save action belongs to the manifest’s storage definition. It declares input: { "text": { "type": "string" } } and puts the text into a draft collection under the key current.

Preview before publishing

Call publish_miniapp with preview: "{}" to check a manifest and render its entry page without storing anything. The response is the rendered card (preview.page and preview.document) or the reason it would fail, such as an unknown block type or a block whose control is not registered. To render a page that reads data, pass a JSON sample instead of "{}", with records, queries, input, page, or creation inputs; records default to the app’s initial storage.

Publish and install a release

Call publish_miniapp with the package identity and serialized manifest:
visibility defaults to workspace. Use public only when every release of the package should be installable in other workspaces. Visibility is fixed when the package is created; use a new slug to change the audience. The response contains package_id and release_id. To put the app where it was asked for, also pass conversation_id (and thread_root_id to reply in a thread). An app with no provider connections is installed there and its card is posted as you; the response adds installation_id and the card’s url. Publishing the same release to the same place again returns the same card. When the app can be reused, the response also has command with its name (such as /standup) and a status: ready means anyone can post a fresh copy from the composer’s / menu, and admin_can_add means a workspace admin can press Add as /name under the card to make it one. When a managed agent publishes in a turn a workspace admin asked for, the command is added for that admin, so it comes back ready. When the card has no command, the response has command_unavailable instead, saying why: for example, a slug longer than 32 characters or one of Ando’s own command names. An app with connections is not posted, because a person must choose accounts and consent; the response adds install_url for you to share instead. Without a destination, share an installation link in this form:
During installation, a member selects provider accounts and consents to the requested operations. Ando rechecks those grants whenever the miniapp runs. Publication alone is not proof that installation or connection succeeded.

Release updates

  • Reusing the same slug, version, and byte-identical manifest returns the existing release. It is safe to retry after an uncertain response.
  • Reusing a version with different content fails because releases are immutable.
  • Publish a new numeric version for changed content.
  • Existing installations adopt a new release explicitly.
  • Added permissions or changed provider connections require renewed consent.
Optional storage can keep declared shared or per-viewer scalar records. Never store credentials or copy personal provider results into shared storage.