Wear Term

Documentation

How the app is installed, how zbd works, what the prefix looks like, and how to point the whole thing at a repository of your own.

Requirements

Wear OS 3 or newer (API 30+), on aarch64 or x86_64. Roughly 200 MB free for the bootstrap and a handful of packages; more if you install a toolchain. No root, and no app on the phone.

Installing the app

Enable developer options and Wi-Fi debugging on the watch, then pair over ADB:

adb connect 192.168.1.42:5555
adb install -r wearterm.apk
The watch's IP is under Settings → Developer options → Wireless debugging. The port there is the pairing port; the connect port is usually 5555.

First run and the bootstrap

The app opens on an empty prefix — there is no shell yet. Open Packages and install bootstrap: that pulls in bash and the core utilities, and everything else becomes installable from inside the shell.

zbd install bootstrap    # or tap it in the Packages screen
zbd install git python

The zbd command

Every package in the repository is reachable from the shell. Dependencies resolve depth-first and each archive is checked against its SHA-256 before it is unpacked.

CommandWhat it does
zbd install <pkg>…Resolve, download, verify and merge into the prefix.
zbd remove <pkg>Delete exactly the paths that package added — nothing else.
zbd search <term>Match against package names and descriptions in the index.
zbd listShow what is installed, with versions.
zbd updateRefetch the index (ETag-revalidated).
zbd show <pkg>Version, size, dependencies and description.

All 146 packages are listed on the packages page.

Typing on a watch

A 1.4-inch keyboard is the real constraint, so the app gives you three ways around it:

  • Key strip. Ctrl, Esc, Tab and the arrows sit above the input line, so Ctrl-C and tab completion work without a modifier key.
  • Voice. Dictated text lands in the input line unsent, so you can fix what the recogniser got wrong before it runs.
  • Snippets. Save the commands you type constantly and run them with one tap.

The rotary crown scrolls the scrollback rather than moving the cursor.

Sessions, the tile and the complication

Sessions are held by a foreground service, so a build or a download keeps running while the display sleeps. The tile and the complication show the running session count and drop you back into the shell in one tap.

For anything long-lived, install tmux and detach — the session then survives the app being killed outright, not just the screen going off.

Filesystem layout and environment

The prefix is /data/data/com.zbd.wt/files/usr, laid out like any UNIX installation:

PathHolds
$PREFIX/binExecutables. On PATH.
$PREFIX/libShared libraries.
$PREFIX/etcConfiguration, including bash.bashrc.
$PREFIX/shareMan pages, terminfo, package data.
$PREFIX/tmpTMPDIR.
$HOME/data/data/com.zbd.wt/files/home.
The application id is deliberately ten characters — com.zbd.wt, exactly as long as com.termux — so the prefix path is byte-for-byte the same length as Termux's and absolute paths baked into repackaged binaries can be patched in place.

How it runs binaries at all

Android will not execute files out of an app's data directory: W^X is enforced, and $PREFIX/bin/git is exactly the kind of path it refuses.

A small shim library is preloaded into every process with LD_PRELOAD and re-routes execution through a helper binary that lives in the APK's native library directory, which is exec-allowed. Because the shim is preloaded into children too, the trick keeps working the whole way down the process tree — a shell that spawns make that spawns a compiler all still work.

Repository and archive format

The repository is static: an index on GitHub Pages plus release assets. Nothing needs a server.

  • index-$ARCH.json — one index per architecture, listing every package with its version, size, SHA-256, dependencies, category and description.
  • <pkg>.zbd — a gzipped tar holding manifest.json, a files/ tree merged into $PREFIX, and an optional post-install.sh.

Every merged path is recorded at install time, which is why zbd remove can delete exactly what was added and nothing more. The index is cached and revalidated with an ETag, so a watch that is offline still installs from what it already has.

Running your own repository

The build tooling lives in wearterm-repo. The package set is a plain text file, packages.list, grouped by # category: lines — the category travels into the index and is what the watch groups by, because a flat list of a hundred names is unusable on a screen that fits six rows.

Add a name under a heading, rebuild, publish the index and the archives, then point the app at your own base URL in Settings. The app takes any URL that serves the same index schema.

Troubleshooting

Nothing installs, and the index never loads

The watch has no route to the internet — Wi-Fi off, or connected to an access point that needs a captive portal login. zbd update reports the underlying error.

A command exits immediately with a permission error

The shim was not preloaded. Restart the app; if it persists, the package was built against a different prefix length and its baked-in paths are wrong.

Installs fail partway with no space

Run zbd list and remove what you are not using, or install ncdu and look at where the storage actually went.

The session dies when the screen turns off

Battery optimisation is killing the foreground service. Exempt Wear Term in the system battery settings, and use tmux for anything that must not be interrupted.