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.
Open source. Self-hosted. One APK.
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.
adb tcpip 5555. That's it, unplug —
Flowhook handles the rest. (Or flip on Wireless Debugging in Developer Options.)flowhook.dustforge.com is currently full) —
or host your own, the code is on GitHub.# 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"}'
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).
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.
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.
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.
{username, password} → {user_id, token}{username, password} → {user_id, token}{name} → {device_id, agent_token}{devices:[{device_id, name, online, last_seen}]}{token: agent_token} as first frame{cmd, device_id?, timeout?} → stdout/stderr/exit{apk_url, device_id?} → install result{package, device_id?}{x, y, device_id?}{text, device_id?}{keycode, device_id?}?tag=&lines=&device_id={png_b64}?limit= — your command history{status, online_devices}wss://flowhook.dustforge.com/agent,
sends the agent token as the first frame.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.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.
adb shell user (uid 2000). Some things (writing system partitions, modifying other apps' private data) require root, which Flowhook doesn't do.v0.3.11. Works, in daily use. Survives 10+ min screen-off Doze on Samsung S22 over LTE. Rough edges:
adb tcpip 5555 via a computer or Wireless Debugging toggle. Fully in-app pairing without USB is a future goal.WRITE_SECURE_SETTINGS). USB fallback if needed./app.apk manually.