Skip to main content
The Mobilerun Assistant skill teaches an AI agent to hold a conversation with the Mobilerun virtual assistant (the VA) over the chat API. You talk to the VA the way you’d talk to a person: send it a task, read the streamed reply, and — this is the part that matters — respond when it pauses to ask a human a question or to get sign-off on a sensitive action (human-in-the-loop, or HITL). This skill covers the chat endpoints under /assistant/chat and the client.assistant.conversations.* methods in the TypeScript and Python SDKs.
This is the chat skill. To have an agent directly control a phone (tap, swipe, type), use the OpenClaw · Android control skill instead.

Install

Download the pre-packaged skill and load it into any compatible agent runtime:

mobilerun-assistant.skill

Download the latest release from GitHub
The .skill file is a zip archive containing the SKILL.md knowledge pack. Refer to your agent runtime’s documentation for how to load a .skill file. All the skill needs at runtime is a Mobilerun API key in MOBILERUN_API_KEY (dr_sk_... — create one on the API Keys page).

How a conversation works

A conversation lives in a session (a persistent chat thread with a title). Each message you send starts a turn: the assistant streams back its reasoning, tool calls, and text until the turn settles.
1

Create a session

POST /assistant/chat/sessions with a title. Returns a session id.
2

Send a message and stream the reply

POST /assistant/chat/message with { sessionId, message } and Accept: text/event-stream. Streaming is the only mode that works for long turns or HITL — the buffered JSON mode hard-times-out at 110s.
3

Read the stream until it settles

Handle text deltas and tool parts. The turn ends with a settle signal — completed, error, or an aborted-* reason.
4

Respond to any HITL card

If the assistant raises a question or approval card mid-turn, collect the user’s decision and post it back (see below). The turn resumes once resolved.

Human-in-the-loop (HITL)

Mid-turn, the assistant can pause and ask a human for input. This is the core of the skill — get it right and unattended integrations stay safe.

Question card

Stream part tool-question. The assistant is asking a clarifying question (e.g. “Which of these two restaurants did you mean?”). Answer with POST /assistant/chat/question, or dismiss it with POST /assistant/chat/question/reject.

Approval card

Stream part tool-hitl-approval. The assistant wants to perform a sensitive action (a payment, a deletion) and needs a human sign-off first. Respond with POST /assistant/chat/permission and once, always, or reject.
Both cards move through the same state machine: input-available while the card is open, then output-available (resolved) or output-error once a human responds.
Blocked is not broken. When a card is input-available, the turn is paused waiting for a human — not failed. Keep the stream open, surface the card, collect an explicit decision, and post it back. Do not retry the send (that starts a second turn and returns 409), do not inject an answer as a follow-up chat message, and do not auto-approve an approval card. Use always only when the user explicitly asks for durable approval; reject is the safe default when they decline.

Answer a question

POST /assistant/chat/question with { questionId, answers }. answers is an outer array aligned with the card’s input.questions; each inner array is nonempty and holds {label}, {custom}, or {label, custom} selections. Include an Idempotency-Key header on retries.

Answer an approval

POST /assistant/chat/permission with { permissionId, response }, where response is exactly once | always | reject.

Reconnecting and turn lifecycle

  • Reconnect after a drop: GET /assistant/chat/stream replays the active turn from its start (a pending HITL card comes back on reconnect; 204 if nothing is running), then GET /assistant/chat/messages refetches full history — which also rehydrates any open card.
  • One turn per session: sending while a turn is in flight returns 409. Check turnActive from GET /assistant/chat/messages before sending.
  • Abort: POST /assistant/chat/abort with { sessionId } stops that session’s in-flight turn (idempotent).
  • Stale session: 404 (unknown/archived) or 410 session_machine_replaced (runtime recycled — start a fresh session). 402 means the account is out of credits.

Reference

The downloadable SKILL.md carries the full endpoint table, curl / TypeScript / Python examples for every call, and the complete list of stream settle reasons and pitfalls. For request and response schemas, see the TypeScript and Python SDK types.