Skip to content

Your first Khora project

A Khora package has a khora.toml manifest and source files, conventionally under src/. This walkthrough adds a small function and a test, then formats, checks, tests, builds, and runs the package with the installed khora toolchain.

If khora --version does not work yet, start with Installation. For the 0.4 release candidate, use its explicit candidate install after publication rather than the plain stable installer. khora new pins whichever compiler ran it: keep 0.4.0-rc.2 in a candidate project, and pin Khora-repository dependencies to v0.4.0-rc.2. The manifest below shows the stable 0.4.0 release, which is installable only after it is published.

Create one with khora new:

Terminal window
khora new hello_khora
cd hello_khora

which writes this:

hello_khora/
├── .gitignore
├── khora.toml
└── src/
└── main.kh

khora new --lib writes a library instead. Creating the same files by hand works too; khora new only saves the typing and writes the [toolchain] pin for the compiler that ran it.

src/ is the convention, but the package is the manifest’s directory, not src/ alone: every .kh file beside khora.toml or under any directory below it is compiled. A scratch file dropped at the package root is part of the package and its errors are reported against it.

Three directories are left out of that walk: target/, .git/, and any directory with a khora.toml of its own — so a nested package or a vendored copy stays its own package rather than being absorbed into its parent. src/bin/ is left out too, but only of the package’s own compilation: each file there is built as a program of its own against the package’s modules, and is still checked.

Delete a scratch file or move it under a directory with its own khora.toml; there is no ignore list.

The manifest names the package and says which Khora builds it:

[package]
name = "hello_khora"
version = "0.1.0"
# Which Khora builds this project. Required.
[toolchain]
version = "0.4.0"

The [toolchain] version is required, and it is what makes a project build the same way on the next machine: run any command here with a different Khora on your path and it hands the command over to the one this project asks for. Every key is in the manifest reference.

Put this in src/main.kh:

module hello_khora::main;
import std::core::{assert, print};
fn double(value: Int) -> Int {
value * 2
}
test "double returns twice its input" {
assert(double(21) == 42);
}
pub fn main() -> Int {
print("Hello, Khora!");
0
}

The Language Reference goes deeper on each construct once the workflow is running.

From the package root:

Terminal window
khora check .

Use check constantly while you work. It validates the package without paying the cost of native code generation and linking.

Khora has one canonical formatter:

Terminal window
khora fmt .

It keeps the line breaks you chose and normalizes everything else: indentation, spacing, sorted import lists, and a comma after the last element of any list broken across lines, so adding an element changes one line. A tuple or a parenthesized expression never gets one, because (e,) is a one-tuple. The formatter changes no other token.

In CI, check formatting without changing files:

Terminal window
khora fmt . --check

See Values and functions for the core expression and function model.

Terminal window
khora test .

The test runner discovers test blocks in the package and reports failures through the CLI. For testing patterns around capabilities, typed failure, and cancellation, see Testing.

Terminal window
khora doc

Run inside a package, this reads the /// and //! comments from its src and writes a page per module into docs/api beside the khora.toml. Name sources or a destination when you want different ones, as in khora doc src --out reference.

It keeps a .khora-doc record beside the pages listing the ones it generated. That is what lets a later run delete the page of a module you removed without touching anything it did not write, so a hand-written file in the same directory is safe and is reported rather than removed. khora doc --check writes nothing and fails when a checked-in page no longer matches its source, which is how a project keeps generated documentation honest in CI.

Terminal window
khora build .

The program goes in build/, named after the package, so nothing a build makes lands among your sources. khora new writes a .gitignore with build/ in it for exactly that reason.

Run it on macOS or Linux:

Terminal window
./build/hello_khora

Or on Windows:

Terminal window
.\build\hello_khora.exe

--out puts it somewhere else, under whatever name you give it:

Terminal window
khora build . --out dist/hello

You should see:

Hello, Khora!

For an optimized build, add --release:

Terminal window
khora build . --release

The language server uses the same compiler queries as khora check, so editor diagnostics and command-line diagnostics stay aligned. Continue with Editor setup.

A useful path from here is:

  1. Expressions — values, functions, lambdas, pipelines
  2. Types — records, variants, wrappers, generics
  3. Patterns — matching and destructuring
  4. Failures — raises, !, catch, attempt
  5. Capabilities — effect, handler, with, context
  6. Concurrency — fibers, nurseries, cancellation

For exact declarations while you work, browse the Standard Library reference.

Khora 0.4.0built frombd964738afb6on 2026-10-17 20:41ZVersioningSecurityContributingReleasesSource