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.
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-rebuildon.13. It runs the Hub, MQTT and every service, and/etc/nixoshas uncommitted changes. - adb lives in the user profile (see AGENTS.md §13, Q4), not a system module.
- Bound every adb command with a timeout.