Your first program

Scaffold a project

bash
cleat new myapp

This creates:

text
myapp/
├── cleat.toml     # Project manifest
└── main.cleat     # Entry point

Project manifest

cleat.toml:

toml
[project]
name = "myapp"
version = "0.1.0"
entry = "main.cleat"

[build]
output = "myapp"

Fields:

The minimal program

main.cleat:

cleat
import "std/io"

fn main() -> int needs { io } {
    io.println("hello from myapp")
    return 0
}

Every Cleat program has a fn main() -> int that returns an exit code. The needs { io } clause declares that this function performs I/O — without it, calling io.println would be a compile error.

Build and run

bash
cd myapp

# Compile and run in one step
cleat run main.cleat

# Or compile to a binary
cleat build
./myapp

When you run cleat build with no arguments inside a directory with cleat.toml, the compiler reads the manifest and uses entry as the source file and output as the binary name.

Adding a test

Add a test block to main.cleat:

cleat
import "std/io"
import "std/strings"

fn greet(name: string) -> string {
    return "hello, ${name}!"
}

fn main() -> int needs { io } {
    io.println(greet("cleat"))
    return 0
}

test "greet produces correct output" {
    let result = greet("world")
    assert(result == "hello, world!")
}

test "greet handles empty name" {
    assert(strings.contains(greet(""), "hello"))
}

Run tests:

bash
cleat test main.cleat

Output:

text
=== RUN   test "greet produces correct output"
--- PASS  test "greet produces correct output"
=== RUN   test "greet handles empty name"
--- PASS  test "greet handles empty name"

2 tests: 2 passed, 0 failed

Tests live alongside production code. No separate test files needed. See Test Runner for details.

Next steps

Edit this page on GitHub