Quick Start
Overview
This guide takes you from a clean checkout to a running wapp. It uses the wsh debug supervisor — an interactive shell wired to the engine's control plane — so every step is a command you type yourself.
Prerequisites
- A container runtime: Podman (default) or Docker.
make.
Nothing else. The toolchain (CMake, Ninja, the WASI SDK, the WAMR runtime) lives in the build container; the host only invokes make, which wraps every command in that container. To use Docker instead of Podman, append RUNNER=docker to any make command.
Build
Compile the sample wapps and the engine with the wsh supervisor:
1make wapps # compile the sample wapps under wapps/ (produces wapps/hello/hello.wasm)
2make wsh # build the engine + CLI with the wsh debug supervisor
make wapps compiles each sample to a .wasm binary. make wsh builds build/cmd/wanted-cli with wsh as its boot supervisor.
Package a wapp into the registry
The engine starts wapps by name from a registry — on Linux, the ./registry/ directory scanned for <name>:<version>.wapp images. A .wapp is an OCI-style ustar TAR holding app.wasm (and any optional data files). The compiled samples are not packaged automatically, so package hello once:
1mkdir -p registry
2stage=$(mktemp -d)
3cp wapps/hello/hello.wasm "$stage/app.wasm"
4tar --format=ustar --owner=0 --group=0 --mtime='1970-01-01 00:00:00 UTC' \
5 -C "$stage" -cf registry/hello:0.0.1-1.wapp app.wasm
6rm -rf "$stage"
The registry filename is the image's identity: hello, version 0.0.1, package 1 → hello:0.0.1-1.wapp. The engine reads the name and version from the filename. The wasm binary is renamed to app.wasm inside the TAR — that is the fixed entrypoint name the loader expects.
app.wasm is the only required member. A wapp image can carry any additional files — config, certificates, static assets, data — and they become visible to the wapp as a read-only filesystem at /, served by TarFS. Add such files to the TAR alongside app.wasm and they appear at the matching path inside the wapp. (Small runtime knobs, like the hello sample's ROLE, are better passed as launch-config env vars or args than baked into the image — see Control Plane Reference.)
Image identity
The image's name and version come entirely from its registry filename <name>:<version>-<package>.wapp — for hello, that is name hello, version 0.0.1, package 1. The engine reports them at /proc/wapps and the per-instance version node. Capabilities are not declared in the image; they are exactly what the launch config grants at start (consoles, drivers, mounts, sockets, the control plane). One image can run as several independent instances — see Control Plane Reference.
Run
Boot the engine to an interactive wsh prompt:
1make wsh-shell
You land at the shell:
1Wsh v 0.5.0
2>
wsh is itself a wapp: a privileged supervisor granted the wanted control-plane driver. Its commands drive /dev/wanted the same way a production supervisor does.
Launch your first wapp
List the running wapps. The supervisor is itself a wapp, so it appears in the list:
1> status
2supervisor running
Launching a wapp is three deliberate steps — reserve the instance name, give it a JSON launch config, then issue the launch verb:
1> create hello
2> set_config hello {"console":{"in":{"name":"null"},"out":{"name":"log"},"err":{"name":"log"}}}
3> start hello
create helloreserves the instance namespace/dev/wanted/wapps/hello/. Itsconfig,ctl, and read nodes exist only after this, and itsstatereadscreated.set_config hello <json>buffers the launch config atwapps/hello/config, moving the instance tonot_started. The config above gives the wapp a null stdin and routes its stdout/stderr to the per-wapp log console. A wapp's capabilities are exactly what this config grants — consoles, drivers, mounts, sockets, args, and envs (see the Control Plane Reference). Keep the JSON free of spaces:wshsplits a line on whitespace, so a compact object stays one token.start hellowrites the bare verbstarttowapps/hello/ctl. The engine resolves the image (noimagein the config, so the instance namehello→hello:0.0.1-1.wapp), loads it, and runs the wapp as its own thread. Astarton a reservation with no config is rejected — theset_configmust come first.
Check its state — it is running:
1> status hello
2hello:
3 state running
4 version 0.0.1-1
5 id 1
The hello sample (launched with no ROLE set) writes an alive marker, lives for two seconds, then exits. A moment later its state is exited. Read its captured output from the log node the config wired up:
1> status hello
2hello:
3 state exited
4 version 0.0.1-1
5 id 1
6> cat /dev/wanted/wapps/hello/log
7hello-wapp: alive
8hello-wapp: exit
A wapp that runs indefinitely is stopped explicitly — stop writes stop to that wapp's own control node /dev/wanted/wapps/<name>/ctl:
1> stop hello
Once a wapp has reached a terminal state, delete hello releases the name so it leaves wapps/. Richer launch configs — drivers, mounts, sockets, args, and environment variables — go in the same set_config JSON; the full console schema and every control-plane node are documented in the Control Plane Reference.
Next steps
- Architecture — how the VFS router, wapp model, and supervisor fit together.
- Wapp Authoring — write and package your own wapp.
- Control Plane Reference — the complete
/dev/wanted/*contract.