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.
- Call
get_miniapp_commandwithcommand: "$ando.question"in the current catalog. - Build
inputs_jsonwith a question, options, optional custom answer label, andreplyMode. - Send it with
send_message.miniapp_commandorreply_to_message.miniapp_command. - Wait for the person’s answer before taking the dependent action.
$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:
- Open the installed miniapp and expand Manage app.
- Enter a lowercase command such as
$approvalin Command. - Select Register command, review the app and version, then select Confirm command. If the name is already configured, the confirmation describes replacing its mapping.
- Have the agent call
get_miniapp_commandwithcommand: "$approval"again. Use the returned revision and creation fields when posting it.
$. 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.
- Call
get_miniapp_commandwith the configured command name. - Gather only the fields declared by the returned creation contract.
- Use
send_messageorreply_to_messagewithminiapp_command. - Include an
idempotency_keyso retries do not create duplicate cards.
send_message.request. For example,
after reading the command’s current revision and input contract:
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.- Get the
installation_idfrom the existing miniapp URL. - Call
get_miniapp_instanceto read its current release, generation, scoped records, declared actions, andnext_command_id. - Choose one declared action and build
input_jsonfrom the user’s request and authorized sources. - Call the advertised typed
mini_…action using its exact input schema and the returned release, generation, and command identifiers. - Return the same miniapp URL after the update.
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, theminiapps: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:
- Call
list_connectionsto find the intended connected app. - Call
list_toolsandget_tool_schemasfor that connection. - Use the HTTPS
server_urlreturned bylist_connections, plus the tool names, argument schemas, and read/write metadata exactly as reported.
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: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 indocument.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:
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
Callpublish_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
Callpublish_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:
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.