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

# Connect a coding agent

> Give Claude Code, Codex, OpenClaw, OpenCode — or a fleet of your own agents — a cloud phone each.

An agent uses a cloud phone through [phone-harness](https://github.com/ShawnPana/phone-harness): the same open-source harness that drives a phone on your desk, pointed at a phone in the cloud over ADB. There is no separate integration per agent, and the agent never needs your API key.

## Set up the machine the agent runs on

Once per machine — a laptop, a CI runner, a sandbox image. Works on macOS, Linux and Windows.

```bash theme={null}
pip install phone-harness                       # or: uv tool install phone-harness
# adb: brew install android-platform-tools | apt install adb | winget install Google.PlatformTools
phone-harness --doctor android

# let the agent find the helpers (Claude Code shown; Codex: $CODEX_HOME/skills/phone-harness)
mkdir -p ~/.claude/skills/phone-harness
phone-harness skill > ~/.claude/skills/phone-harness/SKILL.md
```

## Sign in once

```bash theme={null}
phone-harness cloud login
```

A code and a URL print and your browser opens. Sign in — or create an account; sign-up is open and new accounts start with \$5 of credit — and approve. The machine is linked to your account from then on; nothing is pasted, and the agent never sees a key.

## Let the agent start the phone

That is the whole setup. The agent starts, drives and stops your phone with three commands, which the skill already teaches it:

```bash theme={null}
phone-harness cloud start      # your own Android, ready in about 15 seconds; opens the live view
phone-harness <<'PY'
open_app("Settings")
print([o["text"] for o in ocr()][:10])
PY
phone-harness cloud stop       # billing stops; the phone is saved for next time
```

`cloud start` connects the phone over ADB and unlocks it itself; every helper then drives it with nothing exported. It is the same phone each time: apps and logins are kept between sessions. `phone-harness cloud` shows what is running and how long is left, `cloud watch` reopens the read-only live view, and `cloud open` opens the dashboard when you want to take the controls yourself — to type a password, say.

## Give the agent this prompt

```text theme={null}
Use phone-harness for everything on the phone. Read `phone-harness skill` first.
Run `phone-harness cloud start` if `phone-harness cloud` shows no phone
attached, then drive it with the helpers:

phone-harness <<'PY'
open_app("Settings")
print([o["text"] for o in ocr()][:10])
PY

Tell me what you are about to do before each script and what you saw after.
Take a screenshot and describe the screen before acting. Ask before sending,
posting, buying or changing settings. Run `phone-harness cloud stop` when
we are done, and tell me if the phone expires.
```

## One phone per agent, programmatically

For an agent service, split the work in two. An **orchestrator** holds an API key and never touches phones:

```bash theme={null}
export API=https://api.phone-harness.com KEY=pck_…
SID=$(curl -sS -X POST $API/sessions -H "Authorization: Bearer $KEY" \
        -H "Content-Type: application/json" -d '{"timeout_seconds": 900}' | jq -r .id)
until [ "$(curl -sS $API/sessions/$SID -H "Authorization: Bearer $KEY" | jq -r .state)" = ready ]; do sleep 5; done
curl -sS $API/sessions/$SID -H "Authorization: Bearer $KEY" | jq .adb
# → {"host":"live.phone-harness.com","port":22220,"code":"ph_…","expires_at":…}
```

Each **agent sandbox** gets only `host`, `port` and `code`, and runs the connection at startup — no account of its own:

```bash theme={null}
adb connect live.phone-harness.com:22220
adb -s live.phone-harness.com:22220 shell unlock ph_…
export ANDROID_SERIAL=live.phone-harness.com:22220
export PHONE_HARNESS_PLATFORM=android          # only needed on a Mac
```

It cannot reach any other phone, spend credit, or end sessions. When the agent finishes — or misbehaves — the orchestrator [resets the code](/docs/api-reference/adb/reset-adb) or [ends the session](/docs/api-reference/sessions/end-session); the phone's own `timeout_seconds` is the backstop. Reconnecting is safe to repeat: after a dropped connection, run `adb connect` and `unlock` again with the current code.

## Notes

* **Serial, not identity.** `live.phone-harness.com:22220` belongs to a phone only while its session lives; the session id is the stable name.
* **Reconnects need `unlock` again.** Every `adb connect` is a new connection; `cloud start` handles this for its own phone.
* **Plaintext.** ADB over TCP is not encrypted; do not send secrets through `adb shell` you would not send in the clear.
* **Appium / uiautomator2 / scrcpy** use the same `host:port` as their serial or `udid` after the unlock.
