Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The rut CLI

The rut binary is the toolchain’s command-line face. It is also a full host: running a program mounts the base packages, binds the standard native bodies, and drives the async loop — the same contract an embedded host implements (embedding and native modules).

rut run <file.rut | dir | mod.rutbundle> [--fuel N]
rut fmt <file.rut | dir> [--check]
rut pack <dir> [-o out.rutbundle]
rut dump <file.rut>

Running rut with no subcommand prints the usage line to stderr.

run

Compiles and executes. Three input forms:

inputpipeline
file.rutone file is one module unit — compile it against the base mounts, then decode → verify → run main
dir (a module directory with rut.toml)load the whole graph, compile it, run the root’s main (project structure)
mod.rutbundlethe packed form of the same contract (module bundles)

Flags and defaults:

itembehavior
--fuel Ncap the op budget per turn. Without the flag the run is uncapped; an unparsable value falls back to 10_000_000
heap limitfixed at 64 MiB
interrupt checkevery 1024 ops

Single-file convenience: a loose file that declares use ink:: (or any tree package) gets that package mounted automatically — the CLI scans the source for use <name>:: across rt, ink, pouch, nmapset, json, strbuild, async_engine, async_host, http_host, and http, then assembles peer groups, so a loose file gets json’s peer-gated container impls exactly like a module-directory program (dependency kinds).

Bodies bound by run:

installerpurpose
install_std_mathcalc’s float fns
install_std_log (sink: stdout)the logger; silent no-op unless the program uses ink
install_std_nmapthe native key table behind nmapset
install_std_bench_crossthe crossing-benchmark rows
install_std_asyncthe async launchers
install_std_httpthe std HTTP lanes

Execution: main is called with no arguments; then the async driving loop runs — drain the ready queue, advance the virtual clock to the next timer deadline, repeat until no frames and no tasks remain. The loop is capped, so a program that never idles fails loudly instead of hanging.

A .d.rut input is refused: a declaration file is a surface, not a runnable module (host fns and declaration files).

fmt

rut fmt src/            # rewrite in place
rut fmt --check main.rut

The canonical formatter. Behavior:

  • a directory argument is walked recursively; every .rut file is collected (sorted) and formatted;
  • style comes from the nearest ancestor rut.toml’s [style] block; no manifest → defaults (project structure);
  • .d.rut files are formatted in declaration mode;
  • a file that does not parse clean is refused (diagnostics listed, nonzero exit) — fmt never reformats on a parse error;
  • default mode rewrites in place and prints formatted: <path> per changed file;
  • --check writes nothing: it prints unformatted: <path> for each would-change file and exits nonzero, or fmt: N file(s) formatted when everything is clean.

pack

rut pack plugins/server -o server.rutbundle
# packed plugins/server -> server.rutbundle (18304 bytes)

Packs a module directory into a deterministic .rutbundle — same input, same bytes. Without -o, the output is written beside the input as <dir-name>.rutbundle. The bundle carries the compiled binaries, the declaration surfaces, the cached DeclIr, and symbol sidecars under a versioned manifest; run accepts it directly (module bundles).

dump

rut dump main.rut

Prints the compiler’s view of one file: the == AST == section followed by == IR == (per-function typed register tables and op listings). Compilation is the same base-mounted pipeline run uses, minus execution and verification. .d.rut inputs dump in declaration mode — useful for inspecting a host surface’s slots.

Declaration mode

The file extension selects the parser mode:

filemoderunfmtdump
*.rutimplementationruns mainformats implsAST + IR of the module
*.d.rutdeclarationrefused (exit 2)formats the surfacethe surface’s AST + IR

Exit codes

codemeaning
0success
1compile diagnostics; no binary emitted; binary decode or verify failure; VM boot failure; a trap at run; fmt refuses a file that does not parse; fmt --check found drift; pack or output-write failure
2usage errors (missing arguments); unreadable input file; run on a .d.rut; fmt finds no .rut files under a directory

Diagnostics go to stderr (run renders them with source spans on the single-file path); pack’s success line goes to stdout.

Notes

  • The CLI mounts and binds on behalf of the program, but it never injects names the program did not declare: a program that never spells use ink:: gets no logger; one that never mounts the async packages has no launcher and await stays cold-poll inline (core and the swappable packages).
  • The HTTP lane is native-only: the CLI build carries it, wasm builds do not.
  • run on a module directory is the deployment path for development; pack + run <bundle> is the shipping path — both run the identical contract (loading and the embed loop).