Nothing installed to a program of your own, in eight steps. Every command is written out in full, and every output is what the command actually prints.
Keal is one binary. It carries the prelude and the C runtime inside it, so there is nothing to install beside it. Take the archive for your machine from the latest release, unpack it, and put the keal file somewhere on your PATH.
Linux needs glibc 2.34 or newer — Ubuntu 22.04, Debian 12, RHEL 9 and later. macOS downloads are unsigned, so clear the quarantine flag once. There is no prebuilt archive for Linux on ARM; on that machine, and on any platform not in the list, build from source instead — it is the step below and it works everywhere Rust does.
xattr -d com.apple.quarantine keal
git clone https://github.com/geneacta/keal.git cd keal cargo build --release cargo install --path .
Two commands, and they answer different questions. keal version says the binary is on your PATH and runs. keal doctor says what it can do on this machine: a C compiler unlocks keal build, and the rest are for talking to other languages. Nothing here is required to run a program — the first four steps need none of it.
keal version
keal 1.3.0
keal doctor
keal doctor — the interop toolchains on this machine
cc cc (Ubuntu 15.2.0-16ubuntu1) 15.2.0
verified against: Apple clang 21.0.0
unlocks: keal build (required for native)
cargo cargo 1.98.0 (797e8a9bc 2026-08-05)
verified against: rustc 1.98.0
unlocks: building the toolchain (required)
go MISSING — Go interop (c-archive)A file is a program. There is no class to declare, no main to write, no project to create first: statements at the top level run in the order they are written. Put this in a file called hello.keal, anywhere you like.
println("hello, world")That is the whole cycle: write, run. No build step, no configuration file, no directory layout the tool insists on.
keal hello.keal
hello, world
Sooner rather than later, and that is the point. Keal is statically typed: the mistake below is caught before anything runs, and keal check asks for that check without running the program at all. The error names the file, the line, the column, what it found and what it expected.
val n: Int = "quarante-deux" println(n)
keal check oops.keal
error: initializer has type `String`, but `Int` was expected --> oops.keal:1:14 | 1 | val n: Int = "quarante-deux" | ^ 1 error found
Keal has three engines, and all three run the source you just wrote. keal alone uses the bytecode VM — the default, and the fast way to run something now. --ast uses the tree-walking interpreter, which is the specification the other two are checked against. keal build compiles through C to a real executable that needs no Keal installed to run — that one, and only that one, needs a C compiler.
They must print the same bytes. That is not a slogan: it is what the test suite checks on every program it has, and it is how nearly every defect in this compiler has been found — one engine disagreeing with the other two.
keal hello.keal # the bytecode VM, the default keal --ast hello.keal # the tree-walking interpreter keal build hello.keal # a native executable, through C ./hello
hello, world hello, world hello hello, world
A Keal file can name its own interpreter on the first line, which makes it an ordinary executable on macOS and Linux. Nothing else changes: it is the same language and the same file, and keal build still turns it into a binary the day you want one.
#!/usr/bin/env keal
println("hello from a script")chmod +x script.keal ./script.keal
hello from a script
The tour is fifteen chapters and about half an hour, every snippet a real program with its real output. The docs are the reference once you want the rules rather than the taste of it. keal repl gives you a prompt to try one line at a time. And if you already know another language, the coming from… guides start from what you already do.
keal repl