I have two phones, a family phone I help look after, and an AI assistant that lives on my PC. For months, every phone fix went the same way. Claude would tell me what to tap, I’d tap it, I’d read the screen back, and we’d do it again.

That’s backwards. The AI is the one that knows the fix. It should be doing the tapping.

So we set it up so it can. Claude can now reach any of my phones from anywhere, over my private network, after every reboot, and change them for me. It fixes settings, silences noisy notification channels, installs new app builds and takes screenshots. This is how we built it, including the parts that fought back.

The scripts are on GitHub: pueblokc/android-remote-adb-tailscale.

The idea in one paragraph

Android already ships a remote-control protocol: ADB, the Android Debug Bridge. With a cable, adb shell gets you a command line on the phone and adb install pushes apps. Android 11 and newer can also do it over Wi-Fi (“Wireless debugging”). Put the phone on Tailscale, a private mesh VPN, and “over Wi-Fi” becomes “from anywhere, and only for my own devices.” Then the AI on my PC runs adb connect <phone>:5555 and gets to work.

That’s the whole plan. Android had several objections.

Problem 1: the door keeps moving, and it locks behind you

The host holds a cable in a dark alley, confused, while a power-button gremlin yanks the plug out next to a door whose number spins like a slot machine.

Wireless debugging has two habits that make it useless for remote work:

  1. It listens on a random port, a new one each time it turns on. You can’t adb connect to a port you don’t know.
  2. It turns itself off at every reboot. A phone update, a crash, or a dead battery, and your remote access is gone until someone walks over and flips the switch.

The classic workaround is adb tcpip 5555. That tells the phone’s ADB daemon to listen on fixed port 5555 on every network interface, Tailscale included. It works right up until the next reboot, then it’s gone too.

So the job is really: at every boot, put all of this back without a human.

The fix: a three-part relay that runs every boot

A cutaway of a phone: a small robot with a checklist flips a lever, a ball rolls to a terminal, and a gate opens onto a glowing teal tunnel.

No single app could do the whole job, so the work is split three ways:

StepWho does itWhat it does
1Tasker (boot profile)Sets adb_wifi_enabled = 1, which turns Wireless debugging back on
2Termux:Boot running kc-adb-boot.shFinds Wireless debugging’s random port, connects to itself on 127.0.0.1, and runs adb tcpip 5555
3Tailscale as Always-on VPN, plus a small keeper scriptKeeps the phone on the tailnet so <tailscale-ip>:5555 is reachable from my PC

Step 2 is the fun part. The phone runs its own ADB client inside Termux, uses it to talk to its own Wireless-debugging port, and uses that connection to open 5555. The boot script finds the random port through mDNS (adb mdns services). If that comes up empty, it falls back to an nmap scan of ports 30000–49999 on localhost. It retries for about seven minutes, then logs to /sdcard/Download/kc-adb-boot.log so you can see what happened.

Why Tasker and not just Termux?

This is the first trap we hit. Termux can be granted WRITE_SECURE_SETTINGS, and it still can’t flip the Wireless-debugging switch. settings put global adb_wifi_enabled 1 from Termux dies with “Failed transaction”. Tasker’s Custom Setting action does the same write and it works. So Tasker turns the switch on, and Termux does everything else. (The boot script still tries it; you’ll see that “Failed transaction” line in the log, and it’s harmless.)

Why a Tailscale keeper?

The second trap was on the TCL. Its vendor memory manager kills Tailscale in the background, and Android’s Always-on VPN doesn’t bring it back. kc-tailscale-keeper.sh pings Tailscale’s MagicDNS address (100.100.100.100) every 60 seconds. If there’s no answer, it sends Tailscale’s own CONNECT_VPN broadcast. That’s cheap, and it works.

The one thing we deliberately didn’t automate

Android runs none of this until the phone has been unlocked once after a reboot. Before that first unlock, app storage is still encrypted and Termux can’t even start. That’s Android’s security model doing its job, and I’m not going to fight it. After a reboot, someone unlocks the phone once. About a minute later, it’s back on the network.

Setting it up (the short version)

You need USB debugging on once, plus Tailscale, Termux and Termux:Boot (from the same source, F-Droid or GitHub, because they must share a signing key) and Tasker. The README has every command. The outline:

1. Grant permissions from the PC (reversible). Run host/01-grant-permissions.sh <serial>. It grants Termux and Tasker WRITE_SECURE_SETTINGS, whitelists Termux, Termux:Boot, Tailscale and Tasker from battery optimization, and turns off Android’s “phantom process” killer, which otherwise murders long-running Termux jobs.

2. Push the scripts and open port 5555. host/02-push-scripts.sh <serial>.

3. In Termux, run three scripts in order:

bash /sdcard/Download/kc-upg.sh            # full pkg upgrade, ends in UPGDONE
bash /sdcard/Download/kc-adb-setup.sh      # adb + nmap, installs boot script; tap "Always allow"
bash /sdcard/Download/kc-keeper-install.sh # starts the Tailscale keeper

Don’t skip kc-upg.sh. One phone had an older Termux with a half-upgraded package set, and adb refused to run with CANNOT LINK EXECUTABLE ... __hash_memory. A full pkg upgrade fixed it.

4. Build the Tasker profile: Profiles → + → Event → System → Device Boot. New task, add a Custom Setting action: Type Global, Name adb_wifi_enabled, Value 1. Press ▶ to test it, then ✓ to apply. Accepting Tasker’s terms is a human tap. The AI filled in everything else through the UI.

5. Prove it. host/03-reboot-test.sh <serial> <tailscale-ip> turns Wireless debugging off, reboots, and times how long until 5555 answers. On the family Pixel 6 it was back about 60 seconds after unlock, and mDNS found the port on the first try.

Teaching the AI to have gentle hands

A padded robot glove gently taps a phone while a smiling microphone character stays on screen; behind them a clumsy giant robot fist is crossed out. The host holds a sign reading GENTLE HANDS ONLY.

Getting in was half the work. The other half was learning what not to do once we were in.

  • Don’t use uiautomator dump to read the screen. It’s the standard way to get a phone’s UI as XML, and it quietly shuts down every accessibility service while it runs. My dictation app (Wispr Flow) lives on accessibility. After a few dumps in a row its bubble went invisible and untouchable until the app was force-stopped. That whole saga is here. We replaced it with a small helper that asks Android not to suppress accessibility services (FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) and returns the same XML. It made zero disconnects in five-dump bursts. Plain ADB (shell, dumpsys, screencap, input) was never the problem.
  • Don’t launch apps with monkey. It’s the lazy one-liner for “open this app,” and when it exits it turns auto-rotate back on. Use am start -n with the activity from cmd package resolve-activity instead.
  • adb shell input text goes through the phone’s shell. A |, ; or > in the text runs on the phone instead of getting typed. Push a script file and type bash /sdcard/Download/x.sh instead.
  • On Windows Git Bash, /sdcard/... gets rewritten to C:/Program Files/Git/sdcard/.... Set MSYS_NO_PATHCONV=1. This one cost us two wait loops that sat there until they timed out.
  • The AI never types passwords, PINs or one-time codes. It fills in the username and hands me the phone. Terms-of-service checkboxes are a human tap too.
  • If someone is using the phone, wait. Check what’s on screen (dumpsys window | grep mCurrentFocus) before taking over. That matters most on a phone that isn’t yours.

What it’s actually good for

Two phones lie side by side on a dark workbench while a small mechanic robot feeds glowing boxes into both from a conveyor belt; the host holds a tablet showing two green checkmarks.

This is where it pays off. Some things Claude has done on the phones since:

  • Hunted down a “random” sound. A family phone kept playing a “You’ve got mail!” sound at odd times. The AI dumped every notification channel (dumpsys notification --noredact) and matched the custom sound file’s media ID. The culprit was one chat group’s channel, which is why it seemed random: it only played when that group got a message. It swapped the sound, then set nine mail channels and a few chatty apps to silent. It kept a before-and-after record so every change can be undone.
  • Pushes app updates. When I build a new version of one of my own apps, the new build goes onto both phones over ADB in the same step, and it gets checked on both.
  • Keeps my two phones identical. Any setting changed on one gets made on the other, then read back on both. Auto-rotate off, screen timeout, notification rules.
  • Upgrades the plumbing. Termux package upgrades run through the same pushed-script trick, with logs I can read later.
  • Sees what I see. adb exec-out screencap -p gives it a screenshot any time, and that’s always safe.

Security, because this is full control of a phone

ADB is root-adjacent power over the device, so:

  • Never port-forward 5555 on your router. Tailscale is the only way in. The port is reachable only inside my private tailnet.
  • Lock it down with Tailscale ACLs so only the admin PC can reach the phones on 5555.
  • ADB still checks keys. Even on 5555, only computers whose ADB key the phone has approved can connect. Keep ~/.android/adbkey private.
  • Keep secrets human. The AI can do anything I can on the phone, so the things that prove I’m me (passwords, PINs, 2FA codes) stay with me.

The takeaway

The hard part wasn’t “give the AI access.” It was making access boring: it survives reboots, it doesn’t break other apps, and it doesn’t need me to walk over and toggle a switch. Once it’s boring, the AI stops being a phone-support hotline that reads me instructions and starts closing tickets on its own.

Now when something on a phone annoys me, I describe it, and Claude fixes it.

Scripts and full setup: github.com/pueblokc/android-remote-adb-tailscale