The wado CLI

SkillDev tools

How to drive the `wado` command — compile, run, test, serve, format, and publish a Wado program, target a Wasm world, pick an allocator, grant directories, and inspect the compiler with dump and query. Read before invoking the `wado` binary.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the The wado CLI skill

What this skill tells your AI

The instructions your AI receives, as published by wado-lang/wado in .claude/skills/wado-cli/SKILL.md and read by ahel’s review.

wado <command> --help is the source of truth for flags and is thorough — it states the allocator modes and their per-world defaults, the optimization levels, every dump phase, and every query kind. Run it rather than guessing.

Inside the wado repository, wado means cargo run --bin wado --.

Commands

Usage: wado <command> [options]

Commands:
  init [options]                      Create a new wado.toml manifest
  update [options]                    Resolve dependencies and write wado.lock
  fetch [options]                     Download the project's registry dependencies
  clean [options]                     Evict derived cache state (git worktrees)
  build [options]                     Build the project's worlds from wado.toml
  compile [options] <file.wado>       Compile a single Wado source file
  check [options] [file.wado]         Verify a source file and its Kiln generators
  run [options] [file.wado]           Compile and run a Wado CLI program
  serve [options] [file.wado]         Compile and serve a Wado HTTP service
  test [options] [files or dirs...]   Run tests in Wado source files
  format [options] <file.wado>...     Format a Wado source file
  doc [options] <file.wado>...        Generate documentation from source files
  dump [options] <file.wado>...       Dump compiler internal state
  wit [options] [file.wado | dir]     Emit the WIT contract for a Wado program
  syntax [options]                    Generate syntax definition files
  lsp [options]                       Start the language server (LSP over stdio)
  query <kind> [options] <file.wado>  Query language service information
  publish [options]                   Check whether the package can be published

Global options:
  --help     Show this help message
  --version  Show version information

build works from a wado.toml and writes build/<world>.wasm. compile and check take exactly one source file; dump, doc, and format take several. run, serve, and wit fall back to the manifest's entry point when given no path.

Target World

A Wado program targets a Wasm world: the CLI command (wasi:cli/command, the default), the HTTP service (wasi:http/service, run via wado serve), or the synthetic test world (selected with --world test, used by E2E tests). Several defaults — including the allocator — depend on the target world.

--world <name> overrides it on compile, check, dump, and wit. --world test exports the entry module's test blocks and drops everything else. run, serve, and test pick their world automatically. build --world <fq> is a different flag: it selects which of wado.toml's declared worlds to build.

wado compile --world test file.wado  # compile against the test world
wado check --world test file.wado    # type-check against the test world

Allocators

Three allocators are available via --allocator <mode>:

  • bump (default for CLI): bump pointer; never frees. Fast, minimal code.
  • freelist (default for the HTTP world): reclaims freed memory via a free list. For long-running processes.
  • debug (default for the test world): never reuses freed memory; poisons freed memory with 0xFF. For use-after-free detection.
wado compile --allocator bump file.wado      # bump allocator
wado compile --allocator freelist file.wado  # free-list allocator
wado compile --allocator debug file.wado     # debug allocator

wado compile selects the debug allocator automatically when targeting the test world; E2E tests rely on this.

Compile

wado compile -o file.wasm file.wado    # generate Wasm
wado compile -o file.wat file.wado     # generate WAT
wado compile --wat-to-stdout file.wado # output WAT to stdout

Optimization levels: -O0 (none), -O1 (development), -O2 (production, default), -O3 (aggressive), -Os (-O2 + strip symbols).

To inspect invalid Wasm when debugging codegen bugs, skip validation:

# Output raw Wasm bytes even if invalid
wado compile --no-validate --wat-to-stdout file.wado

wado check verifies a source file — and re-runs its Kiln generators, comparing the output against the committed source — without emitting Wasm.

Run

wado run file.wado  # run a CLI program with wasmtime

A program reaches only the directories granted to it: the current one, or exactly the --dir grants once any is given. Paths open relative to a grant, so an absolute path never opens — reach a file outside the tree by granting its directory and naming it relative to that.

wado run --dir /tmp/scratch prog.wado Foo.g4  # Foo.g4 resolves inside /tmp/scratch

Test

wado test discovers and runs test blocks (compiled against the test world, see Target World above).

wado test                           # discover and run every .wado test in the project
wado test file.wado                 # run tests in one file
wado test --filter '**/json*.wado'  # run tests in files matching a wildcard
wado test --profile guest file.wado # guest profile over that file's tests

--profile takes one file, runs it serially, and leaves a test that hangs unbounded — it samples on the epoch deadline the per-test timeout is counted in. See the wado-performance skill for reading the profile it writes.

A failure or resolved #[TODO] prints its own one-line notice immediately, otherwise a digest (N/Total files · tests, failed, todo, skip · ETA) prints every 5s, ending in a compile:/load:/skip:/test: summary. tailing the last line or two is enough to read the current state of a long run.

Serve

Use wado serve to run a Wado HTTP service (wasi:http/service world):

wado serve file.wado                        # serve on 0.0.0.0:8080 (default)
wado serve --addr 127.0.0.1:3000 file.wado  # serve on a custom address

Dump

Use wado dump to inspect compiler internal state for debugging. See wado dump --help for the full help.

wado dump file.wado                  # show final WIR (default)
wado dump --nir file.wado            # show final NIR (after optimization)
wado dump --nir -O0 file.wado        # show NIR without optimization
wado dump --ast file.wado            # show parsed AST
wado dump --modules file.wado        # show loaded modules
wado dump --symbols file.wado        # show symbol table
wado dump --types file.wado          # show type table
wado dump --tir-resolved file.wado       # show TIR after type resolution
wado dump --tir-monomorphized file.wado  # show TIR after monomorphization
wado dump --nir-lowered file.wado        # show NIR right after lowering (before optimize)
wado dump --assert-plan file.wado        # show which operands each `assert` captures

Query

wado query answers compiler questions about a symbol, for tooling and docs. A symbol is addressed either by position (--line/--column in a file) or by symbol notation MODULE#SYMBOL:

  • MODULE is the import specifier; quote it as in use — droppable for a scheme or bare name (core:json), required for a path or URL ("./utils.wado").
  • SYMBOL uses Wado's operators: bare name (free function/type/global), Type::name (associated const/fn), Type.name (method), Type^Trait::name (trait-impl member).
wado query hover --symbol core:json#from_string                   # signature / type
wado query hover --symbol ./hello.wado#run --base example          # local module
wado query definition --symbol core:cbor#CborDeserializer.peek_byte
wado query references --symbol core:cli#println --base example     # all uses (workspace)
wado query hover --line 5 --column 10 file.wado                   # position-based
wado query diagnostics file.wado                                  # errors/warnings
wado query inlay-hints file.wado                                  # hints, spliced into the source

inlay-hints takes a file, not a symbol, and prints every line that carries a hint with the labels spliced in at the anchors an editor would render them at (let x‹: i32› = add(‹a: ›1, ‹b: ›2);). That is how to check anchor placement — against example/, say — without reading positions off a list. --json prints the raw hints instead, positioned in the LSP's default UTF-16 encoding.

Common options:

  • --symbol <notation> — locate by name instead of --line/--column.
  • --base <dir> — anchor relative modules (default: cwd; core: / wasi: are location-independent).
  • --all — include private members; the default is the public-API view (matches wado doc).
  • --json — machine-readable output.

For a type, hover also lists its impl blocks. references loads every .wado under --base, so it spans the workspace. See docs/wep-2026-06-14-symbol-notation.md for the notation spec.

Format

The wado format command formats Wado source code.

wado format -w file.wado  # rewrite in place

In the wado repository, mise run format formats the whole workspace. Every package skips **/generated/** and **/build/** plus its own [format] exclude; [format] include opts any of those back in. wado-compiler excludes tests/**, so the e2e fixtures and the golden format fixtures keep the hand-authored layouts that are part of the test.

A directory argument is walked from the package that encloses it, so the globs match as authored whichever subdirectory you name. wado format -w wado-compiler/tests formats nothing and reports that directory as empty.

Caution: naming a file bypasses the filters. The golden-fixture scripts rewrite excluded fixtures that way, so wado format -w wado-compiler/tests/fixtures/x.wado reformats it too, silently discarding a layout the test depends on. When the syntax is updated, make sure to add tests to wado-compiler/tests/format.rs.

What the formatter decides — width, wrapping, comment placement — is in docs/formatter.md.

Publish

wado publish builds the package and uploads it through wkg. Credentials belong to wkg, not Wado — authenticate to the registry first (docker login, or WKG_OCI_USERNAME / WKG_OCI_PASSWORD; for GHCR the password is a token with the write:packages scope). --dry-run runs every readiness check without uploading.

Compilation Log and Timing

The compiler emits timestamped diagnostics to stderr. Use --log-level to control verbosity (debug, info, warn — the default — error, off).

wado compile --log-level debug file.wado

Optimizer Remarks

A remark: reports a cost the optimizer could not remove, at the exact source span. They are info-level, so the default warn hides them — ask when chasing why something is slower or larger than expected, not on every build.

wado check --log-level info file.wado              # no Wasm emitted; fastest
wado check --world test --log-level info lib.wado  # a library with test blocks

Two kinds are reported, across the whole entry package — its entry point and every local module it reaches. A dependency, core: and wasi: stay out:

  • A value-semantic copy that survived. Wado deep-copies aggregates on assignment, argument passing, and return; the ones no pass removed are invisible in the source.

    file.wado:6:5: info: remark: a copy of `List<i32>` survives optimization
    
  • A compile-time parameter that still decides a branch. -D log.level=info did not strip what it was told to. The remark names the parameter, and the intermediate global when the gate reads a derived one instead.

    file.wado:111:5: info: remark: compile-time parameter `log.level` is still read
    here through global `LOG_STATIC_LEVEL`, so this branch is decided at run time;
    the code it guards was not stripped
    

Design: docs/wep-2026-06-03-optimizer-remarks.md. What a remark is currently expected to report is the "Not yet implemented" list in docs/optimizer.md.

Signals

GitHub stars
116
Forks
2
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
wado-cli
Source
github.com/wado-lang/wado