Command Line Interface
Every whitehall command, as whitehall --help lists them. The ones
with a page of their own link to it; this is the full surface.
Global flag
| Flag | What it does |
|---|---|
--non-interactive | Never ask a question — fail with the list instead of offering a menu |
-h, --help | Print help for the command |
-V, --version | Print the version |
Interactive is the default: where a verb needs a phone and finds two, it draws a menu. --non-interactive turns that off, for a script that would rather have the
error. WHITEHALL_NON_INTERACTIVE or CI in the environment does the
same, and so does not being at a terminal.
Making and running
| Command | What it does |
|---|---|
init [name] | Start something — an app, or a tool in its own language |
build [source] | Any source → an image in the store. The only verb that reads source |
run [image | path] | Start it and attach to its output — stdout for a tool, logcat for an app |
dev | The .wh edit loop — watch, rebuild, hot-reload |
install [image | path | .apk] | Put it on the phone, launchable from the drawer |
uninstall <image | package> | Take one thing off the phone |
images | List the store. --all includes scratch runs |
package [image | path] | Write an image out as <name>.apk, to hand to another phone |
clean | Remove build artifacts, or the programs left on a phone |
compile | Transpile to Kotlin only — no APK. --watch recompiles on change |
Source, or a name
build, install, run and package all take
either. Which one you meant is decided the way a shell decides it — ./script versus script on $PATH:
| What you type | What it means |
|---|---|
. · ./foo · ../bar · x/y · main.wh | Source. Build it first, then act on the image that came out |
foo | An image in the store — always, even if a directory called foo is sitting right there |
So whitehall install . is build . piped into install,
with the build's own cache deciding whether any work happens. Nothing bypasses the store, and
there is one cache rather than two.
compile, build, install, run and package all accept a single .wh file as well as a project directory,
so a one-file experiment does not need a whitehall.toml.Cleaning
Plain clean belongs to a project, the way cargo clean does: with no whitehall.toml it refuses and does nothing. The flags are global and work from
anywhere.
| Command | What it does |
|---|---|
clean | Build output, plus the images nothing can rebuild or nobody asked for |
clean <name> | Remove that one image from the store |
clean --programs | Uninstall the programs cargo run left on the phone |
clean --programs --all | Also the ones install gave an icon |
clean --images | Empty the image store |
clean --packages | Empty the Termux package cache |
Checking
| Command | What it does |
|---|---|
check | Full transpile and lint, no output, no APK. The fast one |
test | Run the project's tests — every language, one report. --watch reruns on save |
snap | Capture every screen and compare it to its golden PNG |
bench | Run the benchmarks in src/benches/ on a device |
Code quality
| Command | What it does |
|---|---|
format | Format .wh files. Opinionated, zero-config. Alias fmt |
format --check | Fail if anything is unformatted. For CI |
lint | Lint for style and idiom |
lint --fix | Apply the fixable ones |
why <file> | Explain what the compiler decided about a file, and why |
trace | Rewrite generated-Kotlin file references into .wh ones |
lsp | Run the language server an editor talks to over stdin/stdout |
Dependencies and packages
| Command | What it does |
|---|---|
add <name>… | In an app, copy a component into src/lib/components/ui/; in a tool, add a Termux package to [packages] |
remove <pkg>… | Take a package back out of [packages]. Alias rm |
update [pkg]… | Re-resolve the lock — cargo's verb |
deps add <dep> | Add a Maven dependency to whitehall.toml, resolving the version |
deps add --dev <dep> | Add as a test dependency |
deps remove <dep> | Remove one |
deps list | List every dependency with its resolved version |
whitehall deps add io.coil-kt/coil-compose
whitehall deps add --dev io.mockk/mockk
whitehall deps list The top-level add, remove and update are the Termux
package verbs — the phone's own libraries, in [packages]. Given a Maven
coordinate they print the deps spelling and exit 1. The tables these write to
are documented under Configuration.
Signing
| Command | What it does |
|---|---|
keystore init | Generate a keystore into the project and write [signing] |
Toolchain
Java, Gradle and the Android SDK are downloaded and managed for you, cached in ~/.whitehall/toolchains/ and shared across projects while staying
version-isolated. There is no separate setup step — the first build fetches what it needs.
| Command | What it does |
|---|---|
toolchain install | Pre-download everything this project needs |
toolchain list | Show what is installed, marking what this project uses |
toolchain outdated · update · available | Keep the SDK current |
toolchain clean | Remove all cached toolchains |
doctor | What this machine has, and what to type next |
whitehall doctor
The first thing to run, and the thing to run when something is wrong. It reports the SDK and adb, the NDK, the Android target for cargo, CPython, Go, Java and Gradle, and
every device on adb by name — then says which door this directory is and the one
command that opens it.
Found the Android SDK and adb in ~/.whitehall/toolchains/android
Found the NDK 26.1.10909125
Found CPython 3.13.9-0 for arm64-v8a
Device Pixel · 1A2B3C4D5E6F7G
Here a tool — Cargo.toml
whitehall shell then `cargo run`, on the phone
Finished everything is here doctor reads the disk and downloads nothing, so it is safe on a bad connection
— a missing thing is a line, not a wait. Nothing it reports is an error: the toolchain
fetches what it needs at the moment it needs it.Borrowing the environment
The managed toolchain is not on your PATH, which is deliberate — it is what keeps
projects from fighting over versions. These let you reach into it anyway:
| Command | What it does |
|---|---|
shell | Enter the Android context — a subshell where cargo means the phone |
exec <cmd> | Run one command inside the Android context |
which <cmd> | Where that command resolves to. Alias for exec which |
override set android · unset | Point one directory at the phone, the way rustup override does |
whitehall exec java -version
whitehall which gradle
whitehall shell Devices and emulators
| Command | What it does |
|---|---|
device | List connected devices, or pin one for every verb. Alias devices |
emulator | Manage emulators — list, start, create, delete |
logs | logcat, filtered to your app and rewritten to name your .wh files. Alias logcat |
push · pull | adb push and adb pull, with the device resolved |
adb … | Run adb with the managed SDK |
fastboot … | Run fastboot with the managed SDK |
emu … | Run the emulator binary directly, e.g. whitehall emu -avd myavd |
avdmanager … | Manage Android Virtual Devices |
$ whitehall device
Device Pixel · 1A2B3C4D5E6F7G Naming a phone
Every verb that touches a device takes -d/--device, and it means the
same thing everywhere. Give it a serial, the start of one, or the model name — the name the
status lines have been using all along. Case and _, - and spaces are
ignored, so Pixel_10_Pro_XL, "pixel 10 pro xl" and pixel10pro are the same query. Two matches is a refusal that lists them, never a
guess. $ANDROID_SERIAL and whitehall device pin choose a phone when -d is absent.
whitehall run myapp -d pixel
whitehall test -d 1A2B
whitehall clean --programs -d "pixel 10 pro" whitehall adb rather than a system adb. It is the one from the
SDK this project builds against, so it cannot disagree with the APK you just installed.Wear OS
whitehall build --wear
whitehall dev --wear See Wear OS.
See Also
- whitehall dev — the edit loop
- whitehall run — start it and attach to its output
- whitehall build — release builds and signing
- Configuration — what these commands read and write