> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phoneuse.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Commands

> Every CLI command, its arguments and its options.

The CLI is a thin client over the same control plane the agent surface uses, with 20 commands. It installs from npm as `phonebase`, and the same program runs from a checkout: `corepack pnpm cli <command>` during development, or the `phonebase` entry point after `corepack pnpm build`. See [installation](/cli/installation) for the details.

Bad input never crashes the CLI: it prints the usage block and exits 2, and that includes a flag used on a command that does not read it. `phonebase --help` lists every command; `phonebase <command> --help` prints that one command's arguments, flags and an example. Both come from the same table this page is generated from, so the terminal and this page cannot disagree.

## Commands

| Command | What it does |
| - | - |
| [`apps`](#phonebase-apps) | Inspect phone app inventory, refresh it, and recover an original request. Install approved apps through the managed app store. |
| [`login`](#phonebase-login) | Log in from this terminal: approve the request in the console and the CLI stores a new API key for your organization in the system keychain. Run it again whenever you need a new key. |
| [`whoami`](#phonebase-whoami) | Show the organization, key id, scopes and expiry of the key this CLI sends, and where that key came from. |
| [`logout`](#phonebase-logout) | Revoke the key phonebase login stored and remove it from this machine. A key in PHONEBASE\_API\_KEY is left alone. Keys can also be deleted on the console's Keys page. |
| [`devices`](#phonebase-devices) | List every device your org can see, with its status and capabilities. |
| [`acquire`](#phonebase-acquire) | Claim exclusive use of a device and print the lease it returns. |
| [`renew`](#phonebase-renew) | Push a lease's expiry back before it runs out, keeping the same lease id. A lease that expires mid-session strands whatever you were doing, so renew it rather than acquiring again. |
| [`release`](#phonebase-release) | Give a device back by the lease id acquire returned. |
| [`tap`](#phonebase-tap) | Tap one point on a device. |
| [`swipe`](#phonebase-swipe) | Drag from one point to another on a device: scroll a list, pull a sheet down, page sideways. |
| [`long-press`](#phonebase-long-press) | Press and hold one point on a device, for the context menus and drag handles a tap never opens. |
| [`type`](#phonebase-type) | Type text into whatever input the device has focused. Focus it first: this types, it does not aim. |
| [`key`](#phonebase-key) | Press one of the phone's own keys on a device: home, back, enter, delete, app\_switch, power, volume\_up, volume\_down. |
| [`open`](#phonebase-open) | Launch an app on a device by its OS-level id, instead of tapping through a home screen to find it. |
| [`screenshot`](#phonebase-screenshot) | Capture a device's screen and write the image to a file. |
| [`ui`](#phonebase-ui) | Print the device's UI tree, the text-and-elements view a screenshot cannot give you. The tree goes to stdout and its metadata to stderr, so redirecting the output leaves a clean file. |
| [`doctor`](#phonebase-doctor) | Check this machine: node version, device rows, the credential in use and control-plane reachability. |
| [`rows`](#phonebase-rows) | Read and edit the device rows file a control plane running on this machine serves (a local rig, not the hosted fleet). |
| [`mcp`](#phonebase-mcp) | Serve the MCP tool surface on stdio from this process. |
| [`run`](#phonebase-run) | Start an agent run on a device for one natural-language goal. phonebase drives it for you; with --executor self\_hosted nothing happens on the device until your own worker connects to the run's VisualRemote base url. |

## Global options

These apply wherever they make sense rather than to one command.

| Option | Description |
| - | - |
| `--server <url>` | Control-plane base URL. Default: PHONEBASE\_SERVER if set, else `https://mcp.phonebase.co`. A control plane on this machine is [http://127.0.0.1:8788](http://127.0.0.1:8788) |
| `-h, --help` | Print the usage block and exit 0. |
| `--version` | Print the CLI version and exit 0. |

Authentication: run `phonebase login` once and the CLI stores an API key for that `--server` in the system keychain. `PHONEBASE_API_KEY` overrides the stored key, which is what CI and scripts use; `PHONEBASE_DEV_TOKEN` is sent only to a control plane on your own machine (a loopback `--server`).

## phonebase apps

Inspect phone app inventory, refresh it, and recover an original request. Install approved apps through the managed app store.

```bash theme={null}
phonebase apps library capabilities [--json] [--cursor <value>] [--limit <value>]
phonebase apps library check [packageName] [--json] [--cursor <value>] [--limit <value>] [--device-id <id>] [--scope <value>]
phonebase apps library refresh [packageName] [--json] [--request-id <id>] --targets <value>
phonebase apps library refresh-status <id> [--json]
phonebase apps library refresh-results <id> [--json] [--cursor <value>] [--limit <value>]
phonebase apps library request <id> [--json]
```

**`phonebase apps library capabilities`**

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |
| `--cursor <value>` | no | Opaque page cursor from the same query. |
| `--limit <value>` | no | Page size, 1 to 100. |

```bash theme={null}
phonebase apps library capabilities --json
```

**`phonebase apps library check`**

| Argument | Description |
| - | - |
| `[packageName]` | Optional package filter; omit to inspect all user apps in the selected scope. |

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |
| `--cursor <value>` | no | Opaque page cursor from the same query. |
| `--limit <value>` | no | Page size, 1 to 100. |
| `--device-id <id>` | no | Filter inventory by this visible device. |
| `--scope <value>` | no | Actual scope ID from device capabilities. |

```bash theme={null}
phonebase apps library check --json
```

**`phonebase apps library refresh`**

| Argument | Description |
| - | - |
| `[packageName]` | Optional package filter; omit to inspect all user apps in the selected scope. |

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |
| `--request-id <id>` | no | Stable inventory refresh key. After a lost response, query the original request instead of resubmitting |
| `--targets <value>` | yes | Explicit comma-separated deviceId:scopeId pairs. |

```bash theme={null}
phonebase apps library refresh --targets black-arm-01:user_0 --request-id inventory-42 --json
```

**`phonebase apps library refresh-status`**

| Argument | Description |
| - | - |
| `<id>` | Original refresh or request identifier. |

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase apps library refresh-status original_01 --json
```

**`phonebase apps library refresh-results`**

| Argument | Description |
| - | - |
| `<id>` | Original refresh or request identifier. |

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |
| `--cursor <value>` | no | Opaque page cursor from the same query. |
| `--limit <value>` | no | Page size, 1 to 100. |

```bash theme={null}
phonebase apps library refresh-results original_01 --json
```

**`phonebase apps library request`**

| Argument | Description |
| - | - |
| `<id>` | Original refresh or request identifier. |

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase apps library request original_01 --json
```

## phonebase login

Log in from this terminal: approve the request in the console and the CLI stores a new API key for your organization in the system keychain. Run it again whenever you need a new key.

```bash theme={null}
phonebase login [--no-browser] [--with-key]
```

| Option | Required | Description |
| - | - | - |
| `--no-browser` | no | Print the login page and code without trying to open a browser (also skipped over SSH, in CI and without a terminal) |
| `--with-key` | no | Store an existing API key read from stdin instead of pairing with the console. The server checks it first |

```bash theme={null}
phonebase login
```

## phonebase whoami

Show the organization, key id, scopes and expiry of the key this CLI sends, and where that key came from.

```bash theme={null}
phonebase whoami [--json]
```

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase whoami
```

## phonebase logout

Revoke the key phonebase login stored and remove it from this machine. A key in PHONEBASE\_API\_KEY is left alone. Keys can also be deleted on the console's Keys page.

```bash theme={null}
phonebase logout
```

Takes no arguments or options.

```bash theme={null}
phonebase logout
```

## phonebase devices

List every device your org can see, with its status and capabilities.

```bash theme={null}
phonebase devices [--json]
```

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase devices --json
```

## phonebase acquire

Claim exclusive use of a device and print the lease it returns.

```bash theme={null}
phonebase acquire <deviceId> [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase acquire black-arm-01
```

## phonebase renew

Push a lease's expiry back before it runs out, keeping the same lease id. A lease that expires mid-session strands whatever you were doing, so renew it rather than acquiring again.

```bash theme={null}
phonebase renew <deviceId> [leaseId] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `[leaseId]` | Optional: the lease your organization holds is the one renewed. The renewal returns the same id with a later expiry. |

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase renew black-arm-01
```

## phonebase release

Give a device back by the lease id acquire returned.

```bash theme={null}
phonebase release <deviceId> <leaseId> [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `<leaseId>` | The lease id acquire printed. |

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase release black-arm-01 lease_9f2c8d14
```

## phonebase tap

Tap one point on a device.

```bash theme={null}
phonebase tap <deviceId> <x> <y> [--lease <id>] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `<x>` | Horizontal position in the 0-1000 grid. |
| `<y>` | Vertical position in the 0-1000 grid. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase tap black-arm-01 500 620
```

## phonebase swipe

Drag from one point to another on a device: scroll a list, pull a sheet down, page sideways.

```bash theme={null}
phonebase swipe <deviceId> <fromX> <fromY> <toX> <toY> [--lease <id>] [--duration-ms <ms>] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `<fromX>` | Horizontal position the gesture starts at, in the 0-1000 grid. |
| `<fromY>` | Vertical position the gesture starts at, in the 0-1000 grid. |
| `<toX>` | Horizontal position the gesture ends at, in the 0-1000 grid. |
| `<toY>` | Vertical position the gesture ends at, in the 0-1000 grid. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `--duration-ms <ms>` | no | How long the gesture lasts, in milliseconds, both bounds inclusive: 1-10000 for a swipe, 200-10000 for a long press. Omitting it sends no duration at all, which lets the server pick: a long press holds for 800ms, and a swipe takes the default of whichever backend drives the device. A value outside the range is a usage error and exits 2 without touching the device |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase swipe black-arm-01 500 800 500 200 --duration-ms 400
```

## phonebase long-press

Press and hold one point on a device, for the context menus and drag handles a tap never opens.

```bash theme={null}
phonebase long-press <deviceId> <x> <y> [--lease <id>] [--duration-ms <ms>] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `<x>` | Horizontal position in the 0-1000 grid. |
| `<y>` | Vertical position in the 0-1000 grid. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `--duration-ms <ms>` | no | How long the gesture lasts, in milliseconds, both bounds inclusive: 1-10000 for a swipe, 200-10000 for a long press. Omitting it sends no duration at all, which lets the server pick: a long press holds for 800ms, and a swipe takes the default of whichever backend drives the device. A value outside the range is a usage error and exits 2 without touching the device |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase long-press black-arm-01 500 620 --duration-ms 1200
```

## phonebase type

Type text into whatever input the device has focused. Focus it first: this types, it does not aim.

```bash theme={null}
phonebase type <deviceId> <text...> [--lease <id>] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `<text...>` | The text to type. The whole tail is the text, so a sentence needs no quoting, though the shell still eats its own metacharacters. A backend may refuse characters it cannot inject. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase type black-arm-01 tuesday at four
```

## phonebase key

Press one of the phone's own keys on a device: home, back, enter, delete, app\_switch, power, volume\_up, volume\_down.

```bash theme={null}
phonebase key <deviceId> <key> [--lease <id>] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `<key>` | Which key to press, from the fixed set the whole fleet shares. An unknown name is a usage error naming the set; a known name the device does not support is refused by the device. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase key black-arm-01 back
```

## phonebase open

Launch an app on a device by its OS-level id, instead of tapping through a home screen to find it.

```bash theme={null}
phonebase open <deviceId> <appId> [--lease <id>] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `<appId>` | Android package name or iOS bundle id, e.g. com.android.settings. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase open black-arm-01 com.android.settings
```

## phonebase screenshot

Capture a device's screen and write the image to a file.

```bash theme={null}
phonebase screenshot <deviceId> [--lease <id>] [-o <file>] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `-o, --out <file>` | no | Screenshot output path (default ./screenshot-\<deviceId>-\<timestamp>.\<ext>) |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase screenshot black-arm-01 -o screen.png
```

## phonebase ui

Print the device's UI tree, the text-and-elements view a screenshot cannot give you. The tree goes to stdout and its metadata to stderr, so redirecting the output leaves a clean file.

```bash theme={null}
phonebase ui <deviceId> [--lease <id>] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase ui black-arm-01 > tree.json
```

## phonebase doctor

Check this machine: node version, device rows, the credential in use and control-plane reachability.

```bash theme={null}
phonebase doctor
```

Takes no arguments or options.

```bash theme={null}
phonebase doctor
```

## phonebase rows

Read and edit the device rows file a control plane running on this machine serves (a local rig, not the hosted fleet).

```bash theme={null}
phonebase rows list [--json]
phonebase rows add '<row-json>'
phonebase rows remove <deviceId>
```

**`phonebase rows list`**

| Option | Required | Description |
| - | - | - |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase rows list --json
```

**`phonebase rows add`**

| Argument | Description |
| - | - |
| `'<row-json>'` | One device row as JSON. It is checked against the same rules the control plane applies, so a row the CLI accepts is a row the control plane accepts. |

```bash theme={null}
phonebase rows add '{"deviceId":"black-arm-01","kind":"adb","serial":"emulator-5554"}'
```

**`phonebase rows remove`**

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |

```bash theme={null}
phonebase rows remove black-arm-01
```

## phonebase mcp

Serve the MCP tool surface on stdio from this process.

```bash theme={null}
phonebase mcp --stdio
```

| Option | Required | Description |
| - | - | - |
| `--stdio` | yes | Serve MCP over stdin/stdout. `phonebase mcp` accepts nothing else. |

```bash theme={null}
phonebase mcp --stdio
```

## phonebase run

Start an agent run on a device for one natural-language goal. phonebase drives it for you; with --executor self\_hosted nothing happens on the device until your own worker connects to the run's VisualRemote base url.

```bash theme={null}
phonebase run <deviceId> <goal...> [--lease <id>] [--max-steps N] [--executor phonebase|self_hosted] [--watch] [--json]
```

| Argument | Description |
| - | - |
| `<deviceId>` | Device id, as printed by `phonebase devices`. |
| `<goal...>` | What to accomplish, in plain words. The whole tail is the goal. |

| Option | Required | Description |
| - | - | - |
| `--lease <id>` | no | Optional lease id from acquire. Leave it out: the command acts under the lease your organization holds, and a gesture or run takes the device for you when it holds none |
| `--max-steps <n>` | no | Ceiling on metered steps for a run (capped by the server's own limit) |
| `--executor <who>` | no | Who drives a run: phonebase (runs it for you, no worker url) or self\_hosted (your worker drives it through the url printed once). Default: self\_hosted for an API key, phonebase for a signed-in person |
| `--watch` | no | Poll a run to a terminal state instead of returning its id. From 0.3.0: a self\_hosted run's worker url is printed once, and only to an interactive terminal; with --json or a non-terminal stderr a self\_hosted run is refused or canceled, exit 2. On 0.2.1, an API key without --executor gets a self\_hosted run that --watch leaves queued until its deadline |
| `--json` | no | Print the machine-readable structuredContent instead of a summary |

```bash theme={null}
phonebase run black-arm-01 open settings and report the android version --max-steps 12
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.