dsh-go-plugin-adb: Let the Agent open an adb shell on the phone for itself

Preface

When running DSH on a phone, if an Agent wants to install an App, view logs, or take a screenshot, there are typically two paths: run adb via a computer connected by a data cable, or as a compromise, use accessibility services to click the screen. The former requires an extra machine and a local area network; the latter can only simulate clicks and cannot obtain a real shell.

jminn0/dsh-go-plugin-adb takes the third path: the plugin’s adb client and adbd are both inside the same phone, and the Agent connects to the loopback address 127.0.0.1:5555. No root is required, no computer is needed, and turning off WiFi or enabling flight mode after pairing once does not affect it. Below introduces its connection method, installation steps, one-time pairing process, and the actual capabilities of six tools.

What is this

A DSH plugin maintained by JMINN0, categorized under workflow. It provides a real adb shell for the Agent to execute commands like pm, am, logcat, dumpsys, screencap, etc., on the phone itself, with uid 2000 permissions.

Version 2026.1105.1908 (Year.MonthDay.Hour.Minute format). Verification environment is nubia REDMAGIC NX809J / Android 16 (SDK 36) / adb 34.0.4 / DSH 0.2.2-rc.1. README marks stability 10/10, tools definition 6/6. It is a pure ESM JS plugin with no build steps and no npm install.

Key Point: Port is still 5555, just address changed to loopback

This point is worth clarifying first, as it can be confused with conventional adb usage. The port has not changed, it is still 5555; what changed is “which address to connect to” — conventional practice connects to a LAN IP, this plugin connects to 127.0.0.1, and traffic goes through the loopback network card.

The results:

  • Turning off WiFi or enabling flight mode will not disconnect;
  • Does not rely on a router, nor does it require the phone and other devices to be on the same LAN;
  • Other machines theoretically in the same LAN can also connect to this port, but still require holding the local adb private key to enter.

After adb tcpip, adbd listens to the entire network stack, making local connection to loopback feasible. However, this step restarts adbd and kicks out other clients like Shizuku, so the plugin itself does not execute it (see pairing section below for details).

Prerequisites and Installation

DSH Go runs in proot Ubuntu inside the phone, and plugin-related commands are executed there, not on the computer. First, confirm a few things:

  1. An Android phone with Developer Options enabled;
  2. Wireless debugging is available (used for one-time pairing);
  3. The phone must be connected to WiFi during the first pairing — pairing uses LAN, and is not needed afterwards;
  4. The adb client can be installed in the proot environment:
apt-get update && apt-get install -y android-tools-adb

Verify after installation:

adb version
# Android Debug Bridge version 1.0.41

Note: When upgrading the DSH Go runtime image, packages installed via apt will be lost, and adb needs to be reinstalled.

Where does the package come from

This package is not currently published to the npm registry and only exists in the GitHub repository. dsh plugin add supports both local directories and package names as targets; here we need to use a local directory:

git clone https://github.com/JMINN0/dsh-go-plugin-adb.git
cd dsh-go-plugin-adb
dsh plugin --profile web add .

The . after add represents the current directory; you must enter the repository directory before executing; otherwise, it will report that the package cannot be found.

--profile web cannot be omitted. DSH can have multiple profiles; the one loaded by the phone’s local engine is called web. Installing to the default profile will not cause the phone App to load this plugin.

Need to restart engine after installation

Installation only changes configuration, it does not reload code. In the App: Settings → Engine → Restart Engine.

After restarting, six new adb_* tools will appear in the tool list. Without restarting, the tools will not be visible, which is the easiest step to miss.

Verify installation

# ① Whether this bundle exists in the configuration
python3 -c "
import json
d=json.load(open('$HOME/.dsh/profiles/web/package.json'))
print([b for b in d['dsh']['profile']['bundles'] if 'adb' in b])"
# Expected output: ['dsh-go-plugin-adb']

# ② Whether the engine had a load failure
grep -i "apply failed" ~/.dsh/dsh-app/diagnostics.md 2>/dev/null | grep adb || echo "No load errors ✅"

These two steps only prove the configuration is correct, not that the tools work. The final hurdle is to directly say in the DSH Go chat:

用 adb_devices 看看现在连着哪些设备

Expected return:

127.0.0.1:5555  device

Only seeing this line means it is really installed. If the Agent replies “No such tool”, go back to the step of restarting the engine; if it returns “Cannot connect, tried port”, go back to the pairing flow below.

One-time pairing

This is the standard adb flow, not specific to the plugin. The order is important; skipping steps will result in no devices/emulators found.

  1. On the phone: Developer Options → Wireless Debugging → Pair device using a pairing code. The screen will display the IP:Port for pairing (e.g., 192.168.1.100:37123) and a 6-digit pairing code. Note that the main page of “Wireless Debugging” also has an “IP address and port” (e.g., 192.168.1.100:41000), that port changes every time wireless debugging is opened, and is not the same as the pairing port.

  2. Pair using the pairing port:

adb pair 192.168.1.100:37123
# Enter the 6-digit code when prompted Enter pairing code:
# Successfully paired to ...
  1. Connect to the wireless debug port:
adb connect 192.168.1.100:41000
adb -s 192.168.1.100:41000 shell id
# uid=2000(shell) ...
  1. Finally connect to the loopback, which is the path the plugin defaults to:
adb connect 127.0.0.1:5555
adb -s 127.0.0.1:5555 shell id

After successful pairing, the key is stored in ~/.android/adbkey, and no further pairing is needed afterwards; even if adb is reinstalled, it will not be lost.

Do not use adb tcpip 5555 to fix the port

Early documentation taught this step, but now it is explicitly not to be done. The measured result recorded in the README is: before executing adb tcpip 5555, adbd, shizuku_server, and GKD user services all exist; after executing for 8 seconds, adbd’s PID changes (it restarts), and the service processes for Shizuku and GKD are gone. The reason is that adb tcpip restarts adbd, which is a resource shared by multiple clients — Shizuku is itself a client of adbd in adb mode, and restarting it is equivalent to kicking others offline.

The control group is adb kill-server + start-server, these two operations do not touch adbd. The plugin’s own ensure() also never calls tcpip, it only “piggybacks”: using the currently available connection, or scanning the loopback port to find which port adbd is currently attached to.

How to recover after phone restart

Settings from adb tcpip are not persistent and are lost after a restart, but there is no need to execute it again:

  1. On the phone, confirm that “Wireless Debugging” is on;
  2. The plugin will scan ports to find the connection (scanning 127.0.0.1:30000-50000, about 6 seconds);
  3. If the scan fails, read the number from “IP address and port” on the wireless debugging page and manually adb connect <IP>:<Port>.

The adb_reconnect tool can also force a connection rebuild, use it after a phone restart or when adb_devices shows offline.

Six tools

The six tools are for the Agent to call. During normal conversation, the Agent decides which one to call on its own, but you can also call them directly.

adb_devices

List currently connected devices, no parameters.

adb_devices
→ 127.0.0.1:5555  device

adb_shell

Execute arbitrary shell commands, the most commonly used one. command supports pipes, redirects, &&, $(); timeoutMs can set a timeout, default 60000 ms, range 1000–600000.

adb_shell { command: "getprop ro.build.version.release" }   → 16
adb_shell { command: "pm list packages | grep tencent" }
adb_shell { command: "dumpsys battery | grep -E 'level|status'" }

Actual boundaries:

  • Output limit 32MB, exceeding returns failure but the first 32MB is still returned;
  • Output is decoded as UTF-8, directly cat binary content like images will be corrupted, to view binary content you need to use od / base64;
  • Does not support stdin, interactive commands like top, vi cannot be used;
  • Non-zero command exit codes do not count as tool failure, output is returned as usual, with exit code explanation;
  • Each call probes for a connection once, about 50ms, trading for line-break self-healing.

adb_install

Install APK.

Parameter Type Required Description
path string Yes Absolute path on the device, e.g., /sdcard/app.apk
reinstall boolean Add -r to preserve data, default true
downgrade boolean Add -d to allow downgrade, default false
adb_install { path: "/sdcard/Download/app.apk" }
→ { text: "安装成功:<路径>" }

path uses the device-side path, not the path in proot; files in proot must be pushed to the device first. It fails when signatures do not match; either uninstall the old package first (data will be lost) or re-sign with the same key.

adb_logcat

Read log tail, does not keep a long-running process. lines default 200, max 20000; filter supports regex, using grep -E.

adb_logcat { filter: "FATAL", lines: 100 }
adb_logcat { filter: "AndroidRuntime|FATAL|ANR", lines: 200 }

When nothing matches, it returns “(No matches for "X" in the last N lines)”, which is a normal result, not an error.

adb_screencap

Screenshot and save. Both parameters are optional, adb_screencap {} is also valid.

Parameter Type Description
outPath string Path on the device, default /sdcard/dsh-screencap.png
localPath string Path in proot to pull to locally, e.g., /tmp/shot.png
adb_screencap {}
adb_screencap { outPath: "/sdcard/a.png", localPath: "/tmp/a.png" }
→ { text: "截图已保存:/sdcard/a.png" }

It captures the main screen. To capture content on a virtual screen, use another plugin dsh-go-plugin-screen, not this one.

adb_reconnect

Force connection rebuild: kill local adb server, restart, migrate wireless debug port to 5555, verify uid 2000. No parameters.

What it can and cannot do

The tested capabilities listed in the README include:

pm list packages / pm path / pm install / pm uninstall
am start / am force-stop / am broadcast
logcat / dumpsys / getprop / settings
screencap / input / cmd window / cmd notification

cmd package’s uninstall / clear will uninstall the package and clear data; other sub-commands (like list packages) are just queries.

Things it cannot do: cannot read /data/data (SELinux blocks uid 2000); no stdin, interactive commands cannot be used; binary output is decoded as UTF-8 and will be corrupted; after timeout, the command on the device side may still be running, canceling the tool will not kill the remote process.

Applicable Scenarios and Notes

Suitable for: scenarios where DSH Go is already running inside proot on the phone, the Agent wants to operate the local machine directly, and one does not want to rely on an external computer or LAN. The community directory page categorizes it under workflow.

Points to check before use:

  • The plugin runs with the permissions of the current dsh process. adb_shell has no interception, no whitelist, no secondary confirmation; it can uninstall packages, delete files, restart, and change settings. You should read the source code once before installing.
  • License is MIT. The GitHub repository has 0 stars, created on 2026-11-04, a very new project.
  • Verification is only on one model: Android 16, adb 34.0.4, nubia REDMAGIC NX809J. Other Android versions, other vendors’ adbd, and other adb versions have not been verified.
  • Currently not published to the npm registry, can only be installed from GitHub.
  • Installation only changes configuration; the engine must be manually restarted, otherwise the tools will not appear.

Here are the directory page and source code address:

  • Directory page: https://www.skillhub.cn/plugins/JMINN0/dsh-go-plugin-adb
  • GitHub: https://github.com/JMINN0/dsh-go-plugin-adb
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye