The toolchain: binaries and commands
Xo is experimental, and the commands and flags below may change before 1.0. The specification’s section 10.1 is the authoritative list of commands and flags; this page is the practical guide to it.
What xo is
xo is one binary: the compiler, the formatter, the test runner, the
module tools, and the editor and agent servers. It is written in Xo
(the self-hosted compiler, built from selfhost/xo in the repository;
you may see it called xo1 in the project’s notes). The original
implementation, written in Go, is frozen and serves as the seed that
builds the first Xo compiler on a machine.
The layout
An installed toolchain is a directory, and xo finds the rest of the
toolchain relative to itself:
bin/xo the toolchain
bin/xo-gobind a helper that binds Go packages for use go
lib/xo/ std, third_party, the prebuilt native runtime, zoneinfo.zip
Keep the layout: bin/xo looks for the standard library and the
runtime in ../lib/xo, so a copy of bin/xo on its own does not work.
Put bin on your PATH, or link bin/xo from a directory on your
PATH (symbolic links are followed). Set XO_STD to point at the
standard library when it lives somewhere else, as it does in a
checkout.
Building it from source
From a checkout of the repository, the Go seed (Go 1.26 or later)
builds the first Xo xo. On an arm64 host (Apple silicon, arm64
Linux):
go build -o .tools/bin/xo-seed ./cmd/xo
XO_SELF_DRIVER=0 .tools/bin/xo-seed build --backend=arm64 -o .tools/bin/xo selfhost/xo
export XO_STD="$PWD/std"
On an x86-64 host, with clang installed:
go build -o .tools/bin/xo-seed ./cmd/xo
XO_SELF_DRIVER=0 XO_LLVM_SPLIT=12 XO_LLVM_LTO=none \
.tools/bin/xo-seed build --backend=llvm -o .tools/bin/xo selfhost/xo
export XO_STD="$PWD/std"
The arm64 build takes a few minutes; the x86-64 build took about 36
minutes and 10 GB of memory on a 16 vCPU Linux machine. After that,
any Xo xo rebuilds itself without Go (scripts/bootstrap-xo.sh; see
the bootstrap post for how that is checked).
Getting started walks through a first program.
Backends and targets
--backend picks how a program is built. Each backend needs different
tools on the machine.
| Backend | Flag | Builds for | Needs |
|---|---|---|---|
| Go (default) | --backend=go or none | every target in --targets: linux, darwin, windows (amd64 and arm64), and wasip1/wasm | the go command, Go 1.24 or newer (or XO_GO naming it) |
| LLVM | --backend=llvm | the host, including x86-64 Linux and Intel Macs | clang |
| arm64 | --backend=arm64 | darwin/arm64 and linux/arm64 | a C compiler driver (cc), or none with --ld=macho and a prebuilt runtime |
| WebAssembly (experimental) | --backend=wasm | WASI preview 1 | nothing else; the module runs under any WASI runtime |
--no-gcbuilds on a native backend whose memory is reference counted instead of collected: arm64 on arm64 hosts, LLVM otherwise.--backend=llvmand--backend=arm64already imply it. A construct a native build does not support yet is errorXO1201at compile time.--targets=all(Go backend) builds linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64, windows/arm64, and wasip1/wasm, one binary per target.--ld=macholinks an arm64 program with Xo’s own assembler and linker, with nocc. It needs the prebuilt runtime inlib/xoof a packaged toolchain (orXO_RTPACK). On a Mac it is the default when that runtime is present.--ld=ccuses the system linker.- Windows (x86-64) and Intel Macs build natively through the LLVM backend; this work is in progress and tested on a smaller scale than the arm64 hosts.
- Linux programs with no C library at all are an opt-in experiment
(
XO_NOLIBC=1with a native backend), in progress: they refuseuse cand TLS for now. use cworks only on the native backends, anduse goonly on the Go backend.- A program that names time zones reads them from Go’s
zoneinfo.zip,lib/xo/zoneinfo.zip,XO_ZONEINFO, or with--tzdata=system, from the system’s zone files.
Commands
xo help lists every command, and xo help <command> or
-h/--help prints a command’s usage. Every command that reports
diagnostics or results accepts --json, and xo query answers in JSON
by default when its output is not a terminal. The examples run in a
module directory.
A directory argument covers every directory below it, skipping
testdata, vendor/, and names starting with . or _. So
xo check . checks every module under the current directory, and the
Go-style pattern ./... (or cmd/...) means the same thing:
xo check ./..., xo test ./.... A pattern that matches no .xo
files is an error, and xo run takes one directory, not a pattern.
Build, run, and test
| Command | What it does | Example |
|---|---|---|
xo build | Build binaries | xo build --targets=all -o out . |
xo run | Build for the host and run; arguments after -- go to the program | xo run --backend=arm64 . -- --port 8080 |
xo test | Run the test blocks, property tests, and contract fuzzing, with deterministic scheduling | xo test --explore=100 . |
Useful flags of all three: --backend, --no-gc, -o, --json,
--tzdata=embedded|system. xo build and xo run take
--stamp NAME=VALUE (sets a string constant for this build).
xo build also takes --targets, --ld,
--ci (fail on unformatted code or a leftover dbg), and --release.
xo test takes --seed=N, --explore=N, --cases=N, --run=NAME,
-v, and --real (tests that declare effects run with real
capabilities).
Check and edit
| Command | What it does | Example |
|---|---|---|
xo check | Parse and type check, no code generation | xo check --fix . |
xo fmt | Format to the one canonical layout | xo fmt --check . |
xo fix | Apply every machine fix until none applies | xo fix --dry-run . |
xo vet | Advisory checks that never fail the build | xo vet . |
xo query | Semantic queries: type, def, callers, effects, holes, api, imports, deps, hash | xo query callers greet |
xo edit | Semantic edits: rename, add-field, change-sig, rechecked before writing | xo edit rename --dry-run greet salute |
xo doc | Documentation from doc comments | xo doc . |
xo explain | The long explanation of a diagnostic code | xo explain XO0201 |
xo check --fix is the agent loop’s check: it applies every
unambiguous fix, reformats what it changed, and reports what remains.
Modules and dependencies
| Command | What it does | Example |
|---|---|---|
xo init | Start a module | xo init example.com/hello |
xo get | Require a module version, printing its API and effect changes | xo get github.com/acme/billing@v1.4.1 |
xo mod tidy | Tidy xo.mod and xo.lock | xo mod tidy |
xo mod accept-effects | Record a dependency’s wider effects in xo.lock | xo mod accept-effects github.com/acme/billing |
xo vendor | Copy dependencies into vendor/ | xo vendor |
xo audit | Supply chain report: each dependency’s effects, escape hatches, and the capabilities you pass it | xo audit . |
xo publish | Check a release of your module against its previous tag | xo publish --check |
xo mod clean empties the module cache, and xo mod proxy serve
serves it as a module proxy. Every module command takes --offline.
See Dependencies and capabilities for effect
ceilings and vouches.
Bindings
| Command | What it does | Example |
|---|---|---|
xo bind | Generate bindings of Go packages for use go (runs xo-gobind) | xo bind github.com/google/uuid |
xo bind --c | Generate bindings of C headers for use c | xo bind --c --link z zlib.h |
You rarely need to run these yourself: xo check and the builds bind a
missing package or header on first use.
Servers and debugging
| Command | What it does | Example |
|---|---|---|
xo lsp | Language Server Protocol server over stdio, for editors | configure your editor to run xo lsp |
xo mcp | Model Context Protocol server over stdio, for agents: check, query, edit, explain, fmt, test, build | configure your agent to run xo mcp |
xo serve | A resident checker on a Unix socket; xo check and xo query use it when it answers | xo serve |
xo dump | The task tree of a running program | xo dump 4121 |
xo replay | Replay a run recorded with xo run --record=trace.xotrace (Go backend), or a crash bundle (.xocrash) | xo replay trace.xotrace |
xo version | The toolchain version and host | xo version |
Environment variables
| Variable | What it does |
|---|---|
XO_STD | Where the standard library is, when xo is not in the toolchain layout (a checkout: $PWD/std) |
XO_GO | The go command the Go backend uses, when it is not go on the PATH |
XO_ZONEINFO | A zoneinfo.zip for programs that name time zones |
XO_RTPACK | A directory of prebuilt native runtimes, instead of lib/xo/rtpack |
XO_NOLIBC=1 | Linux native builds with no C library (opt-in, in progress) |
Two more apply only to the Go seed when it builds the first Xo xo:
XO_SELF_DRIVER=0 makes the seed do the build itself (as in the
commands above), and XO1 points it at an Xo compiler you already
built.
Coming later
Developer harnesses written in Xo, under an xo dev command, are
planned (decision 0209) but do not exist yet.