Skip to main content

Droidock

A Python library and interactive CLI that remembers Android connection settings on your PC. It groups USB and wireless connections by device serial number, discovers changing addresses, and verifies the device identity before updating a saved profile.

uv tool install droidock
droidock

To run without a persistent CLI installation, use uvx droidock. To use the Python API in another project, run uv add droidock, then from droidock import ConnectionManager.

The package prefers the ADB executable included in adbutils, so a separate Android SDK or ADB installation is not required on supported platforms. If no bundled executable is available for your OS, configure an ADB path or provide ADB on PATH. The distribution has been verified on Windows x64.

First connection

Use the arrow keys and Enter to navigate. For a numbered menu, run uv run droidock --plain.

The main menu scans once on startup and keeps that snapshot while you browse menus or edit saved preferences. Select Scan again to refresh it. Registration, connection changes, and ADB server settings refresh the view when needed. Back and Exit do not start discovery. Use uv run droidock --version to check the installed version; restart an already running CLI after updating it.

Nearby services can advertise both IPv4 and IPv6 addresses. The table and selection menu show one entry per service name and purpose, with all its addresses retained. Selecting a wireless connection tries IPv4 first, then another advertised address if the connection fails (up to three addresses). A discovery entry is not yet a saved device: registration still requires a responding device with a verified serial number.

  1. Select Add a device.
  2. For USB, enable USB debugging on the device and authorize this PC before registering it.
  3. For wireless access, join the same network, enable Wireless debugging, and open Pair device with pairing code on the device.
  4. Select the pairing address in the CLI and enter the six-digit code. The code is hidden and is not saved.
  5. After pairing, connect to the device's current connection address. The pairing port and connection port differ.
  6. Give the device a name. The first registered device becomes the default, with automatic connection enabled.

The interactive menu attempts to reconnect saved devices on subsequent launches. To keep checking connections while the program runs:

uv run droidock watch

watch periodically discovers and reconnects enabled devices until you stop it. It does not install an OS startup entry or background service. Change per-device preferences under Manage saved devices, and startup behavior under Connection settings. Disconnecting a saved device also disables its automatic connection preference. These settings control this tool's connection attempts; other applications and a shared ADB server can manage connections independently.

Tailscale devices

Open Tailscale devices in the main menu. This reads the installed Tailscale client's device list, with Android devices first and both IP address families shown in one row. Tailscale must be installed, running, and signed in on this PC; it is optional for the rest of Droidock. Set DROIDOCK_TAILSCALE_PATH if its executable cannot be found. The device list is cached until you select Refresh device list. Opening a device menu or selecting Back does not search ports.

  1. Select the device, then Find ADB port and connect.
  2. The search first checks ports from current and saved connections at the selected IP. If none answers as ADB, it searches the other TCP ports on that one address, skipping the peer's advertised Tailscale API ports.
  3. A progress bar shows checked ports, percentage, elapsed time, and ETA. ETA estimates the time to check the remaining range at the observed rate; it starts with “estimating” and can change with network conditions. The search stops immediately when ADB responds, or at the five-minute time limit. A partial search keeps its actual count instead of displaying 100%. Press Ctrl+C during the search to return to the device menu.
  4. Droidock connects through ADB, verifies the physical device serial, and lets you save or edit its name. An existing profile for that serial keeps its ID and alias. Finding an ADB port does not grant authorization; first-time wireless pairing still requires the device's pairing code.

IPv4 is selected first. Use Select another device address to try IPv6, or Enter a known connection port to connect without searching. An online Tailscale status alone does not establish ADB access. Keep Wireless debugging enabled, and ensure Tailscale access rules allow the connection.

Successful endpoints are saved on this PC and used by normal automatic connection attempts. Startup, Scan again, and watch do not run broad Tailscale port searches. If the saved port stops working, reopen the Tailscale menu to find its current port. Local mDNS remains part of ordinary discovery; Tailscale device enumeration supplies peer addresses, not Android's changing debugging port.

The same functionality is available without terminal dependencies:

import asyncio

from droidock import AdbPortScanner, ConnectionManager, TailscaleClient, preferred_adb_ports

manager = ConnectionManager()
peers = TailscaleClient().peers()  # List devices without probing their ports.
peer = next(p for p in peers if p.name == "Office XR")  # The caller selects one device.
host = peer.addresses[0]
saved = [e for d in manager.store.read().devices for e in d.endpoints]
result = asyncio.run(
    AdbPortScanner().scan(
        host,
        preferred_ports=preferred_adb_ports(host, saved),
        excluded_ports=peer.peer_api_ports,
    )
)
if result.endpoint:
    device = manager.connect_endpoint(result.endpoint)  # Verify serial before saving.

Async applications can await scan() directly. Its optional on_progress callback receives PortScanProgress values, including eta_seconds. Pass a threading.Event as stop, or cancel the async task, to close all active probes. PortScanStatus distinguishes discovery, no response, timeout, and cancellation. Callers can set concurrency, timeouts, or an explicit port range. Peer names and IP addresses are discovery hints, not persistent Android identities; pass expected=manager.device(saved_name) when connecting on behalf of a specific saved device.

Saved connection settings

droidock settings shows the storage path. On Windows, the default is usually %LOCALAPPDATA%\droidock\state.json.

An explicit --data-dir or DeviceStore(directory) takes priority over DROIDOCK_HOME, followed by the default configuration directory. All stores use the same schema, so CLI and Python applications can share saved profiles or select separate directories.

The store contains:

  • A persistent local device ID, name, verified serial number, manufacturer, and model.
  • Wireless identifiers read from the connected device, recent connection addresses, and the last-seen timestamp.
  • The default device and each device's automatic connection preference.
  • The ADB executable path, server port, discovery duration, command timeout, and connection attempt limit.

Saved IP addresses and ports are connection candidates. A different device serial number never replaces the saved identity. Discovery combines ADB's results with independent mDNS discovery, which looks for device advertisements on the local network. After connecting to a new address, the manager checks the command response and serial number before updating the profile.

Writes use file locking and atomic replacement. An invalid or corrupted store is reported and preserved instead of being silently reset. ADB manages its authorization keys in the PC user's .android directory. This tool does not copy those keys or store pairing codes. Deleting a saved profile does not revoke pairing authorization on Android.

To keep separate records for another application, choose a different directory:

uv run droidock --data-dir C:\MyAppData\android devices
# Alternatively, set the DROIDOCK_HOME environment variable.

Set DROIDOCK_ADB_PATH to override the bundled executable. The saved adb_path setting takes priority over this environment variable. Set DROIDOCK_TAILSCALE_PATH to select a Tailscale executable, or pass its path directly to TailscaleClient(executable=...). The public base exception is DroidockError.

CLI commands

Interactive device details and diagnostics use labeled tables, readable statuses, and suggested next steps. Result commands also display tables or short messages by default. For scripts, append --json to devices, register, connect, pair, auto-connect, diagnose, settings, profile, or disconnect. For example, uv run droidock settings --json preserves the structured field names and values. JSON pairing requires an explicit address and --code-stdin, so prompts do not appear in the JSON output.

Command Behavior
droidock Attempt startup connections and open the interactive menu.
droidock --version Show the installed version without loading profiles or starting ADB.
droidock devices --json List profiles, current connections, and wireless services without requesting reconnection.
droidock register USB_SERIAL --name "Office XR" Register an already connected device.
droidock pair IP:PAIRING_PORT Pair using a hidden code prompt.
droidock connect --endpoint IP:CONNECT_PORT --name "Office XR" Connect, verify identity, and register the device.
droidock connect "Office XR" Discover and reconnect a saved device.
droidock connect "Office XR" --endpoint IP:PORT Connect to an explicit address and verify it matches the saved device.
droidock auto-connect Try once for each device with automatic connection enabled.
droidock watch --interval 5 Maintain connections while running; stop with Ctrl+C.
droidock profile "Office XR" --default Select the default device.
droidock profile "Office XR" --no-auto-connect Disable automatic connection for this device.
droidock disconnect "Office XR" Disconnect verified wireless connections and disable automatic connection.
droidock diagnose Show ADB, server, and device diagnostics with connection guidance.
droidock settings Show connection settings and the storage path.
droidock settings adb_path auto Prefer bundled ADB.
droidock forget "Office XR" Confirm and delete the saved profile from this PC.

Prefix commands with uv run when working in the project. From another directory:

uv run --project C:\Projects\droidock droidock

For scripted pairing, use pair IP:PORT --code-stdin and send the code through standard input. Successful pairing confirms the trust exchange; a subsequent connection must still verify the device response. The default command timeout is 5 seconds, pairing has a 30-second timeout, and reconnection allows up to 3 attempts by default. Each attempt tries at most 3 addresses, preferring current discovery results over saved addresses.

Use the library in another project

Applications use the same ConnectionManager as the CLI. The core has no terminal prompts or output and does not import Typer or Questionary. Importing the package does not start ADB or connect to devices.

During local development, add this package from a sibling project:

uv add ../droidock
import adbutils

from droidock import ConnectionManager

# Share the profiles registered through the CLI.
manager = ConnectionManager()
transport = manager.resolve("Office XR")

# The returned address identifies a verified current ADB connection.
# The calling application owns installation, file transfer, and other device operations.
adb = adbutils.AdbClient(host="127.0.0.1", port=manager.settings.server_port)
device = adb.device(serial=transport.address)
print(device.shell("getprop ro.product.model"))

Use a separate store when your application should manage its own profiles:

from droidock import ConnectionManager, DeviceStore

manager = ConnectionManager(DeviceStore("./my-app-data/android"))

Applications can use the verified connection address for installation, file transfer, and other ADB operations. The package has no dependency on an application workspace or a particular device model. See examples/integrate.py for a runnable integration example.

Extension points:

  • ServiceKind.CONNECT and ServiceKind.PAIRING: typed service purposes on Service and ServiceGroup. Python callers should pass these enum members. Existing string inputs are normalized at runtime; unsupported values raise ValueError. JSON continues to use "connect" and "pairing", with unchanged field names.
  • Snapshot.service_groups or group_services(services): obtain one entry per advertised service with all its addresses. Snapshot.services and devices --json retain the individual address records.
  • connect_endpoints(endpoints, name=...): connect through a selected service's addresses and save a verified device. Pass expected=record to require an existing device identity; profile and identity errors stop fallback.
  • Backend: replace ADB queries, connection, pairing, and identity inspection.
  • Discovery: add discovery for a different network environment.
  • DeviceStore(directory): isolate storage; subclass it to replace the storage implementation.
  • on_event(ConnectionEvent): send discovery, connection, and failure events to your application's UI or logs.
  • watch(stop=threading.Event()): let the calling application stop its reconnection loop.
  • DroidockError.code: handle failures by error category.

Another connected Android device never satisfies a request for the selected device. Missing serial numbers and conflicting model details for the same serial prevent automatic registration or merging. Serial matching is not a cryptographic defense against cloned identifiers; authentication uses Android's ADB authorization and pairing.

Connection troubleshooting

A powered-on device may still be unavailable to ADB. Wireless debugging may be disabled, the network may block discovery advertisements, or USB authorization or drivers may be missing. In those cases, update the device settings or enter its current connection address manually. Windows USB connections may require device-specific drivers.

The tool reuses a compatible running ADB server and does not automatically stop the shared server. A protocol version conflict produces guidance to select a compatible ADB executable or a separate local server port.

Development and validation

Use English for project documentation, CLI messages, comments, docstrings, and examples. User-provided device names remain unchanged. Use uv to manage the Python environment and dependencies.

uv sync
uv run ruff check .
uv run ruff format --check .
uv run isort --check-only --diff .
uv run pyright
uv run pytest -q
uv lock --check
uv build --no-sources

Ruff includes import-order checks (I), and isort is also installed as a development dependency for a separate check. Both use a line length of 110; isort uses the black profile. Pyright covers src, tests, scripts, and examples.

Tests cover identity persistence after address changes, reassigned addresses, USB/wireless duplicates, requested device verification, connection preferences, pairing secrets, storage corruption and concurrent writes, and CLI behavior. See VALIDATION.md for executed checks, isolated wheel installation, and physical-device verification limits.

External API references: adbutils, ADB commands, wireless ADB, ADB protocol, Tailscale CLI, Zeroconf, isort configuration, Ruff formatter.

Metadata

Release files for droidock 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for droidock 0.1.1
File Size Uploaded
droidock-0.1.1.tar.gz 34.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for droidock 0.1.1
File Interpreter ABI Platform
droidock-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 75.5 kB

Release files / droidock-0.1.1.tar.gz

Download URL droidock-0.1.1.tar.gz
Size 34.3 kB
Tags Source
SHA-256 checksum
How to use checksums
59a54988407247cb9e00b81952d199b548c878bfeea3e79cd258e11bf7a527d1
BLAKE2b-256 checksum
How to use checksums
60a7146b9ba50dfffe295eabb91973304510ae40fe80249279ad80f1eeb7cb09
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / droidock-0.1.1-py3-none-any.whl

Download URL droidock-0.1.1-py3-none-any.whl
Size 41.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
85fd32898ed57b3e94e5b0c019c11662239f52b0ca6155ab74bef00d793365a5
BLAKE2b-256 checksum
How to use checksums
df0317bc61ce53df5e99bb7c8bc680cfbc50bb4579807632d7edfb9ef00473c0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.25 {"installer":{"name":"uv","version":"0.11.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page