Files
artemis_control/docs/phase-1-adb-link.md
Paperclip Builder ecb8dd2c11 docs: record Phase 1 ADB link proof
Capture the commands, evidence and port-discovery method for the proven
wireless ADB link from .13 to the Pixel 8a over Tailscale. Includes the
copied-key rationale (no pairing code) and the moving-port scan.
2026-10-16 11:35:59 +11:00

4.2 KiB

Phase 1 — Prove the ADB link

Status: proven. Originally verified on .13 on 2026-10-16 and re-verified on 2026-10-16 during Phase 2 work.

Phase 1 is the risk phase. Its Definition of Done is: the view tree of a real phone screen is fetched. That is done.


1. What was proven

Item Value
Host .13 (nixos-desktop, LAN 192.168.20.13, tailnet 100.114.62.46)
adb android-tools-36.0.1, installed with nix profile install nixpkgs#android-tools
adb server listening on 127.0.0.1:5037
Trusted key .27's ~/.android/adbkey copied to .13; fingerprint QAAAAOHiKYXfHo1i36gZXZqqoTErVCGXiEGc1Jv9atu+BHbi+JiNmPjQxUML
Device 100.101.49.17:46689 → device product:akita model:Pixel_8a device:akita
View tree adb shell uiautomator dump → 14955 bytes, 42 nodes, all com.tailscale.ipn (first proof)
Screenshot adb exec-out screencap -p → 174977 byte PNG, 1080x2400 (first proof)

The first proof captured the Tailscale app screen. Text and bounds are both present in the dump, so FR-2 (read the screen) and FR-4 (find by text) are viable:

[TextView] samuelrolfe@gmail.com   bounds=[221,155][798,217]
[TextView] Connected               bounds=[221,217][453,277]
[TextView] sams-pixel-8a           bounds=[89,946][431,1022]
[TextView] nixos-desktop           bounds=[89,1145][428,1221]

2. Commands

Run these on .13. Every command is bounded with timeout so nothing can hang.

# tool and server
adb version
ss -ltn | grep 5037

# connect (port changes — see section 4)
adb connect 100.101.49.17:46689
adb devices -l

# read the screen
adb shell uiautomator dump /sdcard/artemis_window_dump.xml
adb exec-out cat /sdcard/artemis_window_dump.xml

# screenshot
adb exec-out screencap -p > shot.png

Expected device line:

100.101.49.17:46689    device product:akita model:Pixel_8a device:akita transport_id:2

3. Why the copied key works, and no pairing code is needed

The phone's ADB trust list is keyed by public key, not by host. A copy of .27's private key is therefore indistinguishable from the original, so the phone already trusts .13. No pairing code and no re-pairing step is required.

adb mdns services is not available in this build (error: unknown host service 'mdns:services'), and mDNS does not cross the tailnet anyway. ADB cannot auto-discover the phone, so Artemis must be told the tailnet address and must discover the port itself.

4. Finding the port when it changes

The wireless-debugging port changes on every phone reboot or toggle of wireless debugging. 36291 and 38989 are dead ports from earlier sessions. Never hardcode the port.

Android opens two TCP ports: a pairing port (which refuses adb connect) and the connect port (which succeeds). On 2026-10-16 the open ports were 38989 (pairing, refused) and 46689 (connect, worked).

Artemis implements the scan in Go:

artemis connect            # scan 30000-65535 on ARTEMIS_PHONE, then adb connect
artemis connect <ip:port>  # connect directly when the port is known

The equivalent scan by hand:

# 1. find open ports in the wireless-debugging range
for p in $(seq 30000 65535); do
  (timeout 1 bash -c "echo > /dev/tcp/100.101.49.17/$p" 2>/dev/null && echo "$p") &
done | sort -n

# 2. try adb connect on each open port; the one that yields "device" wins
adb connect 100.101.49.17:<PORT>
adb devices -l

Or ask Sam to read the port from Settings → System → Developer options → Wireless debugging.

5. Re-verification (2026-10-16, Phase 2 run)

$ adb version
Android Debug Bridge version 1.0.41
Version 36.0.1-android-tools

$ adb devices -l
100.101.49.17:46689    device product:akita model:Pixel_8a device:akita transport_id:2

$ adb exec-out cat /sdcard/artemis_p1.xml | wc -c
64735

The byte count differs from the first proof because the phone was showing Spotify rather than Tailscale. The link, key, device and port all match.

6. Constraints carried forward

  • Never run nixos-rebuild on .13. It runs the Hub, MQTT and every service, and /etc/nixos has uncommitted changes.
  • adb lives in the user profile (see AGENTS.md §13, Q4), not a system module.
  • Bound every adb command with a timeout.