No description
Find a file
2026-08-25 08:38:32 +02:00
claude-code adbw: OPUS optimization 2026-08-25 08:38:32 +02:00
scripts adbw: OPUS optimization 2026-08-25 08:38:32 +02:00
README.md adbw: connect over wireless debugging 2026-08-24 11:48:51 +02:00

adb-scripts

Small POSIX shell tools for driving an Android device over adb, written for a Pixel running GrapheneOS but not tied to it.

The scripts

  • adbapps reads and changes app permissions, and can export the lot to JSON to put back after a factory reset
  • adbtext types into whatever field has focus on the device
  • adbw connects over wireless debugging, finding the port over mDNS because it changes every time debugging is switched on

Requirements

  • adb (Arch: android-tools)
  • USB debugging enabled on the device
  • jq, where a script produces or reads JSON
  • avahi and yq, for adbw

Conventions

Every script here follows the same shape:

  • --help prints its own usage; subcommands have their own page where they exist
  • --device <serial> picks the device when more than one is connected; without a serial it lists what is connected and exits
  • Flags have both a short and a long form (-j / --json), except --device, which is long only so that -d stays free for the subcommands
  • Flags may appear anywhere on the command line, before or after the arguments
  • Errors go to stderr, data to stdout, so output can be piped
  • Nothing on the device needs root: only what the system exposes to the shell user. adbw does ask for sudo here, and only to open the firewall

Run any script with --help to see what it does.

Permissions and groups

Settings shows permission groups — Camera, Contacts, Nearby devices — and applies a decision to every permission a group holds. adb works one permission at a time, and the two use different names for the same thing.

Where a name is expected, either form is accepted: CONTACTS acts on the whole group, READ_CONTACTS on that permission alone. A bare name is only ambiguous when it is both a permission and a group of several, and then the fully qualified android.permission.X or android.permission-group.X settles it.

Acting on a single permission leaves its group in a state Settings cannot produce, which is either what you wanted — an app running on the bare minimum — or something left half done.

Wireless debugging

The port changes every time wireless debugging is switched on, and again after pairing, so there is nothing to remember: adbw reads it from the mDNS announcement the device makes. The same goes for the pairing port, which is only announced while the pairing window is open.

Pairing belongs to the machine's adb key, not to the network. It lives in ~/.android/adbkey and adbkey.pub, so copying those two files to another machine carries the pairing with it — and losing them means pairing again.

The six-digit code is never anywhere but the screen: Android delivers it by broadcast to the settings UI and keeps it out of every log and dump. Nor can that screen be opened from adb, since it lives in an activity Settings does not export. So pairing always takes a few taps on the device.

Discovery needs mDNS through the firewall. Where fwctl manages one, adbw opens mdns for the search and takes it back out once connected, keeping the adb port. fw.yaml itself is always put back, so nothing outlives the run and a reboot closes what is left. Any other firewall is left alone: if a search turns up nothing at all, that is the first place to look.

Installing

They live in scripts/ and are self-contained files with no build step: call them from there, or drop them somewhere on $PATH.

The name shown in help messages follows the file, so renaming a script is safe.

Notes

Anything an app keeps in /data/data stays out of reach without root, which is the point of the sandbox. These scripts work with what adb exposes and stop there.