Flowhook Android only bitch™

Full Phone Control for Claude Code.

Flowhook gives any authorized caller — a CLI, Claude Code, Codex, or your own script — full adb shell-level control over an Android phone, over the open internet. Install APKs, run shell commands, simulate taps, grab screenshots, read logcat. Works over cell data from anywhere.

Download APK Quickstart For Claude Code GitHub

Open source. Self-hosted. One APK.

What it is, in one paragraph

A small FastAPI server + an Android companion app. The phone dials out to your server and keeps a WebSocket open. The server exposes a REST API. When you (or an agent) hit the API, the command travels down the socket, executes on the phone via Flowhook's own embedded ADB client talking to the phone's adbd on loopback — running as shell user (uid 2000). Everything a wired adb shell can do, Flowhook can do — from any network.

Human quickstart

0. What you need

1. Register and enroll the phone

# from any machine with curl:
export FLOW=https://flowhook.dustforge.com

# register a user (pick your own creds)
USER_TOKEN=$(curl -s -X POST $FLOW/auth/register \
  -H 'Content-Type: application/json' \
  -d '{"username":"youruser","password":"yourpass"}' \
  | python3 -c "import sys,json;print(json.load(sys.stdin)['token'])")

# enroll the phone — returns an agent token
curl -s -X POST $FLOW/devices/enroll \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"name":"my phone"}'

2. Install the APK on the phone

Download Flowhook.apk — sideload it, open the app once. Paste your server URL (wss://flowhook.dustforge.com/agent) and the agent_token from step 1. Tap Save & (re)start service, then Connect ADB. If an "Allow debugging?" dialog appears on the phone, tap Allow (check "Always allow from this computer"). Grant all three "Keep alive" buttons (battery optimization, app info → unrestricted, Samsung Never-sleeping-apps).

3. Run a command

curl -s -X POST $FLOW/exec \
  -H "Authorization: Bearer $USER_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"cmd":"id; getprop ro.product.model"}'

You should see uid=2000(shell) and your phone's model. That's proof-of-life.

The CLI

A one-file Python script wraps the API:

flowhook health                 # server + device status
flowhook devices                # list enrolled phones
flowhook exec 'uptime'          # run shell, stdout to your terminal
flowhook install https://...apk # silent APK install via our ADB bridge
flowhook uninstall com.foo.bar
flowhook screencap out.png
flowhook logcat FlowhookSvc
flowhook audit 50               # last 50 commands

Script: /home/ky/bin/flowhook on the author's box. Reads ~/.flowhook/user_token.

For a Claude Code (or any agent) walkthrough

Paste the block below into a Claude Code session. It's self-contained — enough context for the agent to set up Flowhook for the user from scratch.

You are helping the user set up Flowhook, a remote phone-control tool.

Context:
- Server runs at https://flowhook.dustforge.com (or the user's own deployment).
- The phone side needs the Flowhook APK installed from /app.apk.
- The phone needs ADB-over-network enabled once (adb tcpip 5555 from any computer,
  or Wireless Debugging from Developer Options).
- After setup the user can issue shell commands to the phone over HTTPS.

Do this:

1. Ask the user for a username and password to register on the server.
   Call POST /auth/register with {username, password} as JSON. Save the returned
   `token` to ~/.flowhook/user_token (create the dir). This is the USER token.

2. Ask for a friendly device name ("my phone", "pixel 8", etc).
   Call POST /devices/enroll with Authorization: Bearer <user_token> and
   {"name": ...} as JSON. Save the returned `agent_token` to
   ~/.flowhook/agent_token and `device_id` to ~/.flowhook/device_id.

3. Tell the user to:
   a. Enable Developer Options → USB Debugging on the phone. Plug it into any
      computer once, run `adb tcpip 5555`, then unplug. (This puts adbd in
      network mode so Flowhook can talk to it via loopback.)
   b. Download the APK from https://flowhook.dustforge.com/app.apk and install it.
   c. Open Flowhook. Paste server URL `wss://flowhook.dustforge.com/agent` and
      the agent_token you just saved. Tap "Save & (re)start service".
   d. Tap "Connect ADB". If an "Allow debugging?" dialog appears on the phone,
      tap Allow (check "Always allow from this computer").
   e. Accept the battery-optimization-exemption prompt and enable all three
      "Keep alive" buttons in the Flowhook UI.

4. Verify by calling GET /devices with the user token. The phone should show
   "online": true.

5. Smoke test: POST /exec with {"cmd":"id"}. Output should contain uid=2000(shell).

6. Once it works, explain the CLI (`flowhook exec`, `install`, `screencap`,
   `logcat`, `audit`) and what commands the user might find useful.

Safety: Flowhook has shell-user privileges on the phone. Don't run destructive
commands (rm -rf /data, reboot with unsaved state, etc.) without explicit
user confirmation. Treat it like an adb shell on someone else's device.

API surface (summary)

POST /auth/register
{username, password}{user_id, token}
POST /auth/login
{username, password}{user_id, token}
POST /devices/enroll
auth: user. {name}{device_id, agent_token}
GET /devices
auth: user. → {devices:[{device_id, name, online, last_seen}]}
WS /agent
agent dials out here with {token: agent_token} as first frame
POST /exec
auth: user. {cmd, device_id?, timeout?} → stdout/stderr/exit
POST /install
auth: user. {apk_url, device_id?} → install result
POST /uninstall
auth: user. {package, device_id?}
POST /tap
auth: user. {x, y, device_id?}
POST /text
auth: user. {text, device_id?}
POST /key
auth: user. {keycode, device_id?}
GET /logcat
auth: user. ?tag=&lines=&device_id=
GET /screencap
auth: user. → {png_b64}
GET /audit
auth: user. ?limit= — your command history
GET /health
{status, online_devices}

How it actually works (for the curious)

  1. You register on the Flowhook server; it issues you a JWT user token.
  2. You enroll a phone; it issues a long-lived agent token tied to that phone.
  3. The phone opens a WebSocket to wss://flowhook.dustforge.com/agent, sends the agent token as the first frame.
  4. The server holds that socket open. Outbound-only — no inbound ports needed, carrier NAT irrelevant.
  5. You call a REST endpoint. The server marshals the command to the phone over the socket.
  6. The Flowhook app uses its embedded ADB client (dadb) to talk to the phone's own adbd on loopback, authenticated with an RSA key that Flowhook generated on first launch. adbd executes the command as uid 2000 (shell) — same privileges a USB ADB session has.
  7. Result streams back over the socket to the server, back to your HTTP response.
  8. Every command is logged to the server's audit table.

Limitations & gotchas

Phone reboots turn off ADB-over-network. On reboot, adb tcpip resets. Re-enable once (plug into any computer, adb tcpip 5555, unplug) or use Wireless Debugging. If your phone rarely reboots (always on the charger), you're effectively always-on. The app has a "Recover ADB Bridge" button that can cycle adbd without USB. If that fails, plug in and run adb tcpip 5555 once.

Status

v0.3.11. Works, in daily use. Survives 10+ min screen-off Doze on Samsung S22 over LTE. Rough edges: