Guides · 17
Tooling
Vyi ships as one compiler binary (vyi) plus a language server that powers the
VS Code extension and the web playground. This guide covers what you type at the
shell, how to pick a target, what diagnostics look like, and what the editor
integration gives you.
Install
The fastest path on linux (amd64 or arm64) is the install script — it fetches
prebuilt vyi, vyi-language-server, and the standard library:
curl -fsSL https://forgejo.roberthurst.ca/robert/Vyi/raw/branch/master/scripts/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
vyi helpTo build from a source checkout instead:
( cd bootstrap-compiler && go build -o vyi ./cmd/vyi )
export VYI_STDLIB_PATH="$PWD/packages" # or --packages packages on each run
./bootstrap-compiler/vyi run path/to/main.vyiFull detail — options, artifact URLs, language server, verification gate — is in reference/toolchain/install.
The vyi CLI
vyi build [bin] # compile to out/<target>/<bin> (all bins if omitted)
vyi run [bin] # compile and execute (all bins if omitted)
vyi check [bin] # typecheck only; report diagnostics
vyi test [dir] # run every *.tests.vyi under dir (default: .)
vyi ast [bin] # print the AST as JSON (post-transform; see --pre-elaborate)
vyi help # summary of all of the aboveOne rule to remember: flags go between the subcommand and
the entry path — vyi run --target x86-64-linux main.vyi. Anything after the
entry is not parsed as a flag; for run it is forwarded to your program as its
arguments (a leading -- separator is conventional):
vyi run main.vyi -- --verbose input.txt # your program's args, not vyi'svyi build
Compiles the entry to an artifact — a .wasm module by default, or a native
executable with --target x86-64-linux (native builds link with your system C
compiler: cc, gcc, or clang).
vyi build main.vyi # writes out/wasm/main
vyi build greeter # bin from package.vyipac
vyi build # every entry in the package
vyi build -o app.wasm greeter # choose the output path (single bin)
vyi build --target x86-64-linux greeter # out/x86-64-linux/greeter--emit picks the output kind:
vyi build --emit=wat main.vyi # WebAssembly text to stdout
vyi build --emit=asm --target x86-64-linux main.vyi # native assembly text(--emit=wasm is the default; wat and asm write to stdout unless -o names
a file.)
In a project with a package.vyipac, the positional argument can also be a
bin name from the manifest's entries block instead of a file path:
vyi build mytool. (Guide 14 covers manifests.)
vyi run
Builds in memory and executes immediately. On the default wasm target the
module runs under an embedded runtime with WASI: your stdin/stdout/stderr pipe
straight through, the current directory is mounted so the program can open
files relative to it, and arguments after the entry become the program's argv.
With --target x86-64-linux it compiles, links, and executes a native binary
directly. Either way the process exit code is your program's exit code — an
fn main() !u8 returning Ok(3) exits with 3; an unhandled error prints
error: … and exits 1; an unhandled panic prints the panic and a stack trace.
--timings prints a machine-readable compile/execute timing line to stderr
after the run — useful for benchmarking your build loop.
vyi check
Runs the full front end and reports diagnostics without producing an artifact —
the fast loop for editors and CI. Exit code 0 when clean, 1 when anything was
reported. Add --json for tooling (see Diagnostics below).
vyi test
Discovers every *.tests.vyi file under the directory (recursively), compiles
and runs each, and renders a pass/fail tree with a summary. Its exit code is
the number of test files that failed, so it slots directly into CI. Test
files are ordinary Vyi programs using the @testing package — guide
16 — Testing covers writing them. Accepted targets are
wasm (default), x86-64-linux, and arm64-linux.
vyi test # wasm (default)
vyi test --target x86-64-linux proj # same tests as native ELFsvyi ast
Prints an abstract syntax tree as JSON. Default is the post-transform tree the
compiler checked; --pre-elaborate dumps the parse tree (FnDecl,
OptionalType, …) before elaborate rewrites sugar. The playground AST tab uses
--pre-elaborate. --spans includes source positions.
Common flags and the package root
Every subcommand accepts --target (see below), --os, and --packages <dir>
— the root where @-packages like @io live. Resolution order: --packages,
then $VYI_STDLIB_PATH ($VYI_PACKAGES is a legacy alias), then the install
and development fallbacks documented in the
CLI reference. You only reach for
--packages or VYI_STDLIB_PATH when running a compiler you built yourself
from an unusual location.
Targets
Vyi compiles to three targets:
wasm(the default) — a WebAssembly module.vyi runexecutes it immediately under the embedded runtime; the same.wasmfile runs under any WASI-capable host.x86-64-linux— a native linux/x86-64 ELF executable (System V ABI). Needs a C compiler on the machine to link.arm64-linux— a native linux/AArch64 ELF executable. Same link requirements asx86-64-linux.
vyi run main.vyi # wasm (default)
vyi run --target x86-64-linux main.vyi # native x86-64
vyi run --target arm64-linux main.vyi # native arm64Programs behave the same on every target — same values, same output, same exit codes. The compiler's own test suite runs fixtures across targets and compares; you can switch targets late in a project without re-validating your logic.
Diagnostics
The compiler reports everything it can find in one pass — it does not stop
at the first error, and it keeps analyzing even when the file has parse errors,
so one vyi check shows you the whole repair list. Diagnostics come out as a
single stream, sorted by position and deduplicated, each with a source excerpt
and caret:
two.vyi:2:18: error: cannot assign ArrayPointer(u8) to i32
con a: i32 = "hi"
^^^^
two.vyi:3:19: error: cannot assign i32 to bool
con b: bool = 3
^
2 errorsvyi check --json emits the same diagnostics as a JSON array on stdout, each
entry attributed to its file with a 1-based range — the format the playground
and other tools consume:
[
{
"path": "err.vyi",
"op": "undefinedName",
"severity": "error",
"message": "undefined name \"tru\"",
"range": {
"start": { "line": 2, "col": 18 },
"end": { "line": 2, "col": 21 }
}
}
]op is a stable machine-readable code for the diagnostic kind; message is
the human text.
The VS Code extension
The vyi extension gives full language support for .vyi files. It runs one
language-server instance per Vyi project (a folder containing package.vyipac)
found anywhere under your workspace, plus one instance for stray .vyi files
that belong to no project — so a repository holding several Vyi packages just
works, and every feature sees the whole project, not just the open file.
What you get:
- Diagnostics as you type, across all files of the project — edit one file and errors it causes in another surface immediately.
- Hover with the declaration's signature, its resolved type, and its doc comment.
- Completion that understands position: struct-literal positions offer the type's remaining fields, member access offers fields/variants/methods, and when the expected type at the cursor is an enum its variants are offered directly (matching-type candidates rank first).
- Go to definition — including into the standard library and your dependencies; find references; rename across the project.
- Quick fixes: fill a struct literal's missing fields, add a
switch's missing arms, "did you mean …" for misspelled names, and add a missing import when another file exports the name. - Refactors: extract variable, extract function, inline variable (each extract drops you straight into a rename).
- Signature help while typing a call, inlay hints showing inferred types, semantic highlighting, document and workspace symbols, and folding.
Doc comments are lines starting with /// immediately above a declaration;
hover and completion surface them:
import { stdout } from "@io"
/// Clamps n to the 0..=255 range.
fn clamp(n: i32) i32 {
if n < 0 { return 0 }
if n > 255 { return 255 }
return n
}
fn main() !u8 {
stdout.writeInt(i64(clamp(300))) // hover `clamp` to see the doc
stdout.write("\n")
return Ok(0)
}The extension also understands package.vyipac manifests: unknown keys,
malformed versions, and entry paths that don't exist are flagged in place, and
key completion knows the manifest schema. .vyipac and .vyisum files get
syntax highlighting too.
Feature toggles live under the vyi.* settings (inlay hints, semantic
highlighting, diagnostics, and code actions can each be switched off). Set
vyi.languageServer.target to wasm (default) or x86-64-linux so analysis
matches the target you build and run with — the extension restarts the server
when path or target changes. Vyi: Restart Language Server(s) is there when
you need a manual restart.
The language server and the playground
All editor intelligence comes from one standalone binary, vyi-language-server,
which speaks the Language Server Protocol over stdio (it accepts the
conventional --stdio flag). It shares the compiler's front end, so what the
editor tells you and what vyi check tells you never disagree. Any
LSP-capable editor can use it — point your editor's LSP client at the binary
for .vyi files.
The web playground wraps the same pieces in a browser page: a Monaco editor
with diagnostics, hover, go-to-definition, outline, and semantic highlighting
from the same language server, plus tabs showing the program's output, the
generated WebAssembly text, and the AST. It runs locally from the repository
(website/run.sh) and serves on one origin.
See also: reference/toolchain/install, reference/toolchain/cli, reference/toolchain/targets.