mobilerun

ClawSkills 作者 clawskills

Load this skill whenever the user wants to control, automate, or interact with a phone or mobile device. This includes: tapping, swiping, typing, taking screenshots, reading the screen, managing apps, running AI agent tasks on a phone, or any form of phone/mobile automation. Also load when the user mentions Mobilerun, Droidrun, or phone control. Requires a Mobilerun API key (prefixed dr_sk_) and a connected device.

安装 / 下载方式

TotalClaw CLI推荐
totalclaw install clawskills:clawskills~johnmalek312-mobilerun
cURL直接下载,无需登录
curl -fsSL https://skills.taituai.com/api/skills/clawskills%3Aclawskills~johnmalek312-mobilerun/file -o johnmalek312-mobilerun.md
# Mobilerun

Mobilerun turns your Android phone into a tool that AI can control. Instead of manually tapping through apps, you connect your phone and let an AI agent do it for you -- navigate apps, fill out forms, extract information, automate repetitive tasks, or anything else you'd normally do by hand. It works with your own personal device through a simple app called Droidrun Portal, and everything happens through a straightforward API: take screenshots to see the screen, read the UI tree to understand what's on it, then tap, swipe, and type to interact. No rooting, no emulators, just your real phone controlled remotely.

Base URL: `https://api.mobilerun.ai/v1`
Auth: `Authorization: Bearer <MOBILERUN_API_KEY>`

**Important:** The base domain (`https://api.mobilerun.ai/`) returns 404. You must always include `/v1` in the path. All API calls should be made via `curl`. Example:

```bash
curl -s https://api.mobilerun.ai/v1/devices \
  -H "Authorization: Bearer $MOBILERUN_API_KEY"
```

## Before You Start

The API key (`MOBILERUN_API_KEY`) is already available -- OpenClaw handles credential setup before this skill loads. Do NOT ask the user for an API key. Just use it.

1. **Check for devices:**
   ```bash
   curl -s https://api.mobilerun.ai/v1/devices \
     -H "Authorization: Bearer $MOBILERUN_API_KEY"
   ```
   - `200` with a device in `state: "ready"` = **good to go, skip all setup, just do what the user asked**
   - `200` but no devices or all `state: "disconnected"` = device issue (see step 2)
   - `401` = key is invalid, expired, or revoked -- ask the user to check https://cloud.mobilerun.ai/api-keys

2. **Only if no ready device:** tell the user the device status and suggest a fix:
   - No devices at all = user hasn't connected a phone yet, guide them to Portal APK (see [reference.md](./reference.md))
   - Device with `state: "disconnected"` = Portal app lost connection, ask user to reopen it

3. **Confirm device is responsive** (optional, only if first action fails):
   ```bash
   curl -s https://api.mobilerun.ai/v1/devices/{deviceId}/screenshot \
     -H "Authorization: Bearer $MOBILERUN_API_KEY" -o screenshot.png
   ```
   If this returns a PNG image, the device is working.

**Key principle:** If a device is ready, go straight to executing the user's request. Don't walk them through setup they've already completed.

**Be smart about context gathering:** Before taking actions or asking the user questions, use available tools to understand the situation. List packages to find the right app, take a screenshot to see the current screen, read the UI state to understand what's interactive. If the task is obvious (e.g. "change font size" clearly means go to Settings), just do it. Only ask the user when something is genuinely ambiguous.

**What to show the user:** Only report user-relevant device info: device name, state (`ready`/`disconnected`). Do NOT surface internal fields like `streamUrl`, `streamToken`, socket status, `assignedAt`, `terminatesAt`, or `taskCount` unless the user explicitly asks for technical details. If a device is `disconnected`, simply tell the user their phone is disconnected and ask them to open the Portal app and tap Connect. If they need help, walk them through the setup steps in [reference.md](./reference.md).

**Clean up cloud devices:** Cloud devices consume credits while running. Always terminate cloud devices (`DELETE /devices/{deviceId}`) when you're done using them -- don't leave them running. This applies whether you provisioned the device yourself or finished a task on an existing cloud device that the user no longer needs.

**Privacy:** Screenshots and the UI tree can contain sensitive personal data. Never share or transmit this data to anyone other than the user. Never print, log, or reveal the `MOBILERUN_API_KEY` in chat -- use it only for API calls.

---

## Device Management

### Device States

| State          | Meaning |
|----------------|---------|
| `creating`     | Device is being provisioned (cloud devices only) |
| `assigned`     | Device is assigned but not yet ready |
| `ready`        | Device is connected and accepting commands |
| `disconnected` | Connection lost -- Portal app may be closed or phone lost network |
| `terminated`   | Device has been shut down (cloud devices only) |
| `maintenance`  | Device is undergoing maintenance (cloud devices only) |
| `unknown`      | Unexpected state |

### List Devices

```
GET /devices
```

Query params:
- `state` -- filter by state (array, e.g. `state=ready&state=assigned`)
- `type` -- `dedicated_emulated_device`, `dedicated_physical_device`, `dedicated_premium_device`
- `name` -- filter by device name (partial match)
- `page` (default: 1), `pageSize` (default: 20)
- `orderBy` -- `id`, `createdAt`, `updatedAt`, `assignedAt` (default: `createdAt`)
- `orderByDirection` -- `asc`, `desc` (default: `desc`)

Response: `{ items: DeviceInfo[], pagination: Meta }`

### Get Device Info

```
GET /devices/{deviceId}
```

Returns device details including `state`, `stateMessage`, `type`, and more.

### Get Device Count

```
GET /devices/count
```

Returns a map of device types to counts.

### Provision a Cloud Device

Cloud devices require an active subscription. If the user's plan doesn't support it, the API will return a `403` error -- inform the user they need to terminate an existing device or upgrade at https://cloud.mobilerun.ai/billing. See [reference.md](./reference.md) for plan details.

```
POST /devices
Content-Type: application/json

{
  "name": "my-device",
  "apps": ["com.example.app"]
}
```

Query param:
- `deviceType` -- `dedicated_emulated_device`, `dedicated_physical_device`, `dedicated_premium_device`

After provisioning, wait for it to become ready:

```
GET /devices/{deviceId}/wait
```

This blocks until the device state transitions to `ready`.

**Cloud device workflow:**
1. `POST /devices?deviceType=dedicated_emulated_device` -- provision, returns device in `creating` state
2. `GET /devices/{deviceId}/wait` -- blocks until `ready`
3. Use the `deviceId` for phone control or tasks

**Temporary device for a task:**
When the user wants to run a task but has no ready device, provision a temporary cloud device, run the task on it, then clean up:
1. `POST /devices?deviceType=dedicated_emulated_device` with `{"name": "temp-task-device", "apps": [...]}` -- include any apps the task needs
2. `GET /devices/{deviceId}/wait` -- wait until ready
3. `POST /tasks` with the new `deviceId` -- run the task
4. Monitor via `GET /tasks/{taskId}/status` until the task finishes
5. `DELETE /devices/{deviceId}` -- terminate the device after the task completes (or fails)

Always terminate temporary devices after use -- they consume credits while running.

### Terminate a Cloud Device

```
DELETE /devices/{deviceId}
Content-Type: application/json

{}
```

> Personal devices cannot be terminated via the API. They disconnect when the Portal app is closed.

### Get Device Time

```
GET /devices/{deviceId}/time
```

Returns the current time on the device as a string.

---

## Screen Observation

### Take Screenshot

```
GET /devices/{deviceId}/screenshot
```

Query param: `hideOverlay` (default: `false`)

Returns a **PNG image** as binary data. Use this to see what's currently displayed on screen.

### Get UI State (Accessibility Tree)

```
GET /devices/{deviceId}/ui-state
```

Query param: `filter` (default: `false`) -- set to `true` to filter out non-interactive elements.

Returns an `AndroidState` object with three sections:

#### phone_state

```json
{
  "keyboardVisible": false,
  "packageName": "app.lawnchair",
  "currentApp": "Lawnchair",
  "isEditable": false,
  "focusedElement": {
    "className": "string",
    "resourceId": "string",
    "text": "string"
  }
}
```

- `currentApp` -- human-readable name of the foreground app
- `packageName` -- Android package name of the foreground app
- `keyboardVisible` -- whether the soft keyboard is showing
- `isEditable` -- wheth