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
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.
| Command | What 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 list | Show what is installed, with versions. |
zbd update | Refetch 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-Cand 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:
| Path | Holds |
|---|---|
$PREFIX/bin | Executables. On PATH. |
$PREFIX/lib | Shared libraries. |
$PREFIX/etc | Configuration, including bash.bashrc. |
$PREFIX/share | Man pages, terminfo, package data. |
$PREFIX/tmp | TMPDIR. |
$HOME | /data/data/com.zbd.wt/files/home. |
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 holdingmanifest.json, afiles/tree merged into$PREFIX, and an optionalpost-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.