Any framework · WSL adb.exe bridge · Rust CLI

Eight fragile steps to reach your phone. Or one.

On WSL, adb can't see your phone. runapk bridges the gap and handles the rest - build, install, launch. One command.

$cargo install runapk
See the difference

The whole bridge-and-deploy dance on the left. One command on the right.

runapk.log
Without runapk 8 steps · flaky
# 1 · install the USB bridge on Windows (admin) PS> winget install usbipd # 2 · find the phone's bus id PS> usbipd list 2-4 18d1:4ee7 Android ADB Interface Not shared # 3 · share + attach the device into WSL (admin) PS> usbipd bind --busid 2-4 PS> usbipd attach --wsl --busid 2-4 error: WSL kernel lacks USB/IP support x # 4 · rebuild the WSL kernel with USBIP + HID... $ make -j8 && sudo make modules_install ...~20 min, then wsl --shutdown # 5 · udev rules so adb can claim the device $ sudo tee /etc/udev/rules.d/51-android.rules $ sudo udevadm control --reload # 6 · point adb at the bridged socket $ export ADB_SERVER_SOCKET=tcp:127.0.0.1:5037 $ adb kill-server && adb start-server # 7 · check the device shows up $ adb devices List of devices attached (empty) retry try again # 8 · ...and only now: build, install, launch $ ./gradlew assembleDebug $ adb install -r app/build/.../app-debug.apk $ adb shell am start -n com.example/.MainActivity
v one command instead v
With runapk 1 command · 15.8s
$ runapk
OKDEVICE_SERIAL (Android device, Android 14, 64%)
··Building MyApp
OKBuilt in 4.6s (11.2 MB)
··Installing…
OKInstalled com.example.myapp
OKcom.example.myapp launched
OKTotal: 15.8s
No usbipd. No kernel rebuild. No udev. No socket juggling. runapk finds adb.exe, converts the paths and recovers ADB on its own.
What it does

One job, done well: get your APK onto the phone, fast.

01

Detects your framework

Flutter, React Native, Expo, Capacitor, Cordova or native Gradle - runapk finds the project, app ID, launch activity and APK, and builds each with the right toolchain.

02

Builds cross-OS from WSL

Drives Windows adb.exe and the flutter/gradlew.bat toolchain from WSL, converts paths, and skips the usbipd, kernel and udev detour.

03

Recovers safely

Restarts wedged ADB and handles safe retries. Reinstall flows that can delete data require explicit approval.

04

Ready for agents

Ships as .agents/skills/runapk with JSON envelopes, NDJSON events, typed errors and documented exit codes.

05

Inspect and drive

Capture screenshots, tap, swipe, stream filtered logs, reverse ports and pull crash traces from the same CLI.

06

One small binary

Rust, no runtime, no background service. Install it once and run it from any Android project.

Built for agents

Readable by humans, parseable by machines.

Add --json to any command and runapk emits stable envelopes; live commands stream NDJSON events, then a final result. Exit codes are stable too, so a caller always knows what happened.

Typed errors for device, ADB bridge, build, install, timeout and remote failures.
Stable exit codes for scripts, CI and coding agents.
Confirmation-required states are explicit before any data-loss reinstall.
Live commands stream NDJSON events, then finish with one result envelope.
$ runapk status --json
{
  "schema": "runapk.result.v1",
  "ok": true,
  "command": "status",
  "project": "/path/to/project",
  "serial": "DEVICE_SERIAL",
  "data": {},
  "error": null
}
FAQ

The questions you're probably about to ask.

Do I still need usbipd, a custom kernel or udev rules?

No. runapk talks to your phone through Windows adb.exe over the WSL-to-Windows bridge, so you skip the whole USB-passthrough detour. Plug the phone into Windows the way you normally would.

How does it know what to build and launch?

It auto-detects the framework (Flutter, React Native, Expo, Capacitor, Cordova or native Gradle) from the project root or its android/ folder, then the application ID, APK and launch activity, and builds each with the right toolchain.

Will it wipe my app data?

Not without asking. Normal installs are incremental; any reinstall flow that could delete data requires explicit approval first.

What happens when ADB wedges?

runapk restarts the ADB server and retries safely, so a stuck daemon doesn't break your deploy loop.

Can I drive it from scripts, CI or a coding agent?

Yes. Add --json for stable result envelopes, live commands stream NDJSON events, errors are typed and exit codes are documented. It also ships as an .agents/skills/runapk skill.

Does it do more than deploy?

Yes - capture screenshots, tap, swipe, stream filtered logs, reverse ports and pull crash traces, all from the same CLI.

How do I install it?

Run cargo install runapk. It's a single Rust binary with no runtime and no background service - install once, run it from any Android project.

Install

Stop fighting the bridge and start shipping.

Cargo, or build from source. No runtime to install.

From crates.io

# requires Rust toolchain
$ cargo install runapk

From source

$ git clone https://github.com/SylvainM98/runapk
$ cd runapk && cargo build --release
$ cp target/release/runapk ~/.local/bin/