# Makori Programming Language > Makori is a compiled language for backend development. No GC, compiles to native via C. ## Docs - [Makori ABI And Plugin Seed](https://mako-lang.com/docs/abi) - [Makori builds (v0.6.5)](https://mako-lang.com/docs/build) - [Makori Built-in Functions Reference](https://mako-lang.com/docs/builtins) - [Changelog](https://mako-lang.com/docs/changelog) - [Contributing to Makori](https://mako-lang.com/docs/contributing) - [Debugging Mako](https://mako-lang.com/docs/debug) - [Makori](https://mako-lang.com/docs/docs-overview) - [Makori language guide](https://mako-lang.com/docs/guide) - [Makori keywords](https://mako-lang.com/docs/keywords) - [Makori language](https://mako-lang.com/docs/language) - [Makori performance](https://mako-lang.com/docs/performance) - [Makori release & cross-platform guide](https://mako-lang.com/docs/release) - [Makori roadmap](https://mako-lang.com/docs/roadmap) - [Makori security](https://mako-lang.com/docs/security) - [Makori status (adversarial / verified)](https://mako-lang.com/docs/status) - [Makori vision](https://mako-lang.com/docs/vision) - [WASM / WASI (preview1 beachhead + browser/edge starter)](https://mako-lang.com/docs/wasm) ## Book - [The Makori Book](https://mako-lang.com/book/book-toc) - [Introduction](https://mako-lang.com/book/ch00-introduction) - [1. Preface -- Why Mako Exists](https://mako-lang.com/book/ch01-preface) - [2. Getting Started](https://mako-lang.com/book/ch02-getting-started) - [3. Language Tour](https://mako-lang.com/book/ch03-language-tour) - [4. Ownership: hold, share, and arenas](https://mako-lang.com/book/ch04-ownership) - [5. Errors and Result Types](https://mako-lang.com/book/ch05-errors) - [6. Concurrency: Crews, Channels, and Actors](https://mako-lang.com/book/ch06-concurrency) - [7. Standard Library](https://mako-lang.com/book/ch07-stdlib) - [8. Networking & HTTP](https://mako-lang.com/book/ch08-networking) - [9. Data: JSON, SQL, and Files](https://mako-lang.com/book/ch09-data) - [10. Packages, Workspaces, and Tooling](https://mako-lang.com/book/ch10-packages) - [11. Speed and Safety](https://mako-lang.com/book/ch11-speed-safety) - [12. Cross-Platform and WASI](https://mako-lang.com/book/ch12-cross-platform) - [13. Tooling](https://mako-lang.com/book/ch13-tooling) - [14. Cookbook](https://mako-lang.com/book/ch14-cookbook) - [15. Appendix](https://mako-lang.com/book/ch15-appendix) ## Standard Library - [Makori standard library](https://mako-lang.com/stdlib) ## How-To Guides - [Getting Started](https://mako-lang.com/howto/01-getting-started) - [Building HTTP JSON APIs](https://mako-lang.com/howto/02-http-apis) - [Errors and Debugging](https://mako-lang.com/howto/03-errors-debugging) - [Packages and Dependencies](https://mako-lang.com/howto/04-packages) - [Concurrency](https://mako-lang.com/howto/05-concurrency) - [Memory Management](https://mako-lang.com/howto/06-memory) - [Compiling to WebAssembly (WASI)](https://mako-lang.com/howto/07-wasi) - [Testing](https://mako-lang.com/howto/08-testing) - [Release Builds](https://mako-lang.com/howto/09-release-builds) - [Collections: maps, slices, and bag values](https://mako-lang.com/howto/10-collections) - [How-To Guides](https://mako-lang.com/howto/README) --- # Full Content ## The Makori Book (book/book-toc) Summary Introduction The Makori Book 1. Preface — Why Mako 2. Getting Started 3. Language Tour 4. Ownership 5. Errors & Result 6. Concurrency 7. Standard Library 8. Networking & HTTP 9. Data: JSON, SQL, Files 10. Packages, Workspaces, fmt, test 11. Speed & Memory Safety 12. Cross-platform & WASI 13. Tooling 14. Cookbook 15. Appendix ## Introduction (book/ch00-introduction) Introduction Welcome to The Makori Book -- the official guide to learning and using the Mako programming language. What is Mako? Makori is a systems and backend language built for speed first, with first-class concurrency and parallelism, plus clarity and safety. Syntax is Mako’s own. Safety comes from ownership and arenas — not a GC. Native performance is a design goal (compiled to C with -O3 -flto). It compiles .mko source files directly to native binaries via Cranelift (default), or optionally through C or LLVM backends. On macOS, no external toolchain is needed — the compiler ships with a bundled linker. Memory safety uses hold / share and arenas. Concurrency and parallelism are language features: structured crew / kick / join, fan across cores, channels, actors — no free-fire leaks, no async coloring. Makori is currently at version 0.5.7. This book teaches idiomatic Mako as it ships today. Identity checklist: IDENTITY.md. Area Where Generics (structs/enums/bounds) language tour § Generics · GUIDE §6 Channels (incl. struct/tuple + len/cap) ch. 6 concurrency · howto/05 Collections (maps/slices/bags) ch. 3 · cookbook · howto/10 Low ceremony ERGONOMICS.md Who is this book for? This book is for programmers who want to build: Backend services (REST APIs, gRPC endpoints, WebSocket servers) Infrastructure tools (proxies, load balancers, protocol stacks) Command-line applications and developer tools Real-time systems with deterministic latency Database engines and storage layers AI services and data pipelines You do not need prior systems programming experience, but you should be comfortable with at least one programming language. The book starts from first principles and builds up to advanced topics. A quick taste Here is a small Mako program (Fibonacci): fn main() { print("hello from mako") print_int(fib(10)) } fn fib(n: int) -> int { if n <= 1 { return n } return fib(n - 1) + fib(n - 2) } Running it: mako run hello.mko # hello from mako # 55 Methods use Makori’s on form; multi-return uses tuples: struct Point { x: int y: int } on Point { fn distance(self) -> int { return self.x + self.y } } fn divmod(a: int, b: int) -> (int, int) { return (a / b, a % b) } fn main() { let p = Point { x: 3, y: 4 } print_int(p.distance()) let q, r = divmod(17, 5) print_int(q) print_int(r) } Error handling with Result (compiler enforces handling): fn parse_port(s: string) -> Result[int, string] { let v = parse_int(s)? if v <= 0 || v > 65535 { return error("port out of range") } Ok(v) } fn main() { match parse_port("8080") { Ok(p) => print_int(p), Err(e) => print(e), } } And a glimpse of ownership and concurrency: fn main() { // hold gives move semantics -- use-after-move is a compile error hold let msg = "important data" process(msg) // print(msg) // compile error: use of moved value `msg` // Arena allocators for request-scoped memory arena a { let mut buf = make([]int, 0, 1024) buf = append(buf, 42) print_int(buf[0]) } // everything in arena `a` freed here -- one deallocation for the region } fn process(s: string) { print(s) } How this book is organized The book is split into chapters that build on each other. If you are new to Makori, read chapters 1 through 6 in order. They cover installation, syntax, ownership, and error handling -- the foundation you need for everything else. Chapter What you learn 1. Preface Why Mako exists, design philosophy 2. Getting Started Install, first project, tooling 3. Language Tour Syntax, types, operators, control flow 4. Ownership hold / share / arenas / scope cleanup 5. Errors Result, ? operator, error wrapping 6. Concurrency crew blocks, channels, actors 7. Stdlib Standard library packages by area 8. Networking HTTP, TLS, WebSocket 9. Data JSON, SQL, file I/O 10. Packages mako.toml, dependencies, workspaces 11. Speed & Safety Release builds, security model 12. Cross-platform Build targets, WASI 13. Tooling LSP, formatter, debugger 14. Cookbook Practical recipes (HTTP, collections, …) 15. Appendix Keywords, types, map grid, flags How to read this book If you are new to Makori: Start at Chapter 2 and read sequentially through Chapter 6. These chapters introduce the language foundations step by step, with each concept building on the previous one. Do not skip the ownership chapter -- it is central to how Makori programs are structured. If you are building a service: After the foundations, jump to Chapters 7 through 10 for standard library coverage, networking, data handling, and package management. If you want recipes: Chapter 14 is a cookbook index that links into the howto/ directory with focused, task-oriented guides. If something looks wrong: The compiler is the source of ## 1. Preface -- Why Mako Exists (book/ch01-preface) 1. Preface -- Why Mako Exists The problem Building backend services, infrastructure, and developer tools requires four things at once: simplicity, memory safety, predictable performance, and fast iteration. Most approaches force a trade-off: Managed runtimes give safety and a rich standard library but pay with garbage collection pauses, unpredictable latency spikes, and heavier deployment stories. Low-level systems approaches give total control but leave memory safety, ownership discipline, and concurrency correctness to the programmer's vigilance. Ownership-focused approaches give strong safety mechanisms but can feel heavy for everyday HTTP servers and session-oriented work. Makori's position is practical: you should not have to choose between safety and simplicity. The language is designed so that the common case gets compiler and runtime safety checks without excessive ceremony, with explicit annotations where they prevent specific classes of bugs. The Makori bet Active memory/resource safety without a mandatory garbage collector. Simple structured concurrency. Fast compiles. Clean error handling. Single-binary deployment. A strong standard library. Great tooling from day one. These are the shipped parts of Makori 0.2.4. The status matrix separates implemented behavior from roadmap goals and platform-dependent paths. Design philosophy 1. Clarity over cleverness Mako favors explicit, readable code. There are no implicit conversions between numeric types. Assignment (=) and equality (==) are visually distinct. Control flow uses braces and does not rely on indentation. The formatter (makori fmt) enforces a single canonical style so teams never argue about formatting. fn classify(code: int) -> string { match code { 200 => "ok", 404 => "not found", 500 => "server error", _ => "unknown", } } 2. Safety at compile time, not runtime The ownership system (hold and share) catches use-after-move and enforces the resource rules implemented by the compiler. Result types are enforced -- you cannot silently ignore a fallible operation. Mako actively prevents several important classes of mistakes; generated C, FFI, and platform libraries remain outside the Mako type system. fn safe_divide(a: int, b: int) -> Result[int, string] { if b == 0 { return error("division by zero") } Ok(a / b) } fn main() { // This line would be a compile error if uncommented: // safe_divide(10, 0) // error: unused Result let r = safe_divide(10, 0) match r { Ok(v) => print_int(v), Err(e) => print(e), } } 3. No garbage collector Makori provides active memory/resource safety mechanisms without a tracing garbage collector. These mechanisms prevent important classes of bugs, but are not a formal proof for generated C, FFI, or every program: Scope-based cleanup: Local values are freed when their enclosing scope exits. defer statements run cleanup in LIFO order. Ownership tracking: hold bindings enforce move semantics. When a value is moved, the original binding becomes unusable -- caught at compile time. Arena allocators: For request-scoped work (HTTP handlers, message processing), an arena allocates many objects and frees them all at once when the arena exits. One deallocation for an entire request's worth of memory. This means no tracing-GC pauses or stop-the-world collector events. Latency still depends on allocation, I/O, scheduling, and the surrounding C/FFI code. 4. Fast compiles Makori compiles .mko sources to C, then invokes clang. This pipeline is fast: incremental builds recompile only changed translation units. Parallel object compilation (makori build -j 8) scales with cores. The result is a tight edit-compile-run loop even for large projects. 5. Single binary deployment makori build --release can produce a statically-linked native binary on supported targets. In that case there is no Makori runtime to install on the target machine; platform libraries and optional integrations can still impose their own requirements. 6. Batteries included The standard library covers the common needs of backend development: HTTP/1.1 and HTTP/2 client and server TLS with certificate verification JSON encoding and decoding SQL database access (SQLite, PostgreSQL) WebSocket client and server UUID generation, base64, hashing File I/O, path manipulation, environment variables Logging with timestamps Regular expressions Sorting, string utilities, byte manipulation You should be able to build a production service without reaching for third-party packages for basic functionality. 7. Structured concurrency Concurrency in Makoriri is structured through crew blocks. A crew spawns tasks that must all complete before the crew exits. Combined with typed channels (chan[T]) and actors, this makes concurrent programs easy to reason about: no dangling goroutines, no fire-and-f ## 2. Getting Started (book/ch02-getting-started) 2. Getting Started This chapter walks you through installing Mako, creating your first project, understanding the project structure, and setting up your editor. System requirements To build and run Makori programs you need: macOS: nothing — the release binary is fully self-contained (bundled linker) Linux: gcc or clang for linking (apt install gcc or apt install clang) Windows: LLVM clang on PATH A POSIX-like shell (bash/zsh on macOS/Linux; PowerShell on Windows) Optional dependencies for full standard library support: OpenSSL (TLS) libnghttp2 (HTTP/2) SQLite (database) libpq (PostgreSQL) Installing Mako macOS and Linux (recommended) From a source checkout: make install This installs the mako binary to ~/.local/bin/mako and runtime headers to ~/.local/share/mako/runtime. Make sure ~/.local/bin is in your PATH. Alternatively, use the install script directly: ./scripts/install.sh Verify the installation: mako version # mako version mako0.6.2 darwin/arm64 The --version flag produces the same output: mako --version # mako version mako0.6.2 darwin/arm64 For verbose output including the git commit (when available): mako version -v Building from source If you want to build from the repository: git clone https://github.com/mako-lang/mako.git cd mako cargo build --release You can run the compiler directly without installing: cargo run --release -- version cargo run --release -- run examples/hello.mko Then install when ready: make install Windows (PowerShell) cargo build --release .\scripts\install.ps1 mako version On Windows, clang must be on PATH. Install via choco install llvm or download from the LLVM releases page. On macOS no external tools are needed — the release binary ships with a bundled linker. Runtime path override The compiler looks for runtime headers at $PREFIX/share/mako/runtime. If you installed to a non-standard location, set the MAKO_RUNTIME environment variable: export MAKO_RUNTIME=/opt/mako/runtime The mako doctor command After installation, run makori doctor to verify your environment is correctly configured: mako doctor This checks: The mako binary is in PATH and executable System linker is available (Linux/Windows; not needed on macOS) Runtime headers are found at the expected path Optional dependencies (OpenSSL, SQLite, etc.) are detected The standard library path resolves correctly If anything is misconfigured, makori doctor prints actionable guidance on how to fix it. Your first program Create a file called hello.mko: fn main() { print("hello from mako") } Run it: mako run hello.mko # hello from mako That is the entire workflow. makori run compiles the source to a native binary and executes it in one step. Creating a project with mako init For anything beyond a single file, use makori init to scaffold a project: mako init myapp --name myapp cd myapp This creates: myapp/ mako.toml -- project manifest main.mko -- entry point Run the generated project: mako run main.mko Backend service scaffold For an HTTP-oriented service layout: mako init mysvc --backend cd mysvc mako run main.mko This generates a project with HTTP server boilerplate and route handlers. Workspace scaffold For a project with multiple members (library + application): mako init myws --workspace cd myws mako check . mako run -p app Project structure: mako.toml The mako.toml file is the project manifest. It declares the project name, version, dependencies, and build configuration: [package] name = "myapp" version = "0.1.0" [dependencies] # path dependencies utils = { path = "../utils" } # registry dependencies (when available) # json = "1.0" [build] # parallel compilation jobs jobs = 8 When you run makori build main.mko in a directory with a mako.toml, the binary name is derived from the package name. The build and run cycle Command What it does makori run file.mko Compile and execute in one step makori check file.mko Type-check without producing a binary (fast) makori build file.mko Compile to a native binary makori build --release file.mko Optimized build (-O3 -flto) makori build -j 8 file.mko Parallel object compilation makori test examples/testing Run the test suite makori fmt file.mko Format source to canonical style Incremental compilation Incremental compilation is on by default. The compiler caches intermediate artifacts and only recompiles translation units that have changed. This makes the edit-compile-run loop fast even for larger projects. Release builds For production deployment, always use --release: mako build --release main.mko This enables -O3 optimization and link-time optimization (-flto), producing a smaller, faster binary. Static linking depends on the target and toolchain; Linux musl is the documented static path, while glibc and platform libraries may remain dynamic. See Cross-platform builds. A more complete first program Here is a slightly more involved example showing functions, types, ## 3. Language Tour (book/ch03-language-tour) 3. Language Tour This chapter is a comprehensive tour of Makori's syntax and semantics. Sources use the .mko extension. Every program begins with fn main(). Program structure Top-level items in a Makori file: pack, pull, export, fn, struct, enum, actor, interface, const, and extern "C". fn main() { print("hello") } Functions can appear in any order -- the compiler resolves them regardless of declaration position in the file. Variables: let and let mut Variables are declared with let. They are immutable by default. fn main() { let x = 42 // immutable, type inferred as int let y: int = 10 // explicit type annotation let name = "mako" // inferred as string // x = 99 // compile error: x is not mutable let mut counter = 0 // mutable variable counter = counter + 1 print_int(counter) } Type annotations are optional when the type can be inferred from the initializer. Prefer annotations on function signatures and omit them on locals when the type is obvious. Primitive types Type Description int Platform-native integer (maps to 64-bit in the C backend) int64 64-bit signed integer int32 32-bit signed integer int8 8-bit signed integer uint64 64-bit unsigned integer byte 8-bit unsigned (alias for uint8) float Floating-point (64-bit double) float64 Explicit 64-bit float bool Boolean (true or false) string Immutable UTF-8 byte sequence fn main() { let a: int = 10 let b: int64 = 1000000 let c: int32 = 42 let d: int8 = 7 let e: uint64 = 99 let f: byte = 65 let g: float = 3.14 let h: bool = true let s: string = "hello" print_int(a) print_int64(b) print_int32(c) print_int8(d) print_uint64(e) print_int(int(f)) } There are no implicit conversions between numeric types. You must convert explicitly. Type conversions Use the target type as a function to convert: fn main() { let a: int = 10 let b = int64(a) // int -> int64 let c = int32(b) // int64 -> int32 let d = int8(c) // int32 -> int8 let e = uint64(a) // int -> uint64 let f = byte(65) // int literal -> byte let g = float64(a) // int -> float64 let h = int(g) // float64 -> int (truncates) // String conversions print(string(a)) // int -> string (decimal representation) print(string(b)) // int64 -> string // String <-> bytes let buf = bytes("hello") // string -> []byte print(string(buf)) // []byte -> string let buf2 = []byte("world") // alternative syntax print(string(buf2)) } Strings Strings are immutable UTF-8 byte sequences. len() returns the byte length. Indexing returns bytes. Use rune_count() for Unicode code point count. fn main() { // Literals and escapes let s = "hi\tthere\n" print_int(len(s)) // byte length // Concatenation with + let t = "ma" + "ko" print(t) // Comparison — == and != work directly on strings if t == "mako" { print("equal") } if t != "other" { print("not equal") } // Unicode let u = "cafe\u0301" print_int(len(u)) // byte length print_int(rune_count(u)) // code point count // Byte indexing let hello = "hello" print_int(int(hello[0])) // 104 (ASCII 'h') print_int(int(hello[1])) // 101 (ASCII 'e') // Slicing (by byte offsets, yields string) print(hello[1:4]) // "ell" print(hello[:2]) // "he" print(hello[3:]) // "lo" print(hello[:]) // "hello" // Empty strings let empty = "" print_int(len(empty)) // 0 // String helpers if str_eq("x", "x") { print("equal") } if str_contains("hello world", "world") { print("found") } // Range over string yields runes (index is byte offset) for i, r in range "abc" { print_int(i) print_int(r) } } Arrays and slices Slices ([]T) are dynamically-sized views into contiguous memory. They have a length and capacity. Literal syntax creates a slice directly. fn main() { // Slice literal let mut s = [1, 2, 3] print_int(len(s)) // 3 print_int(cap(s)) // 3 (or more, implementation-defined) // Indexing (zero-based) print_int(s[0]) // 1 print_int(s[2]) // 3 // Mutation (requires let mut) s[0] = 99 print_int(s[0]) // 99 // Append (may reallocate) s = append(s, 4) print_int(len(s)) // 4 print_int(s[3]) // 4 // Slicing: s[low:high] let t = s[1:3] print_int(len(t)) // 2 print_int(t[0]) // 2 print_int(t[1]) // 3 ## 4. Ownership: hold, share, and arenas (book/ch04-ownership) 4. Ownership: hold, share, and arenas Makori has no garbage collector. Active memory/resource safety mechanisms include compile-time ownership checks and runtime scope/region cleanup. They prevent important classes of bugs; generated C and FFI remain outside the Mako type system: Scope-based cleanup -- local values are freed when their scope exits hold bindings -- enforce move semantics with compile-time tracking share bindings -- reference-counted shared reads Arena allocators -- bulk allocation and single-point deallocation This chapter covers each in detail. Scope-based cleanup: the default Most values in Makori live on the stack or are heap-allocated and freed when their enclosing scope exits. This is the default -- no annotation needed. Owning strings, slices, maps, and struct Own fields free at scope exit, reassign, break/continue, return transfer, ? early-return, and match arm exit (unless moved into a larger result). Live Own values move into a new freer; aliases and field/index borrows clone so only one freer runs. fn main() { let x = 42 // lives for the duration of main let s = "hello" // same if true { let inner = 99 // lives only within this block print_int(inner) } // `inner` is gone here print_int(x) } For explicit cleanup ordering, use defer: fn process() { defer print("cleanup done") print("processing") // "cleanup done" prints after "processing", before function returns } defer statements execute in LIFO order when the function exits: fn main() { defer print("third") defer print("second") defer print("first") print("body") } // Output: body, first, second, third Copy types Certain types are Copy -- they are duplicated rather than moved when assigned or passed. These types do not need ownership annotations: int, int64, int32, int8, uint64 byte float, float64 bool fn main() { let a = 42 let b = a // copies the value; both a and b are usable print_int(a) // fine print_int(b) // fine let f = 3.14 let g = f // copies print_int(int(f)) print_int(int(g)) } Copy types work the same way even under hold -- you can read them multiple times because the "move" is really a copy: fn main() { hold let x = 7 print_int(x) // first read print_int(x) // second read -- OK because int is Copy } hold -- move semantics hold bindings enforce unique ownership. When a hold value is rebound, passed to a function, or fully consumed, the original binding becomes dead. Using it after that point is a compile error. Basic move fn main() { hold let x = "hello" hold let y = x // x is moved into y print(y) // OK // print(x) // compile error: use of moved value `x` } Move into function calls Passing a hold value to a function is a consuming use: fn consume(s: string) { print(s) } fn main() { hold let msg = "important" consume(msg) // msg is moved into the function // consume(msg) // compile error: use of moved value `msg` } Single use is fine If you only use a hold binding once, there is no issue: fn id(n: int) -> int { return n } fn main() { hold let x = 42 print_int(id(x)) // single consuming use -- OK } Mutable hold bindings You can reassign a hold let mut binding before it is moved: fn main() { hold let mut x = 7 x = 9 // reassignment before any move print_int(x) // OK } Partial struct moves When a struct is under hold, you can move individual fields independently. Only the moved field becomes dead: struct Point { x: int, y: int, } fn main() { hold let p = Point { x: 1, y: 2 } let px = p.x // moves only p.x print_int(px) // OK print_int(p.y) // OK -- p.y was never moved // print_int(p.x) // compile error: p.x was moved } Control flow and moves The compiler tracks moves through all branches of if/else and match. A value is considered moved only if it is moved on all reachable paths: fn main() { hold let x = "hi" if 0 == 1 { let y = x // moves x in this branch print(y) } else { print(x) // uses x in this branch } // After the if/else, x MAY be moved (branch-dependent) // The compiler tracks this correctly } If one branch moves a value and another does not, the compiler understands that after the if/else the value's status depends on which branch executed. It will reject uses after the if/else because the move status is uncertain. Moves in loops The compiler is aware of loop re-entry. If a value is moved inside a loop body, it cannot be used on subsequent iterations: fn main() { hold let x = "data" let mut i = 0 while i < 1 { print(x) // OK on first iteration ## 5. Errors and Result Types (book/ch05-errors) 5. Errors and Result Types Mako errors are values. There is no null, no silent exception unwinding, and no way to accidentally ignore a fallible operation. If a function returns Result[T, E] and you do not handle it, the compiler rejects your program. The Result type Result[T, E] has exactly two variants: Ok(value) -- the operation succeeded, carrying a value of type T Err(error) -- the operation failed, carrying an error of type E Most Makori code uses Result[T, string] where the error is a human-readable message. Richer error types (structs, enums) are also supported. fn parse_positive(n: int) -> Result[int, string] { if n <= 0 { return error("must be positive") } return Ok(n) } fn main() { let r = parse_positive(5) match r { Ok(v) => print_int(v), Err(e) => print(e), } } Constructing errors Function Purpose Ok(value) Construct a success Result Err(msg) Construct a failure Result error(msg) Sugar for Err(msg) -- returns a Result errorf(fmt, args...) Formatted error (like printf for errors) fn validate_port(p: int) -> Result[int, string] { if p <= 0 { return error("port must be positive") } if p > 65535 { return errorf("port %d out of range", p) } return Ok(p) } error("...") and Err("...") are equivalent. Use whichever reads more naturally at the call site. error is preferred in most Makori code because it is concise and clearly signals failure. The ? operator The ? operator is the primary way to propagate errors up the call stack. When applied to a Result, it: If the Result is Ok(v), unwraps and returns the value v If the Result is Err(e), immediately returns Err(e) from the enclosing function fn parse_port(s: string) -> Result[int, string] { let v = parse_int(s)? // if parse_int fails, return its error if v <= 0 || v > 65535 { return error("port out of range") } Ok(v) } fn load_config() -> Result[int, string] { let port = parse_port("8080")? // propagates error if any Ok(port) } The ? operator can only be used inside a function that itself returns Result. The error types must be compatible. Chaining multiple ? operations fn setup_server() -> Result[int, string] { let port = parse_port("443")? let fd = bind_socket(port)? let listener = start_listening(fd)? Ok(listener) } Each ? is a potential early return. If any step fails, the function returns immediately with that error. This keeps the happy path linear and readable. Unused Result is a compile error One of Makori's strictest rules: you cannot ignore a Result. If a function returns Result and you call it without handling the return value, the compiler rejects the program. fn might_fail() -> Result[int, string] { return Ok(42) } fn main() { // might_fail() // compile error: unused Result let _ = might_fail() // OK: explicitly discarding let r = might_fail() // OK: binding it for later use match r { Ok(v) => print_int(v), Err(e) => print(e), } } For Result-returning operations, this rule means errors cannot silently slip by. The result must be consciously handled or explicitly discarded. Error wrapping with wrap_err When errors propagate through multiple layers, context is often lost. wrap_err adds context to an error result without discarding the original message: fn open_cfg(path: string) -> Result[int, string] { if str_eq(path, "") { return error("empty path") } if str_contains(path, "..") { return errorf("invalid path %s", path) } Ok(1) } fn load() -> Result[int, string] { let fd = open_cfg("bad..x")? Ok(fd) } fn main() { let r = load() let w = wrap_err(r, "load config") // The wrapped error contains both "load config" and "invalid path bad..x" assert(error_is(w, "invalid path")) assert(error_is(w, "load config")) print(error_string(w)) } wrap_err works like adding a prefix/context layer. The original error is preserved inside, and both the wrapper and the original can be matched with error_is. Inspecting errors Function Purpose error_is(r, substring) Check if the error chain contains a substring error_string(r) Flatten the entire error chain into a single string error_is error_is checks whether any part of the error chain (including wrapped layers) contains the given substring: fn main() { let r: Result[int, string] = error("file not found") let w = wrap_err(r, "loading config") if error_is(w, "file not found") { print("original error matched") } if error_is(w, "loading config") { print("wrapper matched") } if !error_is(w, "network") ## 6. Concurrency: Crews, Channels, and Actors (book/ch06-concurrency) 6. Concurrency: Crews, Channels, and Actors Mako concurrency is structured for ordinary crew tasks. Kicked tasks are joined when their crew scope ends, so they do not outlive that scope. Running work is cancelled cooperatively; a blocked C/FFI call can delay the join, and explicit detach is the documented process-scoped escape hatch. This chapter covers: Crew blocks and task management (crew, t.kick(), t.join()) Cancellation (t.cancel(), t.cancelled()) Data-parallel fan Channels (chan_new / make(chan[T], n) / chan_open[T], send, recv, close, chan_len / chan_cap, for v in range ch) Channel select (select, chan_select2, chan_select_value) Actors (actor, receive, Session_spawn, Session_send, Session_loop) Practical concurrent patterns Crew Blocks A crew block declares a structured concurrency scope. You name the crew handle (conventionally t or c) and use it to kick off concurrent tasks: fn work(n: int) -> int { return n * n } fn main() { crew t { let a = t.kick(work(7)) let b = t.kick(work(9)) let x = a.join() let y = b.join() print_int(x + y) // 49 + 81 = 130 } } Key rules t.kick(expr) spawns a new concurrent task that evaluates expr. It returns a join handle immediately. handle.join() blocks the caller until the kicked task completes and returns its result value. Automatic join on scope exit: when the closing } of the crew block is reached, any un-joined tasks are joined implicitly. No task escapes. One crew at a time per scope: you cannot nest crews in the same function without giving them different names. Why structured? For ordinary kicked tasks, the compiler checks that references passed into the task remain valid for the task's lifetime. This is what makes hold and share ownership work across threads; generated C, FFI, and explicit detached work remain outside that language-level guarantee. go f() — fire-and-forget When you don't need the join handle, go f() schedules a call onto the innermost enclosing crew — the same as t.kick(f()) with the result discarded. The crew still joins it at scope exit for ordinary kicked work; blocked C/FFI calls can delay the join: fn main() { crew t { go log_metrics() // == t.kick(log_metrics()) go flush_cache() // both are joined here, at the end of the crew } } Unlike Go's go, this is not a detached goroutine: go outside any crew is a compile error, because Makori never lets a task escape its scope. t.kick() In Detail t.kick() accepts any expression that returns a value. The expression becomes the body of a new thread: fn fetch_user(id: int) -> string { // ... network call ... return "user_" + string(id) } fn fetch_score(id: int) -> int { // ... database call ... return id * 10 } fn main() { crew t { let user_handle = t.kick(fetch_user(42)) let score_handle = t.kick(fetch_score(42)) // Both tasks run concurrently. Join them: let user = user_handle.join() let score = score_handle.join() print(user) print_int(score) } } Each kicked task runs on its own OS thread. The runtime tracks spawned and joined counts for observability (accessible via runtime_stats_json()). What may cross a kick (Send-like seed) Kick arguments must be sendable: Allowed Notes Copy scalars (int, bool, float, …) packed into the task string heap-cloned for the task Deep-POD named structs scalar/string/nested POD fields only Option / Result / tuples of sendables boxed payloads chan[T] handles shared; the channel is the sync point Rejected Prefer instead Arrays, maps, arenas pass data on a channel or rebuild inside the task Non-POD structs (map/slice fields) chan[Struct] for results; redesign fields struct Point { x: int, y: int } fn work(p: Point) -> int { return p.x + p.y } fn main() { crew t { let j = t.kick(work(Point { x: 3, y: 4 })) print_int(j.join()) // 7 } } For multi-field results from workers, send a named struct on a channel instead of packing fields into one int: struct Done { err: int, status: int, bytes: int } let ch = chan_open[Done](4) // worker: ch.send(Done { err: 0, status: 200, bytes: n }) // parent: let d = ch.recv() See SPEED.md and ERGONOMICS.md. t.join() Calling .join() on a kick handle does two things: Blocks the calling thread until the task finishes. Returns the task's result value. You can join tasks in any order. Join the fastest-completing task first to keep the pipeline flowing: fn slow_work() -> int { sleep_ms(100) return 1 } fn fast_work() -> int { sleep_ms(10) return 2 } fn main() { crew t { let slow = t.kick(slow_work()) let fast = t.kick(fast_work()) // Join fast first — we can use its result while slow is still running let f = fast.join() print_int(f) let s = slow.join() print_int(s) } } Cance ## 7. Standard Library (book/ch07-stdlib) 7. Standard Library Mako ships a standard library focused on backend development: strings, formatting, file I/O, networking, encoding, cryptography, synchronization, and database clients. Application packs also have Go-equivalent surfaces — same jobs, Mako names (concat not Join, matches not Match). Indexes never panic; parse failures are Result or (value, err), never nil. Full index: STDLIB.md. You can call many helpers as bare builtins (str_split, path_join, ...) or import packages for namespaced access (strings.split, path.clean, ...). pull "strings" pull "path" fn main() { let parts = strings.split("a,b,c", ",") print(strings.concat(parts, "/")) print(path.clean("/x/../y")) } Bare pull "strings" (or import "strings") resolves from the standard library directory (std/, overrideable via MAKO_STD). The import auto-aliases so strings.split works immediately. Strings The strings package provides operations on string values. Strings in Makori are owned, heap-allocated, null-terminated byte sequences with a length field. Builtins (no import needed) fn main() { // Length (bytes) print_int(len("hello")) // 5 print_int(rune_count("cafe\u0301")) // Unicode code points // Comparison if str_eq("a", "a") { print("equal") } // Search if str_contains("hello world", "world") { print("found") } // Concatenation let s = "ma" + "ko" print(s) // Indexing (byte access) let c = "hello"[0] // byte value print_int(int(c)) // 104 // Slicing (by bytes) print("hello"[1:4]) // "ell" print("hello"[:2]) // "he" print("hello"[3:]) // "lo" } Package functions import "strings" fn main() { let parts = strings.split("a:b:c", ":") print(strings.concat(parts, ", ")) // "a, b, c" print(strings.trim(" hi ")) // "hi" print(strings.to_upper("mako")) // "MAKO" print(strings.to_lower("MAKO")) // "mako" print(strings.replace("aXbXc", "X", "-")) // "a-b-c" if strings.has_prefix("hello", "he") { print("yes") } if strings.has_suffix("file.mko", ".mko") { print("mako file") } print_int(strings.index("hello", "ll")) // 2 print_int(strings.count("banana", "a")) // 3 let head, tail, ok = strings.cut_ok("a=b", "=") if ok { print(head) // a print(tail) // b } } String-to-number conversions fn main() { // Parse match parse_int("42") { Ok(n) => print_int(n) Err(e) => print(e) } // Format print(format_int(123)) print(string(42)) // int to string } fmt (Formatting) Format values into strings for output or logging: import "fmt" fn main() { print(format_int(42)) print(format_float(3.14)) print(format_bool(true)) // Sprintf-style (limited) log_info("request handled") log_warn("slow query") log_error("connection failed") } bufio (Buffered I/O) Buffered reading and writing for efficient I/O operations: pull "bufio" fn main() { let lines = bufio.scan_lines("a\nb\r\nc") for _, line in range lines { print(line) } print(bufio.peek_prefix("hello", 2)) // he } os (Operating System) File system operations, environment variables, and process interaction: fn main() { // File I/O let _ = write_file("/tmp/test.txt", "hello mako") let body = read_file("/tmp/test.txt") print(body) // "hello mako" // Environment let _ = env_set("APP_MODE", "production") let mode = env_get("APP_MODE") print(mode) // "production" // Command-line arguments print_int(argc()) if argc() > 1 { print(arg_get(1)) } // Exit // exit(1) } path Path manipulation (platform-aware joining, cleaning, splitting): import "path" fn main() { let p = path_join("foo", "bar") print(p) // "foo/bar" print(path_clean("/a/../b/./c")) // "/b/c" } path.matches is the equivalent of Go path.Match (join / match are keywords). * does not cross /. pull "path" pull "path/filepath" fn main() { print_int(int(path.matches("*.mko", "main.mko"))) print(filepath.rel("/a/b ## 8. Networking & HTTP (book/ch08-networking) 8. Networking & HTTP Makori provides a systems-level HTTP stack: synchronous, one-request-at-a-time per connection, with no colored async. You scale concurrency by running handlers inside crew blocks. This chapter covers TCP, HTTP/1.1, HTTPS, HTTP/2, WebSockets, REST APIs, and request routing patterns. TCP Fundamentals At the lowest level, Makori provides raw TCP socket operations: fn main() { // Server side let fd = tcp_listen(18082) let client = tcp_accept(fd) let _ = tcp_write(client, "hello from server\n") let _ = tcp_close(client) let _ = tcp_close(fd) } fn main() { // Client side let peer = tcp_connect("127.0.0.1", 18082) let data = tcp_read(peer) print(data) let _ = tcp_close(peer) } TCP operations block the calling thread. Use crew blocks to handle multiple connections concurrently. HTTP/1.1 Server The HTTP server API is synchronous and explicit. You bind a port, accept connections in a loop, inspect the request, send a response, and close. Minimal server fn main() { let fd = http_bind(18100) if fd < 0 { print("bind failed") return } print("listening on :18100") let c = http_accept(fd) if c >= 0 { let _ = http_respond(c, 200, "hello from mako\n") let _ = http_close(c) } let _ = http_close_listener(fd) } Core API functions Function Purpose http_bind(port) Bind and listen on a TCP port. Returns listener fd (< 0 on error). http_accept(fd) Accept one connection, parse the HTTP request. Returns connection handle. http_method(c) Get the request method (GET, POST, PUT, DELETE, etc.). http_path(c) Get the request path (e.g., "/users/42"). http_body(c) Get the request body as a string. http_header(c, name) Get a specific request header value. http_respond(c, status, body) Send response with text/plain content type. http_respond_ct(c, status, content_type, body) Send response with explicit content type. http_respond_json(c, status, json) Send response with application/json content type. http_close(c) Close the connection (frees the slot). http_close_listener(fd) Close the listening socket. Multi-request server loop fn main() { let fd = http_bind(18100) if fd < 0 { print("bind failed") return } print("http_server on :18100") let mut n = 0 while n < 50 { let c = http_accept(fd) if c < 0 { // accept failed, skip } else { let p = http_path(c) if str_eq(p, "/health") { let _ = http_respond_ct( c, 200, "application/json", "{\"ok\":true}\n" ) } else { if str_eq(p, "/") { let _ = http_respond(c, 200, "hello from mako\n") } else { let _ = http_respond(c, 404, "not found\n") } } let _ = http_close(c) n = n + 1 } } let _ = http_close_listener(fd) print("server done") } Request Inspection Method let c = http_accept(fd) let method = http_method(c) if str_eq(method, "POST") { // handle POST } else { if str_eq(method, "GET") { // handle GET } } Path let path = http_path(c) // path is the raw URI path, e.g. "/users/42" Body let body = http_body(c) // body contains the raw request body (up to Content-Length or 1MB max) Headers let host = http_header(c, "Host") let ua = http_header(c, "User-Agent") let ct = http_header(c, "Content-Type") print(host) print(ua) print(ct) Header lookup is case-insensitive. The runtime validates header names and values, rejecting CR/LF/NUL to prevent header injection attacks. Response Functions Plain text response let _ = http_respond(c, 200, "OK\n") Response with content type let _ = http_respond_ct(c, 200, "text/html", "<h1>Hello</h1>") JSON response let _ = http_respond_json(c, 200, "{\"status\":\"ok\"}") This is equivalent to http_respond_ct(c, 200, "application/json", body). Status codes The runtime maps standard status codes to reason phrases automatically: Code Meaning 200 OK 201 Created 204 No Content 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 405 Method Not Allowed 500 Internal Server Error Request Routing Patterns Simple path-based routing fn handle_request(c: int) { let method = http_method(c) let path = http_path(c) if str_eq(path, "/") { let _ = http_respond(c, 200, "home\n") } else { if str_eq(path, "/health") { let _ = http_respond_js ## 9. Data: JSON, SQL, and Files (book/ch09-data) 9. Data: JSON, SQL, and Files This chapter covers Makori's data handling capabilities: JSON encoding/decoding, SQLite and PostgreSQL database access, file I/O, and the broader encoding family. All database APIs enforce parameterized queries to prevent injection attacks. File I/O Reading and writing files fn main() { // Write a file let _ = write_file("/tmp/config.txt", "port = 8080\nhost = 0.0.0.0\n") // Read it back let content = read_file("/tmp/config.txt") print(content) } Path helpers import "path" fn main() { let p = path_join("data", "users.json") print(p) // data/users.json let clean = path_clean("/a/../b/./c") print(clean) // /b/c } Environment variables fn main() { let _ = env_set("APP_ENV", "production") let env = env_get("APP_ENV") print(env) // production } Buffered I/O For processing large files line by line: fn main() { let content = read_file("data.csv") let lines = str_split(content, "\n") let mut count = 0 for line in lines { if len(line) > 0 { count = count + 1 } } print_int(count) } File path safety Always validate paths before file operations: fn safe_read(path: string) -> string { if str_contains(path, "..") { print("error: path traversal rejected") return "" } return read_file(path) } JSON Makori provides both low-level JSON helpers and a derive macro for struct serialization. Building JSON objects json_ss (string key-value pairs) fn main() { let obj = json_ss("name", "Ada", "city", "London") print(obj) // {"name":"Ada","city":"London"} } json_ss takes alternating key-value string arguments and produces a JSON object string. json_object_from_map_ss Build JSON from a map: fn main() { let mut m = make(map[string]string, 4) m["name"] = "Grace" m["role"] = "engineer" m["team"] = "platform" let obj = json_object_from_map_ss(m) print(obj) // {"name":"Grace","role":"engineer","team":"platform"} } json_object_str (single key-value) fn main() { let field = json_object_str("status", "active") print(field) // {"status":"active"} } Extracting values json_get_string fn main() { let obj = json_ss("name", "Ada", "age", "36") let name = json_get_string(obj, "name") print(name) // Ada } json_get_int fn main() { let obj = "{\"count\":42,\"name\":\"test\"}" let count = json_get_int(obj, "count") print_int(count) // 42 } json_get_object (nested object extraction) fn main() { let doc = "{\"user\":{\"name\":\"Ada\",\"age\":36}}" let user = json_get_object(doc, "user") print(user) // {"name":"Ada","age":36} let name = json_get_string(user, "name") print(name) // Ada } Nested JSON json_nest (wrap object under a key) fn main() { let addr = json_ss("city", "Paris", "zip", "75001") let nested = json_nest("address", addr) print(nested) // {"address":{"city":"Paris","zip":"75001"}} } json_merge (combine two objects) fn main() { let person = json_ss("name", "Ada", "age", "36") let addr = json_nest("address", json_ss("city", "Paris", "zip", "75001")) let doc = json_merge(person, addr) print(doc) // {"name":"Ada","age":"36","address":{"city":"Paris","zip":"75001"}} } json_path_string / json_path_int (deep extraction) fn main() { let doc = "{\"user\":{\"name\":\"Ada\",\"address\":{\"city\":\"Paris\"}}}" let city = json_path_string(doc, "address", "city") print(city) // Paris } JSON Arrays fn main() { // Create arrays let nums = json_array_ints3(1, 2, 3) print(nums) // [1,2,3] let strs = json_array_strings2("hello", "world") print(strs) // ["hello","world"] // Push to arrays let more = json_array_push_string(strs, "mako") print(more) // ["hello","world","mako"] let more_nums = ## 10. Packages, Workspaces, and Tooling (book/ch10-packages) 10. Packages, Workspaces, and Tooling Makori uses a file-based package system. The preferred module primitives are pack, pull, and export: pack mylib — declares the current file's package identity. pull "path" — imports another pack (local file, relative path, or std). export fn / export struct — marks items as public to consumers. A mako.toml manifest coordinates multi-file projects and external dependencies. The makori pkg command manages the full lifecycle: initializing, adding, fetching, locking, and auditing packages. pack / pull / export — The Module System Every .mko file may declare its pack name at the top. Files that share the same pack name belong to the same logical unit: // mathutil.mko pack mathutil export fn add(a: int, b: int) -> int { return a + b } export fn mul(a: int, b: int) -> int { return a * b } // not exported — internal fn clamp(n: int, lo: int, hi: int) -> int { if n < lo { return lo } if n > hi { return hi } return n } A consumer pulls the pack and accesses exported symbols through the pack name: // main.mko pack main pull "./mathutil.mko" fn main() { print_int(mathutil.add(2, 3)) // 5 print_int(mathutil.mul(4, 5)) // 20 // mathutil.clamp(...) // compile error — not exported } Pull forms // Standard library — resolved from std/ pull "strings" // Local file (pack name becomes the qualifier) pull "./helpers.mko" // Explicit alias pull "./helpers.mko" as h // Grouped pulls pull ( "strings" "./db.mko" "./routes.mko" as r ) Bare path names like "strings" resolve under std/. MAKO_STD overrides the standard library root. Visibility rules Items without export are private to their pack. export works on fn, struct, enum, and const. Within the same pack (multiple files sharing a pack name), all items are visible to each other regardless of export. Consumers only see exported items. Types are pack-qualified at the consumer: eng.Table in annotations, return types, struct literals, and struct patterns (same alias as eng.table_new()). Multi-return of pack structs works: let t, n = eng.f(). Enums may use pack paths: eng.Red, eng.Green(n), or eng.Color.Red / eng.Color.Green(n). Relationship to import The older import keyword still works and is equivalent to pull in most contexts. New code should prefer pack/pull/export for clarity. mako.toml Format Every Mako package has a mako.toml at its root: [package] name = "myapp" version = "0.1.0" [dependencies] "helper" = { path = "../helper", version = "0.1.0" } "logger" = { git = "https://github.com/org/mako-logger.git", version = "0.2.0" } Package section Field Required Description name Yes Package name (used for import namespacing) version Yes SemVer version string (e.g., "0.1.0") Dependencies section Each dependency is keyed by its import name and specifies a source: [dependencies] "dep_name" = { path = "../relative/path", version = "0.1.0" } "dep_name" = { git = "https://...", version = "1.0.0" } "dep_name" = { git = "https://...", branch = "main" } "dep_name" = { git = "https://...", tag = "v1.2.3" } Source Description path Local filesystem path (relative to the manifest) git Git repository URL (cloned to .mako/deps/) Additional fields: - version — SemVer constraint for resolution - branch — Git branch to track (default: main) - tag — Specific git tag to pin How Imports Work Once a dependency is declared in mako.toml, its symbols are available under the dependency key as a namespace: # mako.toml [dependencies] "helper" = { path = "../helper", version = "0.1.0" } // main.mko — symbols accessed via helper.fn_name() fn main() { print_int(helper.add(20, 22)) print(helper.greet("world")) } // helper/lib.mko — exports functions directly fn add(a: int, b: int) -> int { return a + b } fn greet(name: string) -> string { return "hi " + name } Path dependencies are merged at compile time. The compiler resolves transitive dependencies automatically. File-Level Imports For single-file imports within the same package (no mako.toml needed), use pull (or the older import keyword): pull "./helpers.mko" fn main() { print_int(helpers.add(2, 3)) print(helpers.greet("mako")) } The pulled file's exported functions become available through the pack name as a qualifier. If the file declares pack helpers, that name is used; otherwise the filename basename is the default qualifier. When you run makori run main.mko, the compiler automatically finds and compiles all imported files -- you don't need to list them on the command line. Aliased imports Give an import a namespace with as. ## 11. Speed and Safety (book/ch11-speed-safety) 11. Speed and Safety Makori compiles to C, then to native machine code via clang. There is no garbage collector. Memory is managed through ownership (hold/share) and arena allocation. Own free is once per allocation: live owns move (no extra alloc); aliases and field borrows clone only when required. This chapter explains how Mako keeps your programs both fast and safe, and the tools you have when you need to push further in either direction. Release Builds By default, makori build produces a debug binary with -O0 -g -- fast compile times, full debug symbols, and all runtime safety checks enabled. When you are ready to ship: mako build --release main.mko -o bin/app The --release flag tells the backend to compile with -O3 -flto: -O3 enables aggressive optimizations: inlining, vectorization, loop unrolling, dead code elimination, and constant propagation. -flto (link-time optimization) lets the optimizer see across translation units, eliminating unused functions and inlining across module boundaries. You can measure where time is spent: mako build --time main.mko # prints frontend + backend + link durations mako profile main.mko --json # structured output for CI dashboards A typical release binary for a small service is under 200 KB on arm64. Incremental and Parallel Builds Makori uses an incremental compilation cache by default. Object files are stored in .mako/cache/ and reused when source has not changed. Flag / Environment Variable Meaning (default) Incremental on, cache at .mako/cache/ --no-incremental Bypass the object cache entirely -j N / MAKO_JOBS Number of parallel clang invocations MAKO_CACHE Override the cache directory path Example: building a workspace with 8 parallel jobs: mako build -j 8 . --release On a cold build the frontend (lex, parse, typecheck, C codegen) is typically under 100 ms. The clang backend dominates. Incremental builds skip unchanged translation units entirely. Bounds Checking: Debug vs Release All slice and array accesses are bounds-checked at runtime in both debug and release builds. An out-of-bounds index aborts the program immediately with a message indicating the file, line, index, and length: abort: index 5 out of bounds (len 3) at main.mko:12 For safe Mako indexing, this prevents an out-of-bounds access from becoming a buffer overflow. The check is typically a comparison and branch; measure the cost on the workload that matters before opting into unsafe_index. When You Need to Opt Out In extremely hot loops where profiling shows the bounds check is measurable, you can use unsafe_index: fn sum_hot(xs: []int) -> int { let mut total = 0 let n = len(xs) let mut i = 0 while i < n { unsafe { total = total + unsafe_index(xs, i) } i = i + 1 } return total } unsafe_index skips the bounds check. It must appear inside an unsafe block. If you pass an invalid index, behavior is undefined -- there is no safety net. Guideline: Only use unsafe_index when you have profiled and confirmed the bounds check is the bottleneck. In most code, the checked path is free. The Hold/Share Move Checker Mako enforces ownership at compile time through hold and share bindings. The checker runs during makori check and prevents use-after-move, double-free, and aliasing violations without any runtime cost. Hold: Unique Ownership A hold binding has exclusive ownership. When the value is rebound or passed to a function, ownership transfers and the original binding is dead: fn consume(s: string) { print(s) } fn main() { hold let x = "hello" consume(x) // x moved into consume // print(x) // COMPILE ERROR: use of moved value `x` } Partial Moves on Structs For struct values, individual fields can be moved independently: struct Pair { left: string right: string } fn main() { hold let p = Pair { left: "a", right: "b" } let l = p.left // moves only `left` print(p.right) // `right` still usable // print(p.left) // COMPILE ERROR: field already moved } Copy Types Primitive types (int, int64, int32, int8, uint64, byte, float64, bool) are Copy. A hold binding of a Copy type can be read multiple times without consuming it: fn main() { hold let n = 42 print_int(n) // fine print_int(n) // still fine -- int is Copy } Share: Borrowed Access share creates an immutable borrow. While a share is live, the source cannot be mutated: fn main() { let mut x = 10 share let s = share_int(x) print_int(share_get(s)) // x = 20 // COMPILE ERROR: cannot mutate while share is live share_drop(s) x = 20 // fine now } The checker uses control-flow-graph analysis to determine precisely when a share ends. A share that is last used on line 5 does not block mutations on line 7, even within the same scope (mid-scope drop). Non-Lexical Lifetimes (NLL) The move che ## 12. Cross-Platform and WASI (book/ch12-cross-platform) 12. Cross-Platform and WASI Mako produces native binaries for multiple operating systems and architectures from a single source tree. This chapter covers cross-compilation, the supported target matrix, WebAssembly output, and static linking. The --target Flag By default, makori build produces a binary for the host machine. To cross-compile, pass a target triple: mako build main.mko --target x86_64-unknown-linux-gnu -o bin/app-linux mako build main.mko --target aarch64-apple-darwin -o bin/app-mac mako build main.mko --target x86_64-pc-windows-msvc -o bin/app.exe mako build main.mko --target wasm32-wasip1 -o bin/app.wasm The target triple follows the <arch>-<vendor>-<os>[-<abi>] convention. Supported Targets Target Triple OS Architecture Notes aarch64-apple-darwin macOS ARM64 Apple Silicon native x86_64-apple-darwin macOS x86-64 Intel Macs x86_64-unknown-linux-gnu Linux x86-64 glibc (default on most distros) x86_64-unknown-linux-musl Linux x86-64 Static musl binary aarch64-unknown-linux-gnu Linux ARM64 Graviton, Ampere, RPi4 aarch64-unknown-linux-musl Linux ARM64 Static ARM64 x86_64-pc-windows-msvc Windows x86-64 MSVC ABI (needs clang on PATH) wasm32-wasip1 WASI WebAssembly Preview 1 (see below) The host target is detected automatically. makori version prints it: mako version mako0.6.2 darwin/arm64 mako version mako0.6.2 linux/amd64 Using Zig as the C Compiler When zig is installed and available on PATH, Mako can use zig cc as the C backend instead of system clang. This is particularly useful for cross-compilation because zig bundles sysroots for many targets: # Cross-compile to Linux x86-64 from macOS using zig MAKO_CC="zig cc" mako build main.mko --target x86_64-unknown-linux-gnu -o bin/app-linux # Cross-compile to Linux ARM64 MAKO_CC="zig cc" mako build main.mko --target aarch64-unknown-linux-gnu -o bin/app-arm64 # Cross-compile to Linux musl (static) from macOS MAKO_CC="zig cc" mako build main.mko --target x86_64-unknown-linux-musl -o bin/app-static The MAKO_CC environment variable overrides the C compiler used by the backend. Set it to zig cc to get zig's cross-compilation sysroots. Why Zig CC Ships sysroots for Linux glibc (many versions), musl, and Windows. No separate toolchain installation per target. Single native binary when the selected target and libraries support static linking. Drop-in replacement for clang in most cases. When to Use System Clang Building for the host platform (fastest, no setup needed). macOS targets (Apple SDK headers are needed, which zig does not bundle). When you need specific clang flags or sanitizers not supported through zig. Static Linking with Musl Linux musl targets can produce fully static binaries without a glibc runtime dependency when the required cross-toolchain is installed: mako build main.mko --target x86_64-unknown-linux-musl -o bin/app file bin/app # bin/app: ELF 64-bit LSB executable, x86-64, statically linked Musl targets default to --static-link. The resulting binary is portable across Linux distributions for the matching architecture, subject to kernel and deployment-policy requirements. You can also force static linking on glibc targets: mako build main.mko --static-link --target x86_64-unknown-linux-gnu -o bin/app And disable it when you want dynamic linking: mako build main.mko --no-static-link --target x86_64-unknown-linux-musl -o bin/app Static Linking Matrix Target Default Override Available Linux musl Static --no-static-link Linux glibc Dynamic --static-link macOS (darwin) Dynamic Not supported Windows (msvc) Dynamic Not supported WASM N/A N/A WASI / WebAssembly Compilation Mako can compile programs to WebAssembly targeting the WASI (WebAssembly System Interface) preview 1 specification. This produces .wasm modules that run in any WASI-compatible runtime. Prerequisites Install the wasi-sdk and set WASI_SDK_PATH: export WASI_SDK_PATH=/opt/wasi-sdk Or install it to a common path (/opt/wasi-sdk, /usr/local/wasi-sdk) and Mako will find it automatically. You also need a WASI runtime to execute the output. wasmtime is recommended: # Install wasmtime (example for macOS/Linux) curl https://wasmtime.dev/install.sh -sSf | bash Building for WASI mako build examples/wasi_hello.mko --target wasm32-wasi -o out/wasi_hello.wasm The target wasm32-wasi is normalized to wasm32-wasip1 internally. Both forms are accepted. Running with Wasmtime wasmtime out/wasi_hello.wasm # Output: hello from mako wasi # 55 Passing Arguments and Environment WASI programs can receive command-line arguments and environment variables from the host: // wasi_args_env.mko fn main() { print_int(argc()) let a = args() for i in range a { print(a[i]) } let greeting = env_get("MAKO_WASI_GREET") print(greeting) } mako build wasi_args_env.mko --target wasm32-wasi -o out/wasi_args_env.wasm wasmtime --env MAKO_WASI_GREET=hello out/wa ## 13. Tooling (book/ch13-tooling) 13. Tooling Mako ships as a single binary that includes the compiler, test runner, formatter, linter, package manager, profiler, documentation generator, and language server. This chapter is a reference for the current subcommands; platform-specific and optional integration limits are called out where they apply. makori version Prints the installed version, operating system, and architecture. mako version # mako version mako0.6.2 darwin/arm64 mako --version # same output mako -V # same output mako version -v # verbose: includes git commit hash if available # mako version mako0.6.2 darwin/arm64 # commit: a1b2c3d makori check Runs the full frontend pipeline -- lexing, parsing, and type checking -- without producing a binary. This is the fastest way to verify correctness. mako check main.mko # check a single file mako check . # check all workspace members mako check -p mylib # check one workspace member mako check --json main.mko # legacy JSON diagnostics array mako check --json=v1 main.mko # versioned report for new integrations The checker validates: - Syntax (matching braces, correct keyword usage) - Type correctness (argument types, return types, no mixed integer kinds) - Ownership (hold moves, share borrow rules, NLL analysis) - Exhaustive match on enums, Option, and Result - Unused Result as a statement (must use ?, match, or let _ = ...) - Call arity (wrong number of arguments) - Interface method implementations JSON Output Bare --json preserves the original JSON array for existing CI and editor integrations. Each checked target has its own result and diagnostics array: [{"ok":false,"file":"main.mko","diagnostics":[{"severity":"error","file":"main.mko","line":12,"column":5,"message":"use of moved value `x`"}]}] New integrations should use --json=v1. It wraps the target reports in a versioned envelope and adds aggregate counts: {"schemaVersion":1,"command":"check","ok":false,"targets":[{"file":"main.mko","ok":false,"symbols":null,"diagnostics":[{"severity":"error","file":"main.mko","line":12,"column":5,"message":"use of moved value `x`"}]}],"summary":{"checked":1,"passed":0,"failed":1,"diagnostics":1},"errors":[]} Successful targets report their top-level symbols count. Failed targets use null because symbol collection did not complete. Resolution failures such as a missing path use the top-level errors array and leave targets empty. Incompatible changes require a new schema version; consumers should ignore unknown fields added to v1. Both formats exit non-zero when any target fails. makori build Compiles a .mko file to a native binary. The pipeline is: Makori source -> C code -> object files -> linked executable. mako build main.mko # debug binary (same name as source, minus .mko) mako build main.mko -o bin/app # specify output path mako build --release main.mko # optimized: -O3 -flto mako build -j 8 main.mko # 8 parallel clang invocations mako build --no-incremental main.mko # skip object cache mako build --time main.mko # print timing breakdown mako build --emit-c main.mko # also write the generated .c file mako build --target wasm32-wasip1 main.mko -o out.wasm # cross-compile mako build --sanitize=address main.mko # AddressSanitizer instrumentation mako build --sanitize=thread main.mko # ThreadSanitizer instrumentation mako build --static-link main.mko # force static linking mako build . # build all workspace members with main.mko mako build -p app # build one workspace member Build Flags Reference Flag Effect -o PATH Output binary path --release Enable -O3 -flto optimization -j N Parallel object compilation (also MAKO_JOBS) --no-incremental Disable .mako/cache/ object reuse --time Print frontend/backend/link durations --emit-c Write generated C alongside the binary --target TRIPLE Cross-compilation target --sanitize=MODE address or thread sanitizer instrumentation --static-link Force static linking --no-static-link Force dynamic linking (override musl default) -p NAME Target a specific workspace member makori run Compiles and immediately runs the program. Equivalent to makori build followed by executing the binary. mako run main.mko # compile and run mako run main.mko -- arg1 arg2 # pass arguments to the program mako run -p app # run a workspace member mako run . # run the workspace member with main.mko Arguments after -- are forwarded ## 14. Cookbook (book/ch14-cookbook) 14. Cookbook Practical recipes for common tasks. Each example is a complete, working program or a self-contained pattern you can paste into your project. HTTP JSON API Server A minimal HTTP server that serves JSON responses with routing: #[derive(json)] struct Health { ok: bool version: string } fn handle_health(c: int) { let body = "{\"ok\":true,\"version\":\"0.1.0\"}\n" let _ = http_respond_ct(c, 200, "application/json", body) } fn handle_create_user(c: int) { let body = http_body(c) // Parse and validate the request body let name = json_get_string(body, "name") if str_eq(name, "") { let _ = http_respond_ct(c, 400, "application/json", "{\"error\":\"name required\"}\n") return } let response = json_ss("name", name) let _ = http_respond_ct(c, 201, "application/json", response) } fn main() { let port = 8080 let fd = http_bind(port) if fd < 0 { print("bind failed") return } print("listening on :8080") let mut running = true while running { let c = http_accept(fd) if c < 0 { continue } let method = http_method(c) let path = http_path(c) if str_eq(path, "/health") { handle_health(c) } else { if str_eq(method, "POST") and str_eq(path, "/users") { handle_create_user(c) } else { let _ = http_respond(c, 404, "{\"error\":\"not found\"}\n") } } let _ = http_close(c) } let _ = http_close_listener(fd) } Build and test: mako build api.mko -o out/api out/api & curl -s http://127.0.0.1:8080/health # {"ok":true,"version":"0.1.0"} curl -s -X POST -d '{"name":"Ada"}' http://127.0.0.1:8080/users # {"name":"Ada"} WebSocket Echo Server A single-client WebSocket echo that upgrades HTTP and echoes text frames: fn main() { let code = ws_echo_once(18092) print_int(code) } The ws_echo_once builtin handles the RFC 6455 upgrade handshake, reads one text frame, echoes it back, and closes the connection. For a multi-client loop: fn main() { let port = 18092 let mut i = 0 while i < 10 { let code = ws_echo_once(port) if code < 0 { break } i = i + 1 } print("ws server done") } Test with a WebSocket client: mako build ws_server.mko -o out/ws_server out/ws_server & echo "hello" | websocat ws://127.0.0.1:18092 # hello Reading and Writing Files fn main() { // Write a file let path = "/tmp/mako_example.txt" let _ = write_file(path, "hello from mako\n") // Read it back let content = read_file(path) print(content) // Append to a file let log_path = "/tmp/mako_log.txt" let _ = append_file(log_path, "line 1\n") let _ = append_file(log_path, "line 2\n") // Check existence if file_exists(path) { print("file exists") } // Directory operations let _ = mkdir("/tmp/mako_dir") if is_dir("/tmp/mako_dir") { print("dir created") } // Clean up let _ = remove_file(path) let _ = remove_file(log_path) } Error-Aware File Reading fn load_config(path: string) -> Result[string, string] { if not file_exists(path) { return error("config file not found: " + path) } let content = read_file(path) if str_eq(content, "") { return error("config file is empty") } return Ok(content) } fn main() { match load_config("app.toml") { Ok(c) => print(c), Err(e) => { log_error(e) } } } CLI Argument Parsing fn main() { let a = args() let n = argc() if n < 2 { print("usage: app <command> [options]") exit(1) } let cmd = arg_get(1) if str_eq(cmd, "serve") { let mut port = 8080 if n > 2 { match parse_int(arg_get(2)) { Ok(v) => { port = v } Err(_) => { print("invalid port") exit(1) } } } print("serving on port:") print_int(port) } else { if str_eq(cmd, "version") { print("app v0.1.0") } else { if str_eq(cmd, "help") { print("commands: serve, version, help") } else { print("unknown command: " + cmd) ## 15. Appendix (book/ch15-appendix) 15. Appendix Complete reference tables for keywords, operators, types, built-in functions, compiler flags, and environment variables. A. Keyword Reference Makori has 38 reserved words. These are always keywords and can never be used as identifiers. Source of truth: src/lexer/mod.rs. Declarations Keyword Purpose fn Function declaration struct Product type with named fields enum Sum type with variants actor Actor type with receive arms receive Message handler arm inside an actor interface Named method set (trait-like) extern Foreign function declaration (extern "C" fn) const Compile-time constant binding import Module import (file, std package, or alias) let Local immutable binding mut Mutable marker for bindings or parameters Control Flow Keyword Purpose if Conditional branch else Alternative branch while Loop while condition is true for Iteration over ranges, slices, maps, channels in Separator in for loops range Range expression (slice, integer, map, channel) break Exit the innermost (or labeled) loop continue Skip to next iteration of innermost (or labeled) loop return Return from function defer Run on function/scope exit (LIFO order) match Pattern match on enums, Option, Result, integers Literals and Logic Keyword Purpose true Boolean literal true false Boolean literal false and Logical AND (same as &&) or Logical OR (same as \|\|) not Logical NOT (same as !) Concurrency Keyword Purpose crew Structured concurrency scope kick Spawn work on a crew join Wait for a kicked job to complete fan Data-parallel map over a collection select Multi-way channel wait timeout Select arm: wait up to N milliseconds default Select arm: non-blocking fallback Memory and Ownership Keyword Purpose arena Bump-allocation region (freed on scope exit) hold Move-on-rebind ownership binding share Shared/borrowed binding as Type cast or alias in imports Alphabetical (Complete List) actor and arena as break const continue crew default defer else enum extern false fan fn for hold if import in interface join kick let match mut not or range receive return select share struct timeout true while B. Operator Table Assignment Operator Meaning = Assignment (never equality) Comparison Operator Meaning == Equal != Not equal < Less than > Greater than <= Less than or equal >= Greater than or equal Logical (Short-Circuit) Operator Keyword Form Meaning && and Logical AND \|\| or Logical OR ! not Logical NOT && and || short-circuit: the right-hand side is not evaluated when the result is already determined by the left. Arithmetic Operator Meaning + Addition (also string concatenation) - Subtraction * Multiplication / Division % Modulo Bitwise Operator Meaning & Bitwise AND \| Bitwise OR ^ Bitwise XOR &^ Bit clear (AND NOT) << Left shift >> Right shift ^x Unary bitwise complement Special Syntax Meaning ? Result propagation (early return on Err) \|x\| expr Lambda / closure s[i] Index access (bounds-checked) s[i:j] Slice expression . Field access or method call C. Type Reference Primitive Types Type Description Size int Platform integer 64 bits int64 Signed 64-bit integer 64 bits int32 Signed 32-bit integer 32 bits int8 Signed 8-bit integer 8 bits uint64 Unsigned 64-bit integer 64 bits byte Unsigned 8-bit integer 8 bits float64 64-bit floating point 64 bits float Alias for float64 64 bits bool Boolean (true / false) 1 byte string UTF-8 text (ptr + length) 16 bytes Composite Types Type Description []T Slice of T (ptr, len, cap) []byte Byte slice []string String slice []float Float slice []bool / []Enum Bool and enum slices []Option[T] / []Result[T,E] Bag element slices (make/append/index/range/lits) [][]T Nested slices (outer headers of inners) map[K]V Hash map — keys: int|string|float|bool|Struct|Enum; values: same, []T, nested map (depth ≤3), Option[T], Result[T,E], (T,U), chan[T] chan[T] Typed channel — int/bool/float/string/struct/enum/tuple Option[T] Some(T) or None Result[T, E] Ok(T) or Err(E) struct Name { } / struct Name[T] { } Named product (generic monomorphs in 0.2.0) enum Name { } / enum Name[T] { } Named sum (generic monomorphs in 0.2.0) Type Conversions Conversion Syntax Notes int -> int64 int64(x) Always valid int -> int32 int32(x) Runtime check (range) int -> int8 int8(x) Runtime check (-128..127) int -> uint64 uint64(x) Aborts if negative int -> byte byte(x) Runtime check (0..255) int -> float64 float64(x) Always valid int -> string string(x) Decimal representation string -> []byte bytes(s) or []byte(s) Copies bytes []byte -> string string(b) Copies bytes into string float64 -> int int(f) Truncates toward zero D. Built-in Functions Output Fu ## Makori ABI And Plugin Seed (docs/abi) Makori ABI And Plugin Seed Product tip: 0.6.5. Makori's current FFI is extern "C" plus the runtime C headers. The plugin ABI gives native dynamic plugins and future WASM plugins one stable handshake. Native ABI v1 Header: runtime/mako_plugin.h API string: mako.plugin.v1 ABI version: 1 Native entrypoint: mako_plugin_entry Required exported symbol type: const MakoPluginVTable *mako_plugin_entry(void) String ownership: plugin-returned strings are released with free_string when the plugin provides it The ABI surface is intentionally small: MakoPluginInfo: name, version, kind, ABI version MakoPluginHost: host callbacks, currently logging and opaque user data MakoPluginVTable: init, shutdown, call, string free callback Generate a native starter: mako deploy plugin my-plugin --name my-plugin --kind native cd my-plugin ./build-plugin.sh WASM Plugin Starter Generate a WASM plugin manifest/starter: mako deploy plugin my-wasm-plugin --name my-wasm-plugin --kind wasm The WASM starter exports ABI-version and call functions. Its generated example implements a deterministic ping operation (ping with an empty payload returns 1; unsupported operations return 0). Full WASM component-model adapters, WIT generation, capability negotiation, and host-side dynamic loading remain roadmap work. Boundary Done now: Stable ABI header Native plugin starter generator WASM plugin manifest/starter generator Release archives include the ABI docs/header Not done yet: Runtime dlopen / LoadLibrary host loader Plugin registry, signing, sandboxing, or permission prompts WASM component-model host adapter Language-level plugin import syntax ## Makori builds (v0.6.5) (docs/build) Makori builds (v0.6.5) Versioning: VERSIONING.md — ship small patches often. Makori compiles to native binaries via three backends: native (Cranelift, default), c (clang/gcc), and llvm (optimizing). The native backend on macOS ships with a bundled linker — no external toolchain required. The C backend uses incremental cached objects under .mako/cache/ (or $MAKO_CACHE). Layout .mako/cache/ meta.txt # COMPILER_CACHE_VERSION typecheck/<fp>.ok # whole-program typecheck stamp c/<fp>.c # generated C per unit obj/<fp>.o # clang -c output Fingerprints include: compiler cache version, full source + transitive deps, generated C bytes, opt/sanitize/target flags, and host feature defines (OpenSSL, etc.). CLI Flag / env Meaning (default) Incremental on --no-incremental Bypass caches -j N / MAKO_JOBS Parallel compilation jobs (default: CPU count) MAKO_CACHE Override cache root MAKO_CACHE_LOG=1 Print HIT/MISS lines Wired into makori build, makori check, and makori run. When mako.lock exists, locked dependencies are rehashed before dependency loading or cache reuse, and compilation uses the verified source snapshot rather than reopening those files. Parallelism Independent object units compile in parallel (owned jobs + channels — no shared mutable typechecker). Dependency order for packages is preserved by merging path deps before codegen; object units for one binary are independent. When is a system linker used? Backend macOS Linux Windows native (default) Bundled LLD — no system tools gcc/clang for linking clang c clang (compile + link) gcc/clang clang llvm Bundled LLD gcc/clang for linking clang wasm / --emit-c / unsupported sanitizers / cross Use explicit --backend c + system compiler Backend policy Makori has three codegen backends. There is no silent fallback between them: unsupported constructs hard-error on native/LLVM rather than dropping to C. Backend CLI Role When to use C --backend c Mature Mako → C → system cc Explicit oracle; sanitizers; cross/--target; wasm; widest host support Native --backend native Shared IR → Cranelift object Fast debug iteration; full language gate (examples/testing 420/420) LLVM --backend llvm Shared IR → LLVM object (release only) Optimizing release path when built with --features llvm-backend + bundled lld Recommended local workflow (0.5 prep): # Debug / test on Cranelift (or set once in the shell) export MAKO_BACKEND=native mako build app.mko -o app mako test examples/testing # or MAKO_TEST_BACKEND=native # Release speed (host with llvm-backend feature) mako build app.mko --release --backend llvm -o app # Sanitizers / oracle remain on C mako test examples/testing --backend c --sanitize address Env Meaning MAKO_BACKEND Default override for build / run / test when no explicit --backend is passed MAKO_TEST_BACKEND Test-only override (checked before MAKO_BACKEND) Explicit --backend … Always wins over env CI (primary hosts): both makori test examples/testing (C) and makori test examples/testing --backend native are required. LLVM runs as a dedicated macOS job (llvm-backend) that bootstraps static lld and executes scripts/llvm-backend-test.sh. Non-Darwin hosts skip LLVM today (bundled lldMachO only); set MAKO_LLVM_SKIP_IF_UNAVAILABLE=1 for a soft skip in local/optional scripts. Install smoke: scripts/install-smoke.sh (doctor + init/run). Product default: native is the default debug path. Unsupported direct-backend modes hard-error; choose --backend c explicitly when you need C-only modes. Native / LLVM backends mako build app.mko --backend native -o app mako run app.mko --backend native mako build app.mko --release --backend llvm -o app # needs llvm-backend feature Native and LLVM emit machine-code objects directly (no generated C). The shared IR covers the full testing corpus on Cranelift. Unsupported modes hard-error with a pointer at the C backend (no silent fallback). Modes matrix (0.4.7) Mode / flag --backend c --backend native --backend llvm Host target (default) yes yes yes (--release required) --target cross yes (zig/clang) hard-error hard-error wasm32-wasip1 yes hard-error hard-error --sanitize=leak\|address yes yes (see note) yes (see note) --sanitize=thread\|memory / --race yes hard-error hard-error --static-link yes (non-macOS) hard-error hard-error --emit-c yes hard-error hard-error --overflow wrap yes yes yes --overflow trap yes yes (shared IR) yes (shared IR) --overflow ignore yes (≡ wrap) yes (≡ wrap) yes (≡ wrap) Debug (makori build) yes yes hard-error (use native) Release (--release) yes yes yes (needs llvm-backend feature) Example: # Works — leak/address are supported on the direct backends: mako build app.mko --backend native --sanitize leak # Wrong — fails closed, because thread/memory need instrumented loads/stores # that an uninstrumented code generator cannot provide: mako bui ## Makori Built-in Functions Reference (docs/builtins) Makori Built-in Functions Reference Current documented reference for Makori built-ins. Platform-specific and optional-library boundaries are marked in the tables; symbol-for-symbol stdlib parity is not claimed. Signatures use the form function_name(param: type, ...) -> return_type. 1. Output Function Signature Description print print(s: string) -> void Print string + newline to stdout print_raw print_raw(s: string) -> int Print string without newline print_int / print_int64 / print_int32 / print_int8 / print_uint64 typed int print + newline print_float / print_bool float / bool + newline eprint / eprintln (s) -> int stderr without / with newline dbg / dbg_str debug echo format_int / format_int_dec / int_to_string decimal string format_int_hex / format_int_hex_upper / format_int_hex_prefix hex (ff / FF / 0xff) format_int_hex_pad (n, width) zero-padded hex format_int_bin / format_int_oct binary / octal format_int_base (n, base) base 2–36 format_pad (s, width, zero) left pad format_float / format_bool float / bool parse_int decimal parse_int_hex / parse_int_bin / parse_int_oct base parse (0x/0b/0o ok) parse_int_base (s, base) base 2–36; base=0 auto prefix parse_int_auto same as base 0 hex_encode / hex_decode byte string ↔ hex (encoding/hex) fmt package (Go-style) String args: %% %s %v %t %q %x/%X (byte hex) %f %g Int args (fmt_sprintf_d / fmt_sprintf_dd): %d %i %v %b %o %x %X Flags: # (0x/0b/0), 0 zero-pad, + sign, width (%08x). Function Signature Description fmt_sprintf … fmt_sprintf4 (fmt, a…) Format → string (1–4 string args) fmt_sprintf_d (fmt, n: int) int verbs %d %x %X %b %o + flags fmt_sprintf_dd (fmt, a, b: int) two int verbs fmt_sprintf_f (fmt, v: float, prec) float into first verb fmt_sprint … fmt_sprint3 join with spaces fmt_sprintln / fmt_sprintln2 join + "\n" fmt_print / fmt_print2 stdout, no newline fmt_println / fmt_println2 stdout + newline fmt_printf … fmt_printf3 printf to stdout fmt_eprint / fmt_eprintln / fmt_eprintf stderr fmt_errorf / fmt_errorf2 format error string Packs: std/fmt, std/print. Tests: fmt_print_test.mko. Demo: examples/fmt_demo.mko. 2. Strings string vs string_view (SAFE-005) Type Role string Owning heap string (or empty singleton). Free on scope exit / reassign. string_view Non-owning view of bytes (same C header as string). Never free. Function Signature Description str_as_view str_as_view(s: string) -> string_view Zero-copy view of an owned string (must not outlive s) str_to_owned str_to_owned(v: string_view) -> string Clone a view into an owning string len len(s: string \| string_view \| …) -> int Byte length (also arrays/maps) let v: string_view = "hello" // points into .rodata; no free let s = f"x{1}" // owned let w = str_as_view(s) // view of s let o = str_to_owned(v) // owned clone Function Signature Description str_len str_len(s: string) -> int Return byte length of a string str_eq str_eq(a: string, b: string) -> bool Test two strings for equality str_contains str_contains(s: string, substr: string) -> bool Check if string contains a substring str_has_prefix str_has_prefix(s: string, prefix: string) -> bool Check if string starts with prefix str_has_suffix str_has_suffix(s: string, suffix: string) -> bool Check if string ends with suffix str_index str_index(s: string, substr: string) -> int Return index of first occurrence of substr, or -1 str_last_index str_last_index(s: string, substr: string) -> int Return index of last occurrence of substr, or -1 str_slice_eq str_slice_eq(s: string, off: int, len: int, other: string) -> int Compare s[off:off+len] to other without allocating (1/0; OOB → 0) str_slice_ci_eq str_slice_ci_eq(s, off, len, other) -> int Case-insensitive region equality (no alloc) str_slice_contains str_slice_contains(s, off, len, needle) -> int Needle inside s[off:off+len] (no alloc) str_slice_index str_slice_index(s, off, len, needle) -> int First absolute index of needle in region, or −1 str_at_eq str_at_eq(s: string, off: int, other: string) -> int s[off..] prefix equals other (no alloc) str_byte_at str_byte_at(s: string, i: int) -> int Byte at index (0–255), or −1 if OOB str_trim str_trim(s: string, cutset: string) -> string Trim characters in cutset from both ends str_trim_space str_trim_space(s: string) -> string Trim whitespace from both ends str_trim_left str_trim_left(s: string, cutset: string) -> string Trim characters in cutset from the left str_trim_right str_trim_right(s: string, cutset: string) -> string Trim characters in cutset from the right str_to_lower str_to_lower(s: string) -> string Convert string to lowercase str_to_upper str_to_upper(s: string) -> string Convert string to uppercase str_repeat str_repeat(s: string, count: ## Changelog (docs/changelog) Changelog Unreleased 0.6.8 - 2026-08-30 (interface type hardening + consolidation plan) Require interface implementations to match every declared non-receiver parameter and return type. Add an adversarial negative fixture and claims-gate coverage for interface signature mismatches. Publish the v0.7 consolidation plan for ownership, concurrency, Unicode, runtime, performance, CI, and external-review hardening. 0.6.7 - 2026-08-30 (consuming View detach portability) Preserve consuming slice-View detach (v = append(v, x)) while keeping the base frozen for every non-consuming mutation, move, reassign, or alias. Make refcount fault probes request portable POSIX/GNU declarations under strict C11 CI builds. 0.6.6 - 2026-08-30 (normative slice safety) Made the slice aliasing contract normative: slices and Views are non-Send, Views are NLL borrows, and refcount uniqueness never authorizes concurrent mutation. Hardened slice backing refcounts against overflow, underflow, and retaining a released allocation; invalid transitions now abort instead of wrapping. Next: v0.6.8 → v0.7 consolidation — no new features. Freeze COW spec, property-based ownership testing, channel model-check, Unicode conformance suites, C runtime modularization, application benchmarks, CI automation, external review. See docs/CONSOLIDATION.md. 0.6.5 - 2026-08-30 (PQC + error tracing + JSON + Unicode 17) ML-DSA post-quantum signatures (FIPS 204) Added mldsa44_keygen, mldsa65_keygen, mldsa87_keygen for all three NIST security levels, wrapping OpenSSL 3.5+'s native ML-DSA via the EVP API. Added mldsa_sign / mldsa_verify for post-quantum digital signatures. Added mldsa_public_key extraction and mldsa_algorithm_name inspection. Added mldsa_self_signed_cert for X.509 certificates with ML-DSA signatures and mldsa_verify_cert for certificate chain verification. Added mako_tls_server_pqc / mako_tls_enable_pqc for TLS 1.3 with ML-DSA signature schemes (MLDSA44/65/87). Graceful compile-time stubs for OpenSSL < 3.5; pqc_available() runtime probe. New file: runtime/mako_pqc.h. 11 adversarial tests in mldsa_pqc_test.mko. Error tracing Added error_trace(msg) and error_wrap_trace(err, context) builtins that automatically embed source file:line in error strings via codegen injection. Added error_message, error_cause, error_chain for extracting and formatting error context chains with source locations. Wire format uses \x01/\x02 delimiters invisible to normal string ops; error_chain renders "context: message [file.mko:42 → caller.mko:10]". New file: runtime/mako_errtrace.h. 5 tests in error_trace_test.mko. Added native-runtime bridges for trace construction and inspection; native traces retain the chain using a backend marker while C emits exact call-site file and line metadata. UUID expansion (RFC 9562) Added uuid_v1 (time + random node, RFC 4122). Added uuid_v6 (reordered time for natural sort order, RFC 9562). Added uuid_v8 (custom/experimental 122-bit data, RFC 9562). Added uuid_timestamp to extract 60-bit timestamps from v1/v6 UUIDs. 7 tests in uuid_v1v6v8_test.mko including sort-order and cross-version. Fixed native uuid_cmp to return true three-way ordering instead of treating every unequal UUID as greater. JSON marshalling Extended #[derive(json)] to support float, bool, and nested struct fields (previously only string and int). Added json_f (float field), json_b (bool field) emitters. Added json_get_float, json_get_bool extractors. Fixed use-after-free in json_get_float/json_get_bool (strlen after free on the pattern buffer). 5 tests in json_marshal_test.mko. Added native-runtime parity for float and bool JSON emitters/extractors. Unicode 17 Unicode 17 identifiers: the lexer now accepts any Unicode XID_Start / XID_Continue scalar in identifiers (let π = 3.14, let 变量 = 1). Emoji and digit-leading names are still rejected per UAX #31. Unicode 17 normalization: added unicode_nfc, unicode_nfd, unicode_nfkc, unicode_nfkd builtins and std/unicode wrappers (nfc, nfd, nfkc, nfkd). Upgraded unicode_is_letter, unicode_is_digit, unicode_is_space, unicode_is_punct, unicode_is_symbol, unicode_is_control to use the full Unicode 17 UCD tables when available, falling back to the legacy regex-derived ranges. Fixed mako_unicode17.h not being included in the default (non-lean) header set, which caused C test-backend builds to fail with undeclared normalization functions. Added native-runtime parity for all four normalization forms and ML-DSA. C backend Fixed C test-backend method lowering for string and aggregate channels so try_send and send_timeout call the matching typed runtime helpers instead of passing MakoString or boxed values to the integer-channel API (#43). Added mako_chan_str_send_timeout and mako_chan_str_recv_timeout runtime functions for string-channel timeout operations. Verified FayDB's TestTransactionWalCommitOnly through mako test --backend c. 0.6.3 - 2026-08-30 (C backend own ## Contributing to Makori (docs/contributing) Contributing to Makori Thanks for being interested in helping out. Here's how to get set up and what we expect from contributions. Prerequisites Rust (stable toolchain) clang (Xcode on macOS, apt install clang on Linux, LLVM on Windows) Optional: OpenSSL, libnghttp2, SQLite, libpq (for live integration tests) Building from source cargo build --release ./target/release/mako --version Or use the Makefile: make release # cargo build --release make install # installs to ~/.local/bin + ~/.local/share/mako/runtime Running tests # Full Mako test suite (130 tests) cargo run --release -- test examples/testing # Specific test cargo run --release -- test examples/testing -r TestAdd -v # Rust-level checks cargo clippy cargo fmt --check For live integration tests (TLS, HTTP/2, QUIC), set the relevant env vars: MAKO_LIVE_TLS=1 cargo run --release -- test examples/testing Project structure To help you navigate the codebase, here is an overview of how the repository is organized: src/ Compiler (Rust) — lexer, parser, types, codegen, CLI runtime/ C runtime headers (included by emitted C code) std/ Standard library (.mko modules) examples/ Example programs and test suite testing/ Test files (*_test.mko) bad/ Negative tests (expected compiler errors) docs/ Documentation book/ The Makori Book (mdBook) howto/ Task-oriented guides editors/vscode/ VS Code extension scripts/ Build, test, and release scripts Compiler pipeline Source (.mko) → Lexer → Parser → Desugarer → Typechecker (NLL) → Codegen (C) → clang/zig → Binary Key modules: - src/lexer/ — tokenization - src/parser/ — recursive descent - src/types/ — type checking + NLL move analysis - src/codegen/ — C code emission - src/cc.rs — C compiler invocation Making changes Process bar (same as Agents.md): Speed is the name of the game (≈ Rust) — no silent cost on the default hot path. Runtime/codegen/concurrency changes: ./scripts/bench-gate.sh (docs/SPEED.md). Concurrency first-class — structured crew / fan / channels; no orphan tasks; no async coloring as the default model. Security first-class — hard errors over advice; secure defaults; costly checks stay opt-in (docs/SECURITY.md). Always check your work — report command + outcome; do not claim green from intent. Be adversarial — empty/null, overflow, timeout, double-close, races, injection edges. Always test — automated coverage that would fail on regression. Build consensus — speed first, then concurrency/security, then identity; one path only. Steps: Create a branch from main Make your changes Add or update tests if behavior changes Update docs in the same change — no feature without docs. Touch every applicable surface (BUILTINS, STDLIB, GUIDE/book, CLI/DEBUG/PERFORMANCE, CHANGELOG, STATUS/ROADMAP). See Agents.md Always update the docs Run cargo clippy and cargo fmt Run cargo run --release -- test examples/testing and make sure it passes Open a PR with a clear description of what and why Do not commit Keep out of commits Why Accidental binaries (trap_ov, root hello, /out/…) Build artifacts — listed in .gitignore .claude/, .cursor/, .grok/, *.local.md Local agent/editor state Secrets, certs, personal env files Security Unrelated local edits to AGENTS.md process notes Prefer human-facing policy in this file / docs/; only change AGENTS.md when the project north star intentionally changes Never git add -A / git add . blindly — stage only source, tests, docs, and intentional config for the change. Style Keep it simple. Don't over-abstract. Match the existing code style in whatever file you're editing. Runtime C code follows the existing naming: mako_ prefix, snake_case. Makori source files use .mko extension. Adding to the standard library Standard library modules live in std/. Each module has a corresponding runtime implementation in runtime/mako_*.h. If you're adding a new stdlib module: Create std/<package>/<module>.mko with the public API Implement the runtime in runtime/mako_<name>.h Wire it into codegen (see existing patterns in src/codegen/mod.rs) Add tests in examples/testing/ Document in docs/STDLIB.md, docs/BUILTINS.md, and the book/guide as needed Reporting bugs Open an issue on GitHub with: - What you expected to happen - What actually happened - Minimal .mko file that reproduces the problem - Output of mako --version License By contributing, you agree that your contributions will be licensed under the MIT License. ## Debugging Mako (docs/debug) Debugging Mako This guide covers the implemented Mako debugging tools, from quick inline prints to source-level debugger sessions (DAP and lldb) and sanitizer runs. Product tip: 0.6.5. Table of contents Source-level debugging with mako dap (DAP) Interactive lldb with mako debug lldb data formatters Debug vs release builds Inline debugging: dbg and dbg_str Running with lldb (manual) Address sanitizer Thread sanitizer Compiler error messages Common error patterns Inspecting generated code with --emit-c Tooling integration with mako check --json Testing and test failures Example debugging session Source-level debugging with mako dap (DAP) mako dap is a real Debug Adapter Protocol (DAP) adapter. It speaks DAP over stdio (Content-Length framing) and proxies the session to a spawned lldb-dap child. Editors with a DAP client (VS Code, Neovim, …) get breakpoints, stepping, and stack frames on .mko source lines. How it works The adapter reads the DAP launch request and looks at its program field. If program is a .mko file, the adapter builds it with debug flags (-O0 -g, C backend) to $TMPDIR/mako_dbg_<stem>_<pid>. If program already points at a binary, it is used as-is. The session is proxied to lldb-dap. Stack frames and breakpoints resolve to .mko source because the C codegen emits per-statement #line directives. A failed build returns a DAP error response to the client. On disconnect the lldb-dap child and the debugged process are killed — no orphan processes. mako dap takes no flags. The old canned-response seed flags (--request, --stdio, --max-messages) are removed. lldb-dap discovery The adapter locates lldb-dap in this order: Order Source 1 $MAKO_LLDB_DAP 2 xcrun -f lldb-dap (macOS) 3 lldb-dap, then lldb-dap-21 … lldb-dap-16 on PATH VS Code The Makori VS Code extension (editors/vscode) spawns mako dap directly via a DebugAdapterDescriptorFactory — no CodeLLDB or Microsoft C/C++ extension needed, and no preLaunchTask (the adapter builds on launch). Launch config: { "type": "mako-native", "request": "launch", "name": "Mako: Debug active file", "program": "${file}", "args": [] } Backend caveat Source-level debugging requires the C backend. The default native (Cranelift) backend emits no DWARF line info, so breakpoints cannot resolve to .mko lines. mako dap and mako debug force the C backend automatically; manual lldb users must build with --backend c (see Running with lldb). dap_ / debug_ builtins are not the debugger The in-process builtins (debug_break, debug_line_bp_set, debug_push_frame, dap_initialize_response, debug_snapshot_json, …) remain available as manual instrumentation helpers for prototyping. The compiler never auto-instruments them; real debugging goes through mako dap or mako debug. Tests: scripts/test-dap.sh drives a scripted DAP session (scripts/dap_drive.py) against examples/testing/debug_probe.mko. It skips cleanly when lldb-dap is absent and includes a negative case: launching examples/bad/assign_string_to_int.mko must return a DAP error. Unit tests live in src/dap.rs. Interactive lldb with mako debug mako debug is the easy path for terminal debugging: it builds the program with debug info (C backend) and launches an interactive lldb session with the Mako data formatters preloaded. mako debug # debug the package in . mako debug main.mko # debug a specific file mako debug . -p app # debug one workspace member mako debug main.mko -- arg1 # arguments after -- go to the program Flag Description [path] Source file or package directory (default: .) -p, --package <NAME> Workspace member to debug -- [ARGS]... Arguments forwarded to the program lldb discovery: $MAKO_LLDB, then xcrun -f lldb (macOS), then lldb on PATH. lldb data formatters Mako ships lldb data formatters at editors/lldb/mako_formatters.py, loaded automatically by mako dap and mako debug: Type Display MakoString Quoted UTF-8 string MakoIntArray / MakoByteArray / MakoStrArray / MakoFloatArray / MakoBoolArray / MakoArr_* [e0, e1, ...] (first 16 elements), with expandable synthetic children Load them manually inside lldb: (lldb) command script import /path/to/mako_formatters.py Override the formatter path with $MAKO_LLDB_FORMATTERS. The installers place the script at $PREFIX/share/mako/mako_formatters.py. Debug vs release builds Debug is the default. With the C backend (makori build --backend c), every makori build, makori run, and makori test invocation compiles with clang -O0 -g, which means: Full debug symbols are embedded in the binary. No optimizations reorder or remove code. Stack frames are complete and readable in debuggers. For release builds, pass --release: mako build --release main.mko # -O2, still linkable Release builds strip debug info and enable optimizations. Only use them for benchmar ## Makori (docs/docs-overview) Makori Makori is a compiled language for backend and systems work. You write .mko files; Makori turns them into standalone native binaries — no garbage collector, no VM, nothing extra to install next to them at runtime. Renamed from Mako. The original name conflicted with Python's Mako templating engine, which has been around since 2006. To avoid confusion between the two projects, the language is now called Makori. The mako command still works as a backward-compatible alias, and the .mko file extension is unchanged — existing code requires zero modifications. Status: alpha (v0.6.8). It works, it compiles real programs, people have built things with it. It is not stable. APIs will change, features are missing, and there are bugs. If that's fine with you, read on. mako-lang.com · Changelog · Roadmap · Status Install Linux curl -fsSL https://github.com/loreste/mako/releases/latest/download/install-linux.sh | bash source "$HOME/.local/share/mako/env.sh" makori version macOS curl -fsSL https://github.com/loreste/mako/releases/latest/download/install-release.sh | bash source "$HOME/.local/share/mako/env.sh" Windows — grab the .zip from Releases, or build from source with LLVM clang on PATH. From source (needs Rust): make install makori version You do not need Rust on the machine that runs Makori. The installer downloads a prebuilt binary bundle. macOS release binaries ship with a bundled linker (LLD) — no Xcode, clang, or any external C toolchain is required. Install and build native binaries out of the box. Linux currently requires gcc or clang for linking. What it looks like fn main() { let ch = make(chan[string], 4) crew t { let p = t.kick(produce(ch)) for msg in range ch { print(msg) } let _ = p.join() } } fn produce(ch: chan[string]) -> int { let _ = ch.send("hello") let _ = ch.send("world") ch.close() return 0 } makori init hello && cd hello makori run main.mko makori build --release main.mko -o hello What actually works Language. Static types with local inference. Result[T, E] and Option[T] with ? propagation. Pattern matching. Enums with payloads. Generics (monomorphized). Interfaces (structural, like Go). Closures. Tuples and multi-return. Integer literals in decimal, hex (0xFF), binary (0b1010), and octal (0o77) with _ separators. defer. Labeled loops. F-strings. Struct update syntax. Pipe operator (|>). prove contracts. live fn hot-reload foundation. Memory. Ownership tracking with compile-time move checks. Arenas for bulk allocation. Bounds checks in debug and release. Escape analysis. Deterministic cleanup with copy-on-write slices — no GC. The C backend shares owned heap backing through atomic reference counts and detaches before mutation; borrowed views and pool-backed buffers never enter that release path. The native backend tracks owned and borrowed values explicitly across calls and returns. The ownership and runtime safety model was introduced in 0.2.4 and continues to be hardened through adversarial tests, sanitizers, leak checks, and regression gates. It is not formally proven complete. unsafe and FFI are outside the model. Concurrency. crew / kick / join — structured concurrency where ordinary crew jobs cannot outlive their scope. Explicit detach tasks are process-scoped and require separate lifecycle management. Typed channels (chan[int], chan[string], chan[T]), select, fan for parallel map. Actors with mailboxes. No free go keyword — every spawned task has an owner. Stdlib. HTTP server and client. TLS (OpenSSL). WebSocket. JSON. SQLite and Postgres. SIP parsing and building. HEP (Homer) ingest. UDP/TCP/Unix sockets. File I/O. Regex. UUID. Base64. Binary buffers. Prometheus metrics. Crypto (SHA-256, HMAC, PBKDF2, AEAD). Protobuf wire codec. gRPC unary frames and service registry. Application packs have Go-equivalent surfaces (strings, bytes, io, os/env, net/netip, math/bits, hash/crc32, crypto/rand, image, … — Makori names, not a syntax clone). Coverage is still uneven — STDLIB.md records what has real tests, what is a capability equivalent, and what is intentionally out (unsafe, go/*, debug/*, weak). Backends. Native object code default (Cranelift). C backend remains available via explicit --backend c as the oracle for sanitizers, cross-compilation, and emit-c; unsupported native/LLVM modes hard-error instead of silently falling back. Both backends produce standalone binaries. LLVM release builds available with --backend llvm --release. On macOS, the native backend ships with a bundled linker (LLD) — no clang or Xcode required. On Linux, gcc or clang is needed for linking. Packages. makori pkg manages dependencies with a lockfile, SHA-256 content hashes, and SemVer resolution. Supports path deps, git deps, local registry, and remote HTTPS registry. The default public registry is https://loreste.github.io/mako-packages — makori pkg get <name> fetches ## Makori language guide (docs/guide) Makori language guide What works today — syntax and APIs the compiler accepts, with examples under examples/. Sources use the .mko extension (not .mk). Idiomatic style is Mako’s own. Prefer fn, let, struct, on Type { }, hold / share / arena, crew / kick. Dual Go-like spellings (func, :=, bare a int) remain valid as compat sugar, not the brand. Doc Role This guide Verified syntax + how to use it IDENTITY.md Our syntax identity + % checklist GO_SYNTAX_CHECKLIST.md Optional dual-form inventory (not preferred) The Makori Book Guided tour (idiomatic Mako) COMPAT.md Dual forms / backward compatibility STATUS.md Done matrix (adversarial) BUILD.md Incremental cache, backends (c / native / llvm), -j VERSIONING.md Patch-first release policy (0.4.6, 0.4.7, …) PERFORMANCE.md Release -O3 -flto, benchmarks DEBUG.md lldb/gdb, dbg, sanitizers SECURITY.md Memory safety + cache guarantees STDLIB.md HTTP library + std surface howto/ Task-oriented how-to guides RELEASE.md Packaging / install KEYWORDS.md Full reserved-keyword list VISION.md North star ROADMAP.md Sequencing Legend: unmarked = verified · Target = aspirational (VISION Later). Mako identity strength: IDENTITY.md (~86%). STATUS north-star / MVP: 100% (homebrew-core publish is the only external blocker). Makori-native syntax (preferred) Canonical sample: examples/mako_style.mko. export struct Point { x: int y: int } on Point { fn distance(self) -> int { return self.x + self.y } } fn divmod(a: int, b: int) -> (int, int) { return (a / b, a % b) } fn main() { let p = Point { x: 3, y: 4 } print_int(p.distance()) let q, r = divmod(17, 5) print_int(q) print_int(r) hold let n = 10 arena a { let label = arena_text(a, "mako") print(label) } crew t { let job = t.kick(work()) print_int(job.join()) } } Prefer (Mako) Dual (compat) fn f(a: int) -> int func f(a int) int on T { fn M(self) … } func (p T) M() struct T { x: int } type T struct { x int } let / let mut := / var export fn Capitalized names crew / kick / join — hold / share / arena — Goal: simple everyday code, systems-grade control, unique Mako surface — addressing real backend pain points with Makori's own tools. Quickstart (install + init) # From a checkout make install # → ~/.local/bin/mako + ~/.local/share/mako/runtime # or: ./scripts/install.sh mako --version mako init hello --name hello cd hello mako run main.mko # uses installed runtime via binary-relative path mako build main.mko # binary named from mako.toml `name` when file is main.mko # Backend API service scaffold mako init mysvc --backend cd mysvc mako run main.mko # Optional: multi-package workspace (local-only) mako init myws --workspace cd myws mako check . mako run -p app makori version (also mako --version / -V) prints makori version mako0.6.5 darwin/arm64. Use makori version -v for an optional commit line. Override headers if needed: export MAKO_RUNTIME=/path/to/runtime. Incremental builds are on by default (-j / MAKO_JOBS, --no-incremental to disable) — see BUILD.md. Release: makori build --release → -O3 -flto (PERFORMANCE.md: optimized on microbenches). For speed: pre-size make([]T, 0, n) / make(map[K]V, n), use arenas for request scope, prefer hold over share, short-lived POD lits stay on the stack ([a,b,c]), use string_view / str_as_view for zero-copy reads, measure with now_ns + ./scripts/bench.sh. See SPEED.md · SOUNDNESS.md. // Ownership (0.4.0): free at scope exit; views never free let mut xs = make([]int, 0, 16) xs = append(xs, 1) let v: string_view = "route" // no malloc, no free let s = f"id={1}" // owned; freed at end of scope let w = str_as_view(s) // Scheduler (opt-in pool) sched_set_workers(4) crew t { let j = t.kick(work(1)) print_int(j.join()) } sched_set_workers(0) From a source tree without installing: cargo run --release -- check examples/hello.mko cargo run --release -- run examples/hello.mko Packages (mako.toml) Local path deps are the useful surface today; remote git fetch is thin (needs git). mako pkg init mylib # same scaffold as `makori init` mako pkg list # name + deps; path/git status on disk mako pkg fetch # clone git deps into `.mako/deps/` (needs git + network) mako pkg add helper ../helper # record / update path dep in [dependencies] mako pkg add path=../helper # same; name from basename mako pkg remove helper # drop a [dependencies] entry mako pkg lock # write SHA-256 content hashes to mako.lock mako pkg install # reuse the lock and verify dependency content mako pkg update # accept intentional changes / migrate v1 locks mako pkg audit # offline advisory + license policy ## Makori keywords (docs/keywords) Makori keywords Source of truth: src/lexer/mod.rs → lex_ident (48 reserved words, including duals; pack/pull/go/switch are contextual). Every identifier that matches one of these strings is always a keyword token — never an Ident. There are no contextual keywords today: you cannot name a variable crew or default. Mako flair (preferred): fn, let, pack, pull, on, hold, share, arena, crew, kick, join, fan, export, queue, graphql, … — see IDENTITY.md. Dual / compat: func, var, package, import, type, plus := (token, not a keyword). Not keywords (ordinary identifiers / builtins): type names (int, int8, int32, int64, uint64, byte, float/float64, string, …), map / chan (type constructors, not reserved), conversions T(x) / bytes(s), Ok/Err/assert*/t_run, len/cap/append/copy/ rune_count/has/delete/str_builder/builder_*/uuid_* / graphql_parse / mq_*, etc. See GUIDE.md. Guided tour: The Makori Book · Current syntax: GUIDE.md · Design: LANGUAGE.md. Declarations Keyword Meaning fn / func Function (or interface method) — fn preferred; func dual var Mutable local (var x = 1) — dual of let mut pack / package Unit name (pack lib) — default pull qualifier; package dual type Dual type decl: type Point struct { … } struct Product type with named fields; generics: struct Pair[T] { … } (0.2.1) enum Sum type with variants; generics: enum Box[T] { … } (0.2.1) actor Actor type with receive arms receive Actor message handler arm interface Named method set (light interfaces) extern Foreign declaration (extern "C" fn …) const Compile-time constant binding pull / import Bring in another .mko / std unit — always qualify; pull preferred let Local binding mut Mutable parameter or binding marker export Package-public declaration (export fn / export struct / export on) on Method block: on Point { fn distance(self) … } (desugars to Point_distance) Control flow Keyword Meaning if / else Conditional while Loop while condition holds for / in / range Iteration (for i, v in range s, for i in n, …) break / continue Exit / next iteration of innermost for/while fallthrough Go dual: last statement of a switch case arm only return Return from function defer Run on function exit (LIFO), including before return match Pattern match on enums / Option / Result / ints Literals / logic Keyword Meaning true / false Bool literals and / or / not Boolean operators (word forms; && / \|\| / ! also work) Operators (not keywords) Form Meaning = Assignment only (never equality) == != < > <= >= Comparison && \|\| ! Logical and / or / not (short-circuit &&/\|\|); !!x is two ! and or not Same as && / \|\| / ! & \| ^ &^ << >> Bitwise; unary ^x is bitwise complement Leading \|…\| Still a lambda; infix \| is bitwise or Concurrency Keyword Meaning crew Structured concurrency scope kick Spawn work on a crew (also .kick(…)) join Wait for a kicked job (also .join()) fan Data-parallel map over a range/collection select Multi-way channel wait timeout Select arm: wait up to N ms default Select arm: non-blocking fallback Memory / ownership Keyword Meaning arena Bump-allocation region (freed on scope exit) hold Move-on-rebind ownership binding share Shared / RC-style binding (seed) as Type / ownership cast helper in expressions Messaging / GraphQL (language types) Keyword Meaning queue FIFO message queue type constructor: queue[string], make(queue[string], n) graphql / Graphql / GraphQL GraphQL document type keyword (methods after graphql_parse) See MESSAGING_GRAPHQL.md. Alphabetical (complete) actor and arena as break const continue crew default defer else enum extern false fallthrough fan fn for graphql hold if import in interface join kick let match mut not on or queue range receive return select share struct timeout true while (also duals: func var package type import · export is reserved) (Count must match lex_ident keywords; duals func/var/package/type/pull/pack also reserved.) ## Makori language (docs/language) Makori language Makori is a systems and backend language: clear to write, strict at compile time, fast at runtime, and designed so builds stay fast. Product version: 0.6.5 (makori version → mako0.6.5). Guided tour: The Makori Book. Current syntax guide: GUIDE.md. Low ceremony: ERGONOMICS.md. Identity (our syntax): IDENTITY.md. Keywords: KEYWORDS.md. Product north star: VISION.md. Honest matrix: STATUS.md. Changelog: ../CHANGELOG.md. Design pillars Pillar How Clear Concise keywords, braces, local inference Strict Static types, no null, exhaustive match, Result / Option Fast binaries Native code via C (today) Fast builds Linear frontend; debug -O0 by default Speed Native compilation, no GC, release -O3 -flto (SPEED.md) Concurrent (first-class) crew / kick / join / channels / select / actor — structured, no orphans Parallel (first-class) fan — data-parallel map over cores; multi-kick crews Memory hold / share / arena — no GC Safe by default Bounds checks; unused Result is an error Syntax identity — ours Makori is a unique language with unique syntax. Not a Go dialect. Not a Rust dialect. Not a hybrid costume of either. Simplicity (as a goal): short programs, little ceremony, good stdlib. Control (as a goal): ownership, no GC, explicit errors, fast binaries. Surface (as a requirement): keywords and forms that are distinctly Mako — fn, on, pack, pull, hold, share, arena, crew, kick, … // Mako — preferred fn handle(req: Request) -> Result[int, string] { hold let body = req.body arena a { let msg = arena_text(a, body) crew t { let j = t.kick(process(msg)) return Ok(j.join()) } } } on Point { fn distance(self) -> int { return self.x + self.y } } Mako-native (preferred) Dual / compat sugar fn func let / let mut := / var x: int x int -> int bare int after ) on Point { … } func (p Point) … struct Point type Point struct export Capitalized names crew / kick / join (no free go) hold / share / arena — Rule: docs, book, and makori fmt lead with the left column. Dual forms stay for familiarity and migration — they do not define the brand. Full identity checklist + %: IDENTITY.md (~86%). Optional dual-form inventory: GO_SYNTAX_CHECKLIST.md. Generics (0.2.2) User type parameters on functions, structs, and enums. All instantiations are monomorphized (one concrete C shape per args). fn id[T](x: T) -> T { return x } struct Pair[T] { a: T, b: T } enum Box[T] { Val(T), Nothing } fn describe_all[T: Describable](x: T) -> string { return x.describe() } fn main() { let p = Pair[int] { a: 1, b: 2 } let q = id(p) } Topic Status Generic functions Done (also dual fn f<T>(…)) Generic structs / enums Done — write Pair[int] { … } Nested monomorphs Done — e.g. Box[Pair[int]] Interface bounds T: I Done — structural method set Iterator for via next Done — prefer fn next(mut self) -> Option[T]; for v in it advances in place Mutable lambda captures Done — multi-stmt outer let mut via heap cells; kick still requires ShareInt/Sync Full grammar: LANGUAGE_SPEC.md · tour: GUIDE.md §6 · book: ch03. Operators = is assignment only. Comparisons: == != < > <= >=. Logical: && || ! (and and / or / not). Bitwise: & | ^ &^ << >>, unary ^. == / != work on strings (by content), named structs (field-wise), and enums (tag + payload). Strings Byte strings with length. Prefer region ops when you only need to compare or search a span — no substring allocation: Builtin Role str_eq / str_contains / str_index whole-string str_slice_eq / str_slice_ci_eq / str_slice_contains / str_slice_index s[off:off+len] without alloc str_at_eq / str_byte_at prefix-at-offset · single byte See BUILTINS.md § Strings and examples/testing/str_slice_zc_test.mko. Comptime (const / const fn) Integer const bindings and const fn bodies fold at compile time: const fn clamp(x: int, lo: int, hi: int) -> int { if x < lo { return lo } else { if x > hi { return hi } else { return x } } } const N = clamp(50, 0, 10) // 10 Supported in const: + - * / % bitwise, comparisons, && || !, let / assign, return, if/else, if-expressions, match on ints (|, _, bind), bounded while / for, C-style for, bare break / continue, string seeds (const S = "…", +, str_len / ==, s[i] byte index), and const fn string params/returns (plus int fns that use string locals). Not a full CTFE interpreter. Actors actor Counter { n: int = 0 receive Inc { self.n = self.n + 1 } // tag only receive Add(delta) { self.n = self.n + delta } // int payload seed receive Bye { let _ = 0 } } // Counter_spawn() · Counter_send(m, Counter_Add(5)) · Counter_loop(m) Desugars to mailbox helpers; messages pack tag + optional int payload (actor_pack / actor_msg_tag / actor_msg_payload). Bye/Stop stops the loop. Tests: actor_test.mko. Interfaces ## Makori performance (docs/performance) Makori performance The mature path compiles through C. LLVM release emits objects directly and links with embedded lld/runtime inputs, using LLVM’s default<O3> pipeline. No GC, no interpreter, no VM tax. LLVM release currently covers scalar CFG and owned strings. On one Apple arm64 box, Fibonacci compiled in 20.1 ms (LLVM) vs 251.9 ms (C), and ran in 146.5 ms vs 148.9 ms (Mako C), 147.8 ms (hand C), 148.0 ms (Rust). Correctness gate: scripts/llvm-backend-test.sh. Those numbers are for that workload, not a ranking of languages. Performance is something we design for; it isn’t a finished claim. Makori 0.5.13 locks workload-specific budgets in benchmarks/performance-contract.json and CI enforces the reproducible subset with ./scripts/performance-contract.sh. A faster-than-Rust statement applies only to rows marked strict_rust_claim: true; bounded channel send/recv is measured against Rust but remains a regression-only budget until the runtime closes that gap. Bias toward the fast design. Convenience that costs belongs off the hot path or behind an opt-in. Measure vs hand-C and Rust per workload (SPEED_SAFE.md); bump baselines when you meant to change them. Scope cleanup and hold / share / arena — no stop-the-world. memory-safety-gate is there for a reason. Codegen is native (.mko → C → clang / LLVM), release -O3 -flto. Locals and direct calls stay cheap by default; alloc and sync cost show up when you use them. share, channels, crew are visible when they cost. Concurrent and parallel work is language-level. If it isn’t in a script with a method, it isn’t a claim. Aimed at backend and systems work: request arenas, tight slice/map layouts, native binaries. Integer channels check waiter counts while holding the channel mutex. Buffered enqueue/dequeue skips condition-variable signaling when no peer is blocked and signals one peer when one item or slot becomes available. Close retains broadcast semantics. Unbuffered rendezvous receives broadcast to senders because slot waiters and handoff-acknowledgement waiters share one condition variable; a one-peer signal can wake the wrong predicate and strand the handoff owner. This removes uncontended wake overhead without weakening MPMC synchronization or lifetime guarantees. Runtime telemetry is pay-for-use in generated C. Programs that call runtime_stats_json() or runtime_stats_reset() compile with exact atomic task, channel, and lock counters. Programs that do not use those builtins compile the counter operations out of the hot path. Native C integrations can force the instrumented form with -DMAKO_RUNTIME_METRICS=1. Release --backend native preserves the mature AST-to-Cranelift whole-function fast paths for recognized Fibonacci and generated slice-reduction kernels. General programs and all test harnesses continue through ownership-explicit shared IR. This prevents canonical IR migration from silently discarding proven CPU transforms while keeping backend selection narrow and deterministic. Copy-on-write slice cost model On the C backend, cloning an owned heap-backed slice performs an atomic retain and is O(1). Reads continue to share backing storage. The first mutation of a shared slice allocates and copies its live elements, so that detach is O(n); subsequent unique mutations reuse the detached allocation. Borrowed views and pool-backed buffers do not participate in refcounting. This removes unconditional deep copies from collection-heavy read and pass-through paths without adding a collector. It is not a promise that every slice operation is allocation-free: mutation of shared storage deliberately pays the copy required to preserve value semantics. The native backend uses explicit owned/borrowed tracking across calls and returns; benchmark each backend rather than assuming the C refcount cost model applies to both. Book: §11 Speed & memory safety · Release how-to: howto/09-release-builds.md. Don’t invent numbers. Re-run locally: # Microbenchmarks (fib, slice, map): ./scripts/bench-gate.sh ./scripts/bench-gate.sh 1.5 # stricter threshold ./scripts/performance-contract.sh # Direct-native parity against Mako C, hand C, and Rust # (core ≤1.25×; map ≤2.50×; io ≤2.00×; + regression vs baselines JSON): ./scripts/native-bench-gate.sh # Subset / override: # MAKO_NATIVE_WORKLOADS="native_map native_io" ./scripts/native-bench-gate.sh # Baselines: scripts/native-bench-baselines.json (MAKO_NATIVE_REGRESSION=1.15) # Years-up steady-state (live ownership + RSS stability): ./scripts/long-run-soak.sh # HTTP accept-loop soak (RSS under concurrent clients): ./scripts/http-long-run-soak.sh # See docs/LONG_RUNNING.md (years-up soaks for long-running services). # Optional: MAKO_ALLOCATOR=mimalloc|jemalloc · scripts/pgo-build.sh for PGO. # Anneal — adaptive opt (traffic feedback, offline PGO): docs/ADAPTIVE_OPT.md · scripts/anneal-cycle.sh # HTTP throughput (requires wrk or hey): ./scripts/bench-http.sh # Compiler scaling (cold and cached checks, JSON output): p ## Makori release & cross-platform guide (docs/release) Makori release & cross-platform guide Product version: 0.6.8 (Cargo.toml / makori version); release tag v0.6.8. Tree status: examples/testing inventory 438 *_test.mko files (2026-08-30): CI/claims gates pass across the release matrix. Versioning: small patches preferred — VERSIONING.md. Backends: default native for debug/test; use explicit --backend c as the oracle for C-only modes and --backend llvm --release for optimizing builds (see BUILD.md § Backend policy). Train: 0.6.8 interface type hardening and consolidation planning; C/native backend coverage and sanitizer gates must remain green. Modes: native/LLVM refuse unsupported sanitize/static/cross/wasm/emit-c modes — use explicit --backend c (see BUILD.md § Modes matrix). Published release: last tagged GitHub release may lag the tree — check releases. Platform-specific workflow artifacts only; this guide does not promise a binary for every target triple. External: homebrew-core publish (see STATUS). The release body and checksums are generated by GitHub Actions. The historical packaging/ snapshots are not the source of current release metadata. 0.6.8 release notes Reject interface implementations whose non-receiver parameters or return type do not match the declared interface method. Add the v0.7 consolidation plan and a claims-gate regression fixture. 0.6.7 release notes Preserve consuming View detachment: v = append(v, x) creates owned backing, ends the base borrow, and remains valid across C/native/LLVM backends. Make the standalone refcount fault probe portable under strict C11 on Linux. 0.6.6 release notes Slice Views are explicit NLL borrows; their base cannot detach, mutate, move, reassign, drop, or create a competing View while the borrow is live. Mutable Views remain the exclusive zero-copy mutation path within one task. Slice refcount overflow, underflow, and retain-after-release abort instead of wrapping or resurrecting storage. The language and memory-model specifications now define slice header, element ownership/destructor, detachment, Send, and atomic-ordering rules. 0.6.5 release notes Unicode 17 XID identifiers, normalization, and property tables. OpenSSL 3.5+ ML-DSA key generation, signatures, and certificates. Source-aware error chains, UUID v1/v6/v8, and float/bool JSON derivation. C and native backend regression coverage for the new builtin surfaces. 0.6.4 release notes String and aggregate channel try_send / send_timeout methods lower to typed C runtime helpers instead of the integer-channel API. String timeout sends retain caller ownership on success, timeout, and closed outcomes; FayDB's WAL transaction test compiles and passes under the C test backend. 0.6.3 release notes C-backend string, channel, map, and iterator range loops release owned body temporaries after every iteration instead of retaining them until function exit. Durable workloads no longer accumulate loop-local allocations until an rc_alloc out-of-memory abort. 0.6.2 release notes C-backend heap slices use atomic refcounted backing, making clones O(1), and detach before mutation to preserve value semantics. Borrowed views and pool-backed buffers stay outside the refcount release path; generated helpers match cleanup to the backing allocator. Native lowering tracks owned and borrowed slice values across calls, returns, nested temporaries, and discarded structs. Release verification passed ASan/LSan, TSan, UBSan, native differential tests, the memory-safety gate, and long-running RSS soaks. 0.5.15 release notes makori fmt --check is available for CI/editor gates and fails when files differ from canonical formatting. makori doctor validates native runtime sources plus structured install-manifest.json fields: schema, version, binary, runtime, and stdlib. Typechecker diagnostics now report line/column for inferred semantic errors, including equality mismatch issue #39. Integer channels avoid unnecessary global select notifications, modulo ring advancement, and repeated peak-depth CAS on the hot path; channels remain a measured regression-budget workload, not a faster-than-Rust claim until they are consistently below Rust. Official install scripts write consistent manifest fields and plain output. Release archives include share/mako/package-metadata.json with product, artifact, host, mode, and payload facts. 0.5.13 release notes Added benchmarks/performance-contract.json and scripts/performance-contract.sh as the hard performance gate. Runtime Rust comparison now covers fib, stack structs, slices, maps, strings, and bounded channels. Strict speed claims are limited to workloads marked strict_rust_claim; the channel workload is measured with a 3.5× regression budget and no speed claim. Parser hot-path smoke budgets run through bench-compile.py in the same contract gate. scripts/bench-gate.sh fails hard when rustc is unavailable. 0.5.12 release notes Main CI rejects continue-on-error and has a dedic ## Makori roadmap (docs/roadmap) Makori roadmap Product version: 0.6.5 (tip) · release tag v0.6.5 · Last sync: 2026-08-30. Suite: 423 examples/testing *_test.mko files · 2026-08-26: C 423 passed, 0 failed · native 423 passed, 0 failed (per-file sweep) · cargo test 156 passed, 0 failed · tooling, stdlib, memory-safety, and performance gates passed locally. Versioning: VERSIONING.md — prefer small patches over mega-minors. Release: tag v0.6.5; tip train 0.6.5. Verified: STATUS.md · Stdlib: STDLIB.md · Security: SECURITY.md · Release: RELEASE.md. Book: The Makori Book · Identity: IDENTITY.md. Soundness: SOUNDNESS.md · Memory model: MEMORY_MODEL.md. Native plan detail: NATIVE_COMPILER_PLAN.md. Version map (0.4.5 → patches → 0.5.x → 1.0) Version Theme Status 0.1.9–0.2.5 Generics → stdlib → soundness → tooling honesty Shipped 0.3.0 Cross-platform, CI green, ownership hardening Shipped 0.4.0 Performance — DCE, constant folding, runtime speed, lint Shipped 0.4.1 Windows/runtime/edge stability Shipped (see CHANGELOG) 0.4.5 Native compiler product path (language + release cut) Shipped — tag v0.4.5 0.4.6–0.4.15 Perf gates, cross/WASM/static, LLVM CI, soaks, messaging, adaptive opt Shipped (folded into later tags) 0.4.16 Memory-safety audit · anneal naming · hot-site tests Shipped 0.4.17 Ownership fixes · Windows mutexes · portable crypto · LSP · security audit Shipped 0.4.18 Hex/bin/oct literals · security hardening (white-hat audit) Shipped 0.4.19 Remote HTTPS registry · ed25519 package signing · makori pkg get Shipped 0.4.20 #line source mapping directives · debugger-friendly C output Shipped 0.4.21 Public package registry · default registry URL · wildcard version fix Shipped 0.5.0 Native-first default (CLI default flip — minor theme) Shipped 0.5.1 DTLS 1.2 + SRTP key export · DCE underscore fix · native stdout flush Shipped 0.5.2 Runtime trust & production concurrency soaks Shipped 0.5.3 Native backend completeness & struct memory safety Shipped — struct clone/drop, chained assign, mut param safety 0.5.4 Stdlib expansion, TLS server pool, self-contained macOS Shipped — math, os, sort, collections, CMap, UDP reuseport, bundled LLD 0.5.5 CI fixes, OpaqueHandle, backend regressions Shipped — #34 #35 #36, CMap ASan fix, TLS mutex fix 0.5.6 Native heap-argument ownership Shipped 0.5.7 Stdlib expansion (144 package files), str_slice, string compare Shipped 0.5.8 Memory-safety gates, native mutable slice ownership, claims CI Shipped 0.5.9 Stdlib safety contract families and enforced audit Shipped 0.5.10 Package-local malformed codec coverage and fail-closed Base64 Shipped 0.5.11 Native backend hardening and no silent C fallback Shipped 0.5.12 Flake and CI honesty: hard gates plus explicit quarantine Shipped 0.5.13 Performance contract: workload-specific Rust budgets and parser hot-path gates Shipped 0.5.14 Stdlib safety completion: package-local evidence and explicit unsafe-boundary exclusions Shipped 0.5.15 Tooling polish: doctor, installers, release metadata, version reporting, fmt/lint/doc stability Shipped 0.6.0 Pipe operator, prove contracts, and live function syntax foundation Shipped 0.6.1 Native LLM bridge and release-platform hardening Shipped 0.6.2 Copy-on-write slice ownership and memory-safety hardening Tip 0.6.x Further patches on 0.6 Planned as needed 1.0 Stability contract (compat, LTS-ish discipline) Planned after the 0.x series Principle: ship measurable gates each patch or minor; do not reopen identity (no free go, no lifetime params, no silent native→C fallback). Prefer 0.4.N patches over waiting for 0.5.0. 0.4.5 language gate [shipped] 0.4.6–0.15 perf gates, cross, soaks, messaging, adaptive opt [shipped] 0.4.16 memory-safety audit [shipped] 0.4.17 ownership fixes, Windows, crypto, LSP [shipped] 0.4.18 hex/bin/oct literals, security hardening [shipped] 0.4.19 remote HTTPS registry, ed25519 signing [shipped] 0.4.20 #line source mapping directives [shipped] 0.4.21 public package registry, wildcard version fix [shipped] 0.5.0 native-first CLI default (minor) 0.5.1 toolchain/IDE 0.5.2 runtime trust 0.5.3 native backend completeness & memory safety 0.5.4 stdlib expansion, TLS server pool, self-contained macOS 0.5.5 CI fixes, OpaqueHandle, backend regressions 0.5.6 native heap-argument ownership 0.5.7 stdlib expansion, str_slice, string compare 0.5.8 memory-safety gates, native mutable slice ownership, claims CI 0.5.9 stdlib safety contract families and enforced audit 0.5.10 package-local malformed codec coverage and fail-closed Base64 0.5.11 native backend hardening and no silent C fallback 0.5.12 flake and CI honesty 0.5.13 performance contract and workload-specific budgets 0.5.14 stdlib safety completion and pack ## Makori security (docs/security) Makori security Status: actively hardened toward the product goal of 100% memory-safe safe Mako, not formally proven. The ownership model prevents many classes of memory bugs by construction, and the full test suite is exercised under ASan (with leak detection disabled) and UBSan with zero errors. ASan validates invalid accesses, use-after-free, double-free, and buffer overflows — but not general leak freedom. Edge cases are still being found and fixed. This is not yet equivalent to a formally verified memory model. Product version: 0.6.5. Mako treats safety as a compiler and runtime contract, not a style guide. The goal: make memory corruption and common backend footguns hard to ship — by construction where possible, by hard errors where not. Makori is its own language with its own syntax. Safety decisions are Mako-shaped: stdlib parity with Go or Rust never requires exposing their unsafe memory surfaces. Safe APIs must uphold Mako ownership, bounds, cleanup, and concurrency rules; unsafe or unverifiable integration stays explicit and outside the safe claim. Pillar How it shows up Ownership hold/share/arena — deterministic free, no GC Concurrency Structured crew cancel-joins ordinary kicked tasks; detach is explicit Bounds Array/slice bounds checks in all builds (safe release mode) Verification Full suite runs under ASan, UBSan, and TSan in CI Soundness program: SOUNDNESS.md · Memory model: MEMORY_MODEL.md · Stdlib gate: STDLIB_SAFETY.md. Slice backing ownership (0.6.2+) Safe slice values preserve value semantics without a tracing garbage collector: The C backend stores owned heap slices in atomic refcounted backing allocations. Cloning one is an O(1) retain; mutation and append detach first when backing storage is shared. Borrowed views, stack literals, and pool-backed buffers are non-refcounted and never enter the refcount release path. Generated cleanup matches the allocator that produced the backing storage. The native backend records owned versus borrowed values across calls and returns, transfers returned ownership to the caller, and cleans nested or discarded temporaries at their last use. Struct fields and generated collection helpers follow the same retain, replace, and release rules as local slices. This contract is covered by adversarial aliasing and clone-storm tests, native differential tests, leak checks, ASan/LSan, TSan, UBSan, and long-running RSS soaks. It is evidence of continued hardening, not formal verification. unsafe blocks and unverifiable FFI remain outside the safe-language guarantee. Principles Prevent, don't advise -- illegal states should not compile or should abort with a clear diagnostic. No GC -- packages stay on ownership, shares, and arenas for predictable latency. There is no collector mode that can weaken hold/share/move rules. Secure defaults in stdlib -- parameterized DB APIs, header validation, constant-time token compare, explicit secret wiping, verified TLS by default. Speed is the name of the game -- security features that cost cycles stay opt-in or debug-only; do not silently tax every release binary. Footgun Prevention Policy Safe Mako should make the secure path the short path. APIs that commonly lead to memory corruption, credential leaks, injection, or silent downgrade must force an explicit choice: a loud name, an unsafe boundary, or a failing return. No hidden insecure fallback: TLS, HTTPS, JWT, database, and parser helpers fail closed instead of silently downgrading verification, bounds, or algorithm checks. Dangerous names are explicit: helpers such as *_insecure are for demos, tests, and controlled local development only. They are not part of the safe default path and must have a verified alternative next to them. CI can enforce this: makori lint --security fails on known insecure helper calls unless the exact line carries // mako: allow-insecure. Sanitizer-clean runtime boundaries: HTTP client DNS/connect uses getaddrinfo rather than direct legacy hostent pointer loads, keeping the network path compatible with UBSan alignment checks. Input injection is rejected at the boundary: HTTP headers reject CR/LF/NUL, SQL has parameterized APIs, URL/path helpers normalize before use, and parsers bound lengths before touching buffers. Secrets are not ordinary strings once classified: keys, bearer tokens, password material, and session secrets should use Secret plus secret_eq_str/const_eq; docs and examples must not teach == for token checks. Unsafe stays narrow: raw memory, unchecked indexes, FFI ownership transfer, dynamic loading, and platform-specific handles are excluded from safe parity unless wrapped by checked handles with deterministic cleanup. Concurrency Send seed (kick) crew.kick(f(args…)) only accepts Send argument types: Copy scalars (including float and Uuid/ULID POD), deep-POD structs, string (heap-cloned), channels, ShareInt / AtomicInt (RC clone), locked handles (CMap / Mutex / RWMutex), ## Makori status (adversarial / verified) (docs/status) Makori status (adversarial / verified) Last inventory: 2026-08-30 · product mako0.6.8 (tip; release tag v0.6.8) · versioning: small patches — VERSIONING.md. Unique Mako surface · pack/pull · map/slice/bag monomorphs · package-per-directory · const-fn depth (match/while/for/strings · s[i]) · 438 examples/testing *_test.mko files · 2026-08-30: release claims gate passed · cargo test 356 passed, 0 failed · tooling, stdlib, memory-safety, and performance gates passed locally · CI ASan/UBSan; focused concurrency under TSan · CI honesty policy gates hard failures/quarantines · The Makori Book. Book: The Makori Book · Guide: GUIDE.md · Identity: IDENTITY.md · Pain points: PAIN_POINTS.md · Build: BUILD.md · Stdlib: STDLIB.md · Roadmap: ROADMAP.md · Changelog: ../CHANGELOG.md · Release: RELEASE.md · Soundness: SOUNDNESS.md · Memory model: MEMORY_MODEL.md. Completion estimate (honest) Scope Approx. Product version 0.6.8 tip · release tag v0.6.8 (ROADMAP.md, VERSIONING.md) MVP / usable language Core compiler/runtime scope is exercised; this is not a production-readiness claim STATUS north-star Tracked scope is explicit; optional depth below remains Mako identity (preferred syntax) Checklist complete — IDENTITY.md; not a maturity score Target pain coverage 22/24 scoreboard rows Strong (1 Partial, 1 mixed) — PAIN_POINTS.md Dual-form coverage (optional sugar) 52/52 in-scope items Done (1 intentional Won't: *T/&x) — GO_SYNTAX_CHECKLIST.md Standard library Application packs have Go-equivalent surfaces (2026-08-18 wave). The default-safe claim covers safe and audited checked-native packages only; unsafe-boundary, blocked, won't, and external/environmental surfaces are excluded unless hardened and reclassified. Evidence lives in STDLIB_SAFETY.md and STDLIB_SAFETY_MATRIX.md. Not every Go toolchain/unsafe package — see STDLIB.md Soundness (SAFE/RT core) Introduced in 0.2.4, actively hardened — SOUNDNESS.md; soaks and edge cases remain Soundness — introduced in 0.2.4, actively hardened The core ownership and runtime safety model was introduced in 0.2.4 and continues to be hardened through adversarial tests, sanitizers, and regression gates. It is not a completed, permanently solved property. Program: SOUNDNESS.md · model: MEMORY_MODEL.md · roadmap: ROADMAP.md. Area Status SAFE-001 bounds in release Done SAFE-002 ownership categories Done SAFE-003/004 slice+map free (incl. monomorph) + reassign + nested release_replaced Done (2026-07-18 audit) SAFE-005 string own + string_view Done SAFE-006 CFG drops (return/break/continue/?/match/discard) + double-free guards Done (core) — resolved bag payload cleanup, borrowed-bag guard, bind-scope free, __own alias mut, move/clone store SAFE-007 arena/slice escape + field store Done SAFE-008 capture matrix Done (core) SAFE-009 CMap gate Done SAFE-010 memory model doc Done RT-001 / RT-005 / RT-006 Done RT-002/003 scheduler pool + spawn_blocking Done (seed) RT-004 channel ownership (clone/take) Done (core) Struct Own field free Done Pkg lock build verification (PR #3) Done Hot path: stack POD lits + cold free Done Docs — Done Piece Status The Makori Book (docs/book/ · mdBook book.toml + chapters) Done Accuracy pass: README / GUIDE / STATUS / ROADMAP / howto index Done Collections surface docs (ERGONOMICS · LANGUAGE · BUILTINS · book ch03/ch14/ch15 · howto/10 · llms*) Done — full map/slice/bag surface + demand-driven monomorphs Tooling — Done Piece Status makori version / --version with OS/arch Done Grouped import ( / { + fmt Done Packs & pulls (pack/pull flair, always qualify, import/package dual, internal rewrite) Done Low-ceremony ergonomics doc + tests (print poly, == strings, match routes, maps/slices) Done — ERGONOMICS.md Path-style import blocks (nested std, vendor/, module=, aliases, blank-line groups) Done Speed / concurrency / parallelism north star (SPEED.md) Done (product bar) fan + Mako fn lambdas (block body codegen + types) · crew/fan tests Done CLI help polish (build/run/check/test flag docs; version near top) Done VS Code mako-native launch configs through LLDB/cpptools Done makori pkg audit offline advisory and license policy checks Done mako doc API markdown, runnable examples, and search index Done makori test --coverage plus fuzz/property/snapshot/mock/fixture categories Done mako profile wall-clock compile/run profile reports with JSON output Done Release archives include the full internal docs tree and top-level release notes Done Standard library — Wave 9 Area Status RE2 backrefs \1–\9 · \p{L/N} ASCII · [:lower:]/[:upper:]/[:punct:] Done JFIF grayscale encode (jpeg_encode_gray_jfig + jpeg_is_jfif) Done Reflect type schema registry from codegen constructors Done SMTP STARTTLS soft path + AUTH PLAIN; OpenSSL probe Done str_cut / str_count Done UTF-8-aware regexp \p{...} for common scripts/categories + simple lookahead Done Tests goex ## Makori vision (docs/vision) Makori vision North star Native compilation · no garbage collector · structured concurrency · ownership-based memory · practical standard library · fast builds. Goal: a compiled language for backend and systems development that is simple to write, produces fast native binaries, and manages memory without a tracing GC. Concurrency and parallelism are language primitives, not library abstractions. Why Mako exists: we wanted a language that compiles to native code, handles memory deterministically, has structured concurrency built in, and doesn’t require heavy ceremony for everyday backend work. Makori is our answer — still experimental, still evolving. Principle What it means Native performance Compiled to C, then native — no interpreter or VM overhead Concurrency first-class crew / kick / join / channels / select / actor — structured, no leaked tasks Parallelism first-class fan + multi-kick crews — use the cores without a third-party pool Memory safety (in progress) Ownership, arenas, explicit resource control — active UAF prevention via ASan-verified drops Simple syntax Clean, readable code that gets out of your way Low ceremony Real work without a lot of typing (ERGONOMICS.md) Fast builds Incremental compilation; compile times stay short Easy deploy Static binaries where the target/toolchain supports them Practical stdlib Batteries for common backend tasks (HTTP, TLS, JSON, SQL, networking) Makori is for backend software, networking systems, developer tools, and services — without a mandatory garbage collector. Product surfaces that must work over time: Backend applications and API services (HTTP/JSON, makori init --backend) CLI and developer tools (flags, env, files, subprocesses, static binary deploy) Cloud and infrastructure tools (agents, operators, sidecars, proxies, gateways) Systems programming (arenas, hold/share, bytes/files, append logs) Database / storage engines (mini embedded KV in examples/db_engine/, plus SQL clients) Realtime and telecom systems (actors, timers, protocol stacks, session state) Fast native binaries (release -O3 -flto, no GC — PERFORMANCE.md) Core promise: Ship fast binaries, run concurrent and parallel work as a first-class part of the language, stay safe without a GC, keep everyday code short. Syntax promise: Makori has its own syntax. It may accept dual spellings for familiarity, but preferred docs, examples, and makori fmt always lead with Makori forms: fn, let, on, pack / pull, hold / share / arena, crew / kick / join, match, export, .mko. See IDENTITY.md. Honest status lives in STATUS.md. How to write Mako today: The Makori Book (guided tour) and GUIDE.md (verified syntax). This file is the product map (includes Target ideas). Identity checklist Pillar Target Memory Ownership + arenas; RC/manual escapes; no tracing GC Speed Native performance; measure; no silent cost Concurrency First-class crew / channels / actors / select (structured) Parallelism First-class fan + multi-kick crews Syntax Unique Mako surface; familiar, concise, practical backend style Errors Explicit, typed, easy ? — unused Result is illegal Tooling pkg, fmt, lint, test, bench, docs, audit, cross-compile, IDE/LSP Stdlib net/tls/quic/http/ws, JSON/CBOR/…, DB drivers, queues, observability Systems Drivers, protocols, DBs, engines, compilers Generics List<T>, Map<K,V>, Result<T,E> — light interfaces Deploy Static binaries, small containers, WASM later, fast startup Versatility Goal Mako should be equally comfortable for: REST / GraphQL / gRPC APIs, modular monoliths, microservices, background jobs CLI tools, developer tools, migration tools, deployment tools, cloud CLIs Cloud infrastructure: operators, controllers, sidecars, agents, gateways Network services: proxies, load balancers, WebSocket servers, streaming APIs Data systems: databases, caches, search engines, queues, storage engines AI inference services, realtime applications, telecom platforms, edge/WASM apps The standard for "general purpose" is practical: a beginner should be able to ship a simple API, and an expert should be able to build a database, proxy, compiler, or distributed runtime. Domain Track — Sessions Session-oriented servers remain a high-value proving ground: VoIP/telecom, game rooms, connection brokers, streaming gateways, and realtime collaboration. // Target surface (actors) actor Session { state Call receive Invite receive Bye receive Timer } The actor model keeps actor state behind message passing rather than exposing it as ordinary shared mutable state. Under the hood today: mailboxes on channels + crew (see examples/actor.mko). This is a language/runtime design boundary. The compiler enforces this boundary for safe Mako kick/fan code; generated C, FFI, and explicit unsafe code remain outside that guarantee. Realtime / telecom priority stack This track should guide runtime and networking decisions without becoming the languag ## WASM / WASI (preview1 beachhead + browser/edge starter) (docs/wasm) WASM / WASI (preview1 beachhead + browser/edge starter) Book: §12 Cross-platform & WASI · How-to: howto/07-wasi.md. Product tip: 0.6.5. Browser/DOM bindings are planned for a future release. Status makori build --target wasm32-wasi (alias of wasm32-wasip1) uses wasi-sdk clang + sysroot when WASI_SDK_PATH (or /opt/wasi-sdk, /usr/local/wasi-sdk) is set. Piece Status Driver: wasi-sdk clang, --target=wasm32-wasip1, no host -pthread/OpenSSL Done Minimal runtime (-DMAKO_WASI → mako_rt.h only) Done Hello / print + fib → runnable .wasm under wasmtime Done argv / environ (argc / arg_get / env_get via wasi-libc) Done FS preopens (read_file / write_file + wasmtime --dir) Done Clear skip when SDK / wasmtime missing Done (scripts/wasi-verify.sh) Sockets / HTTP / TLS / DB on WASI VISION Later WASI preview2 / full browser DOM Target / later Browser/edge starter (makori deploy wasm) Done for preview1 loader path Browser loader polyfill (wasm/mako-wasi-loader.js) Seed STATUS counts preview1 beachhead as Done. makori deploy wasm makes that path usable in browser/edge-style static hosting through a preview1 polyfill. Sockets, preview2 components, Workers request adapters, and full browser DOM bindings remain target work. env_set soft-fails on WASI (no setenv in wasi-libc) — pass env from the host (wasmtime --env KEY=VAL). Browser loader supplies empty argv/environ. FS paths: use relative names with --dir=HOST::. (guest . = sandbox), or absolute /file with --dir=HOST::/. Without a matching preopen, read_file returns "" and write_file returns -1. Try (local SDK) export WASI_SDK_PATH=/path/to/wasi-sdk # or use .mako/toolchains/wasi-sdk mako build examples/wasi_hello.mko --target wasm32-wasi -o out/wasi_hello.wasm wasmtime out/wasi_hello.wasm # → hello from mako wasi / 55 mako build examples/wasi_args_env.mko --target wasm32-wasi -o out/wasi_args_env.wasm wasmtime --env MAKO_WASI_GREET=hi out/wasi_args_env.wasm hello # → argc / hello / hi mkdir -p out/wasi_fs_sandbox && echo seed > out/wasi_fs_sandbox/in.txt mako build examples/wasi_fs.mko --target wasm32-wasi -o out/wasi_fs.wasm wasmtime --dir=out/wasi_fs_sandbox::. out/wasi_fs.wasm # → seed / 0 / wrote Or: ./scripts/wasi-verify.sh (exits 0 with skip: if toolchain missing). Emit C then cross-compile mako build examples/wasi_hello.mko --emit-c -o /tmp/wasi_hello.c # Generated C still has `#ifndef MAKO_WASI` guards; for manual clang: $WASI_SDK_PATH/bin/clang --target=wasm32-wasip1 \ --sysroot=$WASI_SDK_PATH/share/wasi-sysroot \ -I runtime -O2 -std=gnu11 -DMAKO_WASI -D_WASI_EMULATED_PROCESS_CLOCKS \ -D_POSIX_C_SOURCE=200809L /tmp/wasi_hello.c -o /tmp/wasi_hello.wasm \ -lwasi-emulated-process-clocks Docker recipe (no local SDK) ./scripts/wasi-ci-build.sh # or: docker build -f docker/wasi-build.Dockerfile -t mako-wasi . docker/wasi-build.Dockerfile installs wasi-sdk, builds mako, then runs makori build examples/hello.mko --target wasm32-wasi and checks the .wasm is non-empty. Browser glue (fd_write + empty environ/args) Generate a starter: mako deploy wasm wasm-dist --entry examples/wasi_hello.mko --wasm hello.wasm --port 8080 ./wasm-dist/build-wasm.sh python3 -m http.server -d wasm-dist 8080 wasm/mako-wasi-loader.js + wasm/index.html fetch hello.wasm and instantiate with a minimal wasi_snapshot_preview1 import object: fd_write → console.log / page <pre> environ_sizes_get / environ_get → empty environ (count 0; NULL list) args_sizes_get / args_get → empty argv (argc 0; NULL list) clock_time_get → Date.now() as realtime nanoseconds random_get → crypto.getRandomValues (fallback Math.random) fd_prestat_get / fd_prestat_dir_name → one virtual preopen: fd 3 → "/"; other fds → EBADF (8) path_open under fd 3: hello.txt → "hi", bye.txt → "bye"; unknown without O_CREAT → ENOENT (44); O_CREAT → empty writable virtual file; other dirfds → ENOTCAPABLE (76) path_open /host/<rel> → fetch cwd-relative ./<rel> (sync XHR). With FD_WRITE rights: in-memory write overlay (HOST_OVERLAY); CREAT allowed for empty overlay. Rejects .., absolute paths. Not a general host FS — overlay never escapes the browser. path_create_directory → ENOTCAPABLE (76) path_unlink_file under fd 3 → remove virtual path (ENOENT if missing) fd_seek / fd_tell on virtual file fds (whence SET/CUR/END) fd_filestat_get → filetype regular + size for virtual file fds fd_read / fd_write → virtual file bytes; writable fds append via fd_write and are readable back Other WASI calls are unsupported and return 0 / ENOSYS. ./scripts/wasi-ci-build.sh cp out/hello.wasm wasm/ python3 -m http.server -d wasm 8080 # open http://127.0.0.1:8080/ Preview2 / edge boundary makori deploy wasm is the browser/edge story for current Mako: build a WASI preview1 module and run it behind a JS polyfill. It is useful for CLIs, deterministic compute, demos, and static-hosted edge experiments. Still target work: WASI preview2/component-model output WIT interface generation HTTP sockets ## Getting Started (howto/howto-01-getting-started) Getting Started This guide walks you through installing Mako, creating a project, and running your first program. By the end you will have a working development loop. Install Mako Prebuilt (recommended — no Rust) # macOS curl -fsSL https://github.com/loreste/mako/releases/latest/download/install-release.sh | bash source "$HOME/.local/share/mako/env.sh" # Linux curl -fsSL https://github.com/loreste/mako/releases/latest/download/install-linux.sh | bash source "$HOME/.local/share/mako/env.sh" Pin a version: --version v0.2.3. Needs clang so .mko files can compile. From source make install # requires cargo/rustc + clang This places the mako binary in ~/.local/bin/ and runtime headers in ~/.local/share/mako/runtime. Ensure ~/.local/bin is on your PATH. Verify the installation: mako version # mako version mako0.6.2 darwin/arm64 mako version -v # includes the git commit hash Create a project Makori provides scaffolding for three project shapes: # Simple application mako init hello --name hello # Backend API service (includes HTTP handler scaffold) mako init mysvc --backend # Multi-package workspace (lib + app) mako init myws --workspace Each creates a directory with mako.toml and a main.mko entry point. Project structure After makori init hello --name hello: hello/ mako.toml # package manifest (name, version, dependencies) main.mko # entry point — must contain func main() / fn main() The mako.toml looks like: name = "hello" version = "0.1.0" Write your first program Open hello/main.mko (Mako-native syntax preferred): fn main() { print("hello from mako") print_int(fib(10)) } fn fib(n: int) -> int { if n <= 1 { return n } return fib(n - 1) + fib(n - 2) } Identity guide: IDENTITY.md. Dual forms (func, :=, …) still work for compatibility. The development loop From inside the hello/ directory: # Typecheck without compiling (fast feedback) mako check main.mko # Compile and run in one step mako run main.mko # Build a binary (name comes from mako.toml) mako build main.mko # Run the binary directly ./hello Passing arguments to your program mako run main.mko -- arg1 arg2 Inside the program, use argc(), arg_get(i), or args() to read them. Key commands Command Purpose makori check file.mko Typecheck (incremental, fast) makori run file.mko Compile and execute makori build file.mko Produce a binary makori build --release file.mko Optimized release binary makori build -j 8 file.mko Parallel compilation makori test path/ Run tests makori fmt file.mko Format source code makori version Print version and platform Running from source (no install) If you have not installed yet, run directly from the compiler source tree: cargo run --release -- check examples/hello.mko cargo run --release -- run examples/hello.mko Environment variables Variable Purpose MAKO_RUNTIME Override runtime header location MAKO_JOBS Default parallel job count (same as -j) Next steps Build an HTTP API Handle errors properly Set up packages and dependencies ## Building HTTP JSON APIs (howto/howto-02-http-apis) Building HTTP JSON APIs This guide builds a complete JSON API server with routing, request parsing, and response handling. You will also make client requests to test it. Minimal server A Makori HTTP server uses four steps: bind, accept, respond, close. fn main() { let fd = http_bind(8080) let mut n = 0 while n < 100 { let c = http_accept(fd) if c >= 0 { let _ = http_respond(c, 200, "hello from mako\n") let _ = http_close(c) n = n + 1 } } let _ = http_close_listener(fd) } Build and run: mako build main.mko -o server ./server & curl http://127.0.0.1:8080/ # hello from mako kill %1 Adding routes Use http_path and http_method to dispatch requests: fn main() { let fd = http_bind(8080) let mut running = true let mut count = 0 while running { let c = http_accept(fd) if c < 0 { continue } let method = http_method(c) let path = http_path(c) if str_eq(path, "/health") { let _ = http_respond_json(c, 200, "{\"ok\":true}\n") } else if str_eq(path, "/echo") { let body = http_body(c) let _ = http_respond_ct(c, 200, "text/plain", body) } else { let _ = http_respond(c, 404, "not found\n") } let _ = http_close(c) count = count + 1 if count >= 50 { running = false } } let _ = http_close_listener(fd) } JSON responses with derive Use #[derive(json)] to generate serializers for your types: #[derive(json)] struct User { name: string age: int } fn handle_user(c: int) { let json = User_to_json("Ada", 36) let _ = http_respond_json(c, 200, json) } For manual JSON construction: fn health_json() -> string { return json_object(json_si("status", "ok") + "," + json_i("uptime", 42)) } Reading request headers and body let c = http_accept(fd) let content_type = http_header(c, "Content-Type") let auth = http_header(c, "Authorization") let body = http_body(c) Keep-alive connections For clients that reuse connections, call http_next instead of closing: let c = http_accept(fd) let _ = http_respond(c, 200, "first\n") let ok = http_next(c) if ok > 0 { let _ = http_respond(c, 200, "second\n") } let _ = http_close(c) HTTP client Make outgoing requests from your program: fn main() { let body = http_get("http://127.0.0.1:8080/health") let status = http_last_status() print_int(status) print(body) let resp = http_post("http://127.0.0.1:8080/echo", "ping") print(resp) // With timeout (milliseconds) let data = http_get_timeout("http://example.com/api", 3000) } Complete working example Save as api.mko: #[derive(json)] struct Status { ok: bool version: string } fn main() { let fd = http_bind(18100) print("listening on :18100") let mut n = 0 while n < 20 { let c = http_accept(fd) if c < 0 { continue } let path = http_path(c) if str_eq(path, "/health") { let _ = http_respond_json(c, 200, "{\"ok\":true,\"version\":\"0.1.0\"}\n") } else if str_eq(path, "/echo") { let body = http_body(c) let _ = http_respond_ct(c, 200, "application/json", body) } else { let _ = http_respond(c, 404, "{\"error\":\"not found\"}\n") } let _ = http_close(c) n = n + 1 } let _ = http_close_listener(fd) } Test it: mako run api.mko & curl -s http://127.0.0.1:18100/health | cat # {"ok":true,"version":"0.1.0"} curl -s -X POST -d '{"msg":"hi"}' http://127.0.0.1:18100/echo # {"msg":"hi"} curl -s http://127.0.0.1:18100/unknown # {"error":"not found"} API reference Function Purpose http_bind(port) Start listening, returns fd http_accept(fd) Accept and parse one request, returns conn id http_method(c) Request method string http_path(c) Request path string http_body(c) Request body string http_header(c, name) Get a request header value http_respond(c, status, body) Send plain text response http_respond_ct(c, status, ct, body) Send response with Content-Type http_respond_json(c, status, json) Send JSON response http_close(c) Close connection http_close_listener(fd) Stop listening http_get(url) GET request, returns body http_post(url, body) POST request, returns body http_last_status() Status code of last client call http_last_header(name) Response header of last client call Next steps Handle errors in your API HTTPS and HTTP/2 (see Networking section) Scaf ## Errors and Debugging (howto/howto-03-errors-debugging) Errors and Debugging Mako enforces error handling at compile time. Every function that can fail returns a Result[T, E]. This guide covers patterns for working with results, adding context, and debugging when things go wrong. Result basics A function signals failure by returning error(...) and success with Ok(...): fn parse_port(s: string) -> Result[int, string] { match parse_int(s) { Ok(n) => { if n < 1 || n > 65535 { return error("port out of range") } return Ok(n) } Err(e) => return error("not a number") } } The ? operator Use ? to propagate errors up the call stack. If the result is Err, the function returns immediately with that error: fn load_config(path: string) -> Result[int, string] { let content = read_file(path) let port = parse_port(content)? return Ok(port) } Without ?, you would need an explicit match on every fallible call. Matching on results When you need to handle both cases explicitly: fn main() { let r = parse_port("8080") match r { Ok(port) => print_int(port), Err(msg) => { print("error: ") print(msg) }, } } Wrapping errors with context Use wrap_err to add context as errors propagate: fn connect_db() -> Result[int, string] { let r = parse_port(env_get("DB_PORT")) return wrap_err(r, "connect_db") } // On failure: "connect_db: port out of range" Use errorf for formatted error messages: fn open_config(name: string) -> Result[int, string] { if not file_exists(name) { return errorf("missing %s", name) } return Ok(1) } Error inspection let e = error("connection refused") let wrapped = wrap_err(e, "redis") let msg = error_string(wrapped) // "redis: connection refused" assert(error_is(wrapped, "refused")) // substring check Compile-time enforcement Mako refuses to compile code that ignores a Result: fn main() { // parse_port("bad") // COMPILE ERROR: unused Result let _ = parse_port("bad") // explicit discard — compiles } This ensures you never silently swallow failures. Debugging with dbg Insert dbg calls to print values to stderr with file and line info: fn process(n: int) -> int { let x = dbg(n * 2) // [dbg] file.mko:3: 42 let s = dbg_str("step 2") // [dbg] file.mko:4: step 2 return x + 1 } dbg returns its argument, so you can inline it in expressions without changing program behavior. Native debugging with lldb Debug builds (the default) include full debug symbols (-O0 -g): mako build main.mko -o app lldb ./app Inside lldb: (lldb) breakpoint set --name main (lldb) run (lldb) step (lldb) print x (lldb) bt All local variables, struct fields, and function arguments are visible to the debugger because Makoriri compiles through C with debug info preserved. Address sanitizer Catch out-of-bounds access and use-after-free at runtime: mako build --sanitize=address main.mko -o app_asan ./app_asan The sanitizer will print a detailed report if any memory violation occurs, including the exact source location. Thread sanitizer Detect data races in concurrent programs: mako build --sanitize=thread main.mko -o app_tsan ./app_tsan Practical error handling pattern A complete example combining these techniques: fn read_config(path: string) -> Result[int, string] { if not file_exists(path) { return errorf("missing %s", path) } let content = read_file(path) let port = parse_port(content)? return Ok(port) } fn start_server() -> Result[int, string] { let port = wrap_err(read_config("config.txt"), "config")? let fd = http_bind(port) if fd < 0 { return error("bind failed") } return Ok(fd) } fn main() { match start_server() { Ok(fd) => { print("server started") } Err(e) => { log_error(e) } } } Summary Tool When to use Result[T, E] Any operation that can fail ? Propagate error to caller wrap_err(r, ctx) Add context string to errors errorf(fmt, ...) Create formatted error messages error_is(e, sub) Check if error contains substring match Handle Ok/Err explicitly let _ = ... Explicitly discard a result dbg(x) / dbg_str(s) Print debug info to stderr --sanitize=address Detect memory errors --sanitize=thread Detect data races lldb Step through native code Next steps Organize code into packages Memory safety with hold/share ## Packages and Dependencies (howto/howto-04-packages) Packages and Dependencies This guide covers creating reusable packages, declaring dependencies, and organizing larger projects into workspaces. Package basics Every Makori project has a mako.toml at its root: name = "myapp" version = "0.1.0" Create one with: mako init myapp --name myapp # or for a library: mako pkg init mylib Project layout Package-per-directory: all non-test .mko files in a directory form one package and must share the same pack / package name (Go model). myapp/ mako.toml main.mko # application entry (fn main) lib.mko # library unit (optional name; merged with siblings) helpers.mko # same pack — merged automatically When another package depends on yours, Mako merges all non-test units except main.mko (binary entry stays out of the library surface). Cross-file calls inside the package resolve before the import prefix is applied. util/ lib.mko # pack util · greet more.mko # pack util · shout (calls greet) Adding a local dependency Suppose you have a helper library next to your app: projects/ helper/ mako.toml # name = "helper" lib.mko # fn add(a: int, b: int) -> int { return a + b } app/ mako.toml main.mko In app/mako.toml: name = "app" version = "0.1.0" [dependencies] "helper" = { path = "../helper", version = "0.1.0" } Or use the CLI: cd app mako pkg add helper ../helper In app/main.mko, call functions through the dependency namespace: fn main() { print_int(helper.add(2, 3)) } The namespace comes from the key in [dependencies] -- rename it with: "math" = { path = "../helper" } Then call math.add(2, 3). Transitive dependencies If helper depends on core, and app depends on helper, Mako walks each package's mako.toml transitively. Each package uses its own declared names: app -> helper -> core (helper calls core.scale) (app calls helper.add) Git dependencies For a concrete local package: [dependencies] "tool" = { path = "../tool", version = "0.1.0" } Then fetch: mako pkg fetch This clones into .mako/deps/tool/. Use --offline flags to prevent network access in CI. Lockfile Pin exact versions for reproducible builds: mako pkg lock This writes lockfile version 2 with deterministic SHA-256 hashes of the root manifest and recursive .mko sources. Commit it to version control. The makori pkg install, makori build, makori run, and makori check commands rehash locked dependencies and fail if their content changed, including nested source files. They also fail closed when a transitive manifest cannot be read or the lockfile has malformed or contradictory fields. Use makori pkg update only after inspecting an intentional dependency change. The same command migrates legacy version 1 lockfiles; install does not silently trust their older non-cryptographic hashes. Package commands Command Purpose makori pkg init mylib Create a new package makori pkg add name path=../name Add or update a path dependency makori pkg add name ../name Same (positional) makori pkg remove name Remove a dependency makori pkg list Show packages and their status makori pkg fetch Clone git dependencies makori pkg lock Write/update mako.lock makori pkg audit Check advisories and license policy Workspaces For larger projects with multiple packages that build together: mako init myws --workspace This creates: myws/ mako.toml # [workspace] members = ["lib", "app"] lib/ mako.toml lib.mko app/ mako.toml # [dependencies] "lib" = { path = "../lib" } main.mko Root mako.toml: [workspace] members = ["lib", "app"] Workspace commands From the workspace root: Command Behavior makori check . Typecheck all members makori build . Build members with main.mko makori test . Run tests in all members makori fmt . Format all members makori run -p app Run a specific member makori check -p lib Check a single member If only one member has main.mko, makori run . runs it directly. Security audits Create mako-cve.toml beside your lockfile: [[advisory]] id = "CVE-2024-1234" name = "util" version = "<=1.2.3" severity = "high" And mako-license.toml for license policy: allow = ["MIT", "Apache-2.0"] deny = ["GPL-3.0"] [licenses] helper = "MIT" Then run: mako pkg audit This checks offline -- no network required. Pulls (multi-file) Most real projects need more than one file. Mako pulls are always pack-qualified so call sites stay clear. makori run compiles everything that’s pulled. Basic file pull // utils.mko pack utils fn format_name(first: string, last: string) -> string { return first + " " + last } // main.mko pull "./utils.mko" fn main() { print(util ## Concurrency (howto/howto-05-concurrency) Concurrency Makori uses structured concurrency: ordinary kicked work lives inside crew blocks and is joined before the block exits. Cancellation is cooperative, so a blocked C/FFI call can delay the join; explicit detach is a separate, process-scoped escape. Memory model: happens-before, Send/Sync, crew lifecycle, and channel ownership are specified in MEMORY_MODEL.md. The full SAFE/RT program is in SOUNDNESS.md. Crew blocks A crew spawns jobs with kick and collects results with join: fn compute(n: int) -> int { return n * n } fn main() { crew t { let a = t.kick(compute(7)) let b = t.kick(compute(9)) print_int(a.join()) // 49 print_int(b.join()) // 81 } // Ordinary kicked jobs have been joined here. } Jobs cannot escape their crew. When the block ends, all kicked work has joined. Scheduler pool (opt-in) By default each kick creates one OS thread. For high fan-out, enable a fixed worker pool (RT-002): sched_set_workers(4) // reuse 4 workers for kicks crew t { let a = t.kick(compute(1)) let b = t.kick(compute(2)) print_int(a.join() + b.join()) } sched_set_workers(0) // back to one pthread per kick Blocking I/O/FFI should use a dedicated thread path (mako_spawn_blocking in the runtime) so pool workers are not stalled (RT-003). Child errors When a kicked function returns Result[T, string] and you join it, any Err is also recorded on the crew: crew t { let j = t.kick(maybe_fail()) let _ = j.join() match t.wait() { Ok(_) => { /* no child errors */ }, Err(msg) => print(msg), // first Err message } // t.err_count() / t.first_err() also available after joins } Detach (process-scoped) detach f() runs outside the enclosing crew join (still tracked). Always detached_join_all() before process exit (or in tests) so work is not leaked: detach background_work() // … detached_join_all() Channels Communicate between jobs using typed channels. Element types: int family, bool, float, string, named structs, named enums, and tuples (chan_open[Point](n) / make(chan[Point], n) / make(chan[(int, string)], n)). fn producer(ch: chan[int], count: int) -> int { for i in range count { let _ = ch.send(i + 1) } ch.close() return count } fn consumer(ch: chan[int]) -> int { let mut sum = 0 for v in range ch { sum = sum + v } return sum } fn main() { let ch = chan_new(4) // buffered channel, capacity 4 crew t { let p = t.kick(producer(ch, 5)) let c = t.kick(consumer(ch)) let _ = p.join() print_int(c.join()) // 15 } } Struct results (no int bit-packing) Prefer a POD struct on a channel when a worker returns several fields: struct Done { err: int status: int bytes: int } fn worker(out: chan[Done]) -> int { let _ = out.send(Done { err: 0, status: 200, bytes: 42 }) return 0 } fn main() { let ch = chan_open[Done](4) crew t { let j = t.kick(worker(ch)) let d = ch.recv() let _ = j.join() print_int(d.status) } } Deep-POD structs (scalar/string fields only) may also cross kick as args. Maps, arrays, and non-POD structs cannot — use channels. Details: SPEED.md · ERGONOMICS.md. Channel operations: Operation Meaning chan_new(cap) / chan_open[T](cap) / make(chan[T], cap) Create buffered channel ch.send(val) Send a value (blocks if full) ch.recv() Receive a value (blocks if empty) ch.close() Signal no more sends chan_len(ch) Current buffered depth — any chan[T] chan_cap(ch) Capacity — any chan[T] (immutable after create) for v in range ch Receive until closed Select Wait on multiple channels, with timeout and default arms: fn main() { let a = chan_new(2) let b = chan_new(2) crew t { let _ = t.kick(sender(a, 11)) let _ = t.kick(sender(b, 22)) select timeout 500 { a => { print("got from a") print_int(chan_select_value()) } b => { print("got from b") print_int(chan_select_value()) } default => { print("nothing ready") } } } } fn sender(ch: chan[int], val: int) -> int { sleep_ms(30) let _ = ch.send(val) return 0 } The timeout value is in milliseconds. Use default for a non-blocking poll. Up to 16 channel arms are supported. Fairness is round-robin when multiple channels are ready simultaneously. Helper functions for programmatic select: let which = chan_select2(a, b, 500) // returns 0 or 1 (-1 on timeout) let which = chan_select4(a, b, c, d, 500) // returns 0..3 (-1 on timeout) let val = chan_select_value() // value from whichever fired Fan (parallel map) Apply a function to every element in parallel: fn main() { let xs = [1, 2, 3, 4, 5] let squares = fan ## Memory Management (howto/howto-06-memory) Memory Management Makori has no garbage collector. Active memory/resource safety mechanisms include ownership rules (hold/share) and region-based allocation (arena). This guide explains when to use each strategy; generated C and FFI remain outside the Mako type system. Deeper contracts: ownership categories and SAFE/RT drop/escape rules are in SOUNDNESS.md and MEMORY_MODEL.md. As of 0.3.0, owning slices, maps, strings, and struct Own fields free at scope exit, reassign, break/continue, return transfer, ? early-return, and match Own payloads. Free is once per allocation: live owns move into a new freer; aliases and field/index borrows clone. Alias muts that start as a view of another owner (let mut out = path) only free after they take Own (conditional freer flag — no double-free with the caller). Default bindings Regular let bindings are the simplest form. They work like stack values: let x = 42 // immutable let mut y = 10 // mutable y = y + 1 let mut s = make([]int, 0, 8) s = append(s, 1) // s freed at end of scope let v: string_view = "route" // zero-copy view — never free let owned = f"id={1}" // owning string — free at scope exit let w = str_as_view(owned) For most local computation, this is all you need. Prefer string_view for read-only hot paths; use make([]T, 0, n) when you will grow. Match and free Matching on Result / Option Own payloads takes ownership of the payload for the arm. The arm frees it unless you move it into a larger expression result: fn load() -> Result[string, string] { return Ok("payload") } fn use_match() { match load() { Ok(s) => { // s freed at end of arm assert(str_len(s) > 0) }, Err(e) => { // e freed at end of arm assert(str_len(e) > 0) }, } // Move into a let — only the let frees let s = match load() { Ok(x) => x, Err(e) => e, } } Explicit discard let _ = value and _ = value destroy the resolved payload of a fresh Option or Result. Common string, slice, map, struct, and nested-bag shapes are supported. Bags borrowed from fields or indexes are left untouched so the containing value remains valid. A debug compiler warns when it cannot resolve the payload type and therefore cannot complete cleanup. let _ = load() Alias mut reassign fn branch(a: string, path: string) -> string { let mut out = path // alias of path until reassigned if str_eq(a, "f") { out = "custom" // out becomes freer of its Own buffer } return out // free only if out took Own (not the raw param) } hold -- unique ownership hold marks a binding as move-semantics. Once moved, the original is gone: hold let x = 7 hold let y = x // x is moved into y print_int(y) // 7 // print_int(x) // COMPILE ERROR: use of moved value `x` Moving into a function call also consumes the binding: fn consume(n: int) -> int { return n * 2 } hold let val = 42 print_int(consume(val)) // print_int(val) // COMPILE ERROR: moved into consume Mutable hold hold let mut x = 7 x = 9 // allowed -- still owned print_int(x) // 9 Partial moves on structs Move individual fields while keeping the rest usable: struct Point { x: int y: int } hold let p = Point { x: 1, y: 2 } let px = p.x // moves only x print_int(p.y) // y still usable // print_int(p.x) // COMPILE ERROR: x already moved Copy types Integer and bool types are Copy -- they can be re-read after a hold binding without consuming: hold let n = 42 let a = n let b = n // fine -- int is Copy print_int(a + b) // 84 share -- shared read access share creates a read-only shared reference. While a share exists, the original cannot be mutated: hold let a = 1 share let s = share_int(a) print_int(share_get(s)) // 1 // a = 5 // COMPILE ERROR: cannot mutate while shared share_drop(s) // Now a is free again (if mut) Rules enforced at compile time: share let is always immutable (no share let mut) Cannot assign to the shared source while a share is live Cannot create two shares of the same source simultaneously Share ends at share_drop, block exit, or last use (NLL) When to use hold vs share Situation Use Value has one owner, passed linearly hold Multiple readers, no mutation needed share Short-lived local computation plain let Large allocation, bounded lifetime arena Prefer hold (unique ownership) whenever possible. It adds no reference-counting traffic and gives the compiler maximum freedom to optimize. Arenas -- region-based allocation An arena allocates many objects cheaply and frees them all at once when the scope exits: fn main() { arena a { let msg = arena_text(a, "hello arena") print(msg) let xs = arena_ints(a ## Compiling to WebAssembly (WASI) (howto/howto-07-wasi) Compiling to WebAssembly (WASI) Mako can compile programs to WebAssembly using WASI preview1. This lets you run Makori programs in sandboxed environments, edge runtimes, and browsers. Prerequisites Install wasi-sdk and wasmtime: # wasi-sdk (provides the WASI clang toolchain) # Download from https://github.com/WebAssembly/wasi-sdk/releases # Set the environment variable: export WASI_SDK_PATH=/path/to/wasi-sdk # wasmtime (WebAssembly runtime) curl https://wasmtime.dev/install.sh -sSf | bash Hello World in WASM Write a simple program: // wasi_hello.mko fn main() { print("hello from mako wasm") } Build and run: mako build wasi_hello.mko --target wasm32-wasi -o hello.wasm wasmtime hello.wasm # hello from mako wasm The --target wasm32-wasi flag selects the WASI preview1 backend. Mako normalizes this to wasm32-wasip1 internally. Command-line arguments WASI programs can receive arguments from the host: // wasi_args.mko fn main() { print_int(argc()) for i in range argc() { print(arg_get(i)) } } mako build wasi_args.mko --target wasm32-wasi -o args.wasm wasmtime args.wasm -- hello world # 3 # args.wasm # hello # world Environment variables Access host environment variables (passed explicitly to wasmtime): // wasi_env.mko fn main() { let greeting = env_get("MAKO_GREET") if str_eq(greeting, "") { print("no greeting set") } else { print(greeting) } } mako build wasi_env.mko --target wasm32-wasi -o env.wasm wasmtime --env MAKO_GREET=hi env.wasm # hi Note: env_set is a no-op on WASI (the sandbox does not allow modifying the environment). File system access WASI sandboxes file access. You must grant directory preopens: // wasi_fs.mko fn main() { let _ = write_file("output.txt", "written from wasm") let content = read_file("output.txt") print(content) } mkdir -p sandbox mako build wasi_fs.mko --target wasm32-wasi -o fs.wasm wasmtime --dir=sandbox::. fs.wasm # written from wasm cat sandbox/output.txt # written from wasm The --dir=sandbox::. flag maps the host directory sandbox/ to the guest path . (current directory inside the WASM module). What works on WASI Feature Status print / print_int Works argc / arg_get / args Works env_get Works read_file / write_file Works (with preopens) file_exists Works (with preopens) Arithmetic, control flow, structs Works Result types, match, enums Works What stays native-only These features require OS capabilities not available in WASI preview1: Feature Reason Networking (TCP, HTTP) No socket support in preview1 TLS / HTTPS Requires OpenSSL SQLite / Postgres / Redis Requires native libraries crew / channels No thread support in preview1 arena (advanced) Limited memory model Browser deployment Generate a browser-ready static site with the WASI loader: mako deploy wasm dist/ --entry wasi_hello.mko --wasm hello.wasm This creates: dist/ index.html # Loads and runs the WASM module mako-wasi-loader.js # WASI preview1 polyfill build-wasm.sh # Rebuild script README.md # Usage instructions Build and serve: cd dist ./build-wasm.sh python3 -m http.server 8080 # Open http://localhost:8080 in a browser Verifying your setup Run the verification script to check that wasi-sdk and wasmtime are configured: ./scripts/wasi-verify.sh If dependencies are missing, it prints skip: and exits cleanly (useful in CI). Complete example // wasi_demo.mko fn fib(n: int) -> int { if n <= 1 { return n } return fib(n - 1) + fib(n - 2) } fn main() { print("WASI Fibonacci demo") let n = 10 print_int(fib(n)) let name = env_get("USER") if not str_eq(name, "") { print("hello, " + name) } } mako build wasi_demo.mko --target wasm32-wasi -o demo.wasm wasmtime --env USER=mako demo.wasm # WASI Fibonacci demo # 55 # hello, mako Next steps Testing Release builds (native optimized binaries) WASM.md for full technical details ## Testing (howto/howto-08-testing) Testing Makori has a built-in test framework. Tests are functions named TestXxx in files ending with _test.mko. No external test library needed. Writing your first test Create the code to test in math.mko: // math.mko fn add(a: int, b: int) -> int { return a + b } fn mul(a: int, b: int) -> int { return a * b } Create tests in math_test.mko (same directory): // math_test.mko fn TestAdd() { assert_eq(add(2, 3), 5) assert_eq(add(-1, 1), 0) assert_eq(add(0, 0), 0) } fn TestMul() { assert_eq(mul(3, 4), 12) assert_eq(mul(0, 5), 0) } Run them: mako test . # PASS: TestAdd # PASS: TestMul # 2 passed, 0 failed Test assertions Helper Purpose assert(cond) Fails if condition is false assert_eq(got, want) Fails if integers differ assert_eq_str(got, want) Fails if strings differ fail("message") Unconditionally fail with message A failed assertion fails the current test and continues to the next test function. The exit code is non-zero if any test failed. Running tests # Run all tests in a directory mako test examples/testing # Run a specific test file mako test math_test.mko # Verbose output (shows which tests are running) mako test . -v Filtering tests Use --run (or -r) to select which tests execute: # Substring match mako test . -r TestAdd # Glob pattern mako test . -r 'Test*Mul' # Regex (wrapped in /.../) mako test . -r '/^TestAdd$/' mako test . -r '/Add|Mul/' Table-driven tests Test multiple cases with parallel data arrays: fn TestAddTable() { let inputs_a = [1, 2, 10, -5] let inputs_b = [1, 3, 5, 5] let expected = [2, 5, 15, 0] for i in range 4 { assert_eq(add(inputs_a[i], inputs_b[i]), expected[i]) } } Subtests Use t_run to name sections within a test: fn TestParser() { t_run("valid input") assert_eq(parse_port("8080"), Ok(8080)) t_run("negative") assert(error_is(parse_port("-1"), "out of range")) t_run("not a number") assert(error_is(parse_port("abc"), "not a number")) } Output: TestParser/valid input PASS TestParser/negative PASS TestParser/not a number PASS Nested subtests with t_run_nested: fn TestNested() { t_run("outer") assert_eq(1, 1) t_run_nested("inner") assert_eq(2, 2) } // Prints: TestNested/outer/inner Repeating tests Run tests multiple times to catch flaky behavior: mako test . --count 5 Coverage Measure which code paths your tests exercise: mako test . --coverage This reports line coverage percentages per file. Test categories Beyond TestXxx, Mako recognizes additional category prefixes that run in the same harness: Prefix Purpose TestXxx Standard unit test FuzzXxx Fuzz / randomized test PropertyXxx Property-based test SnapshotXxx Snapshot comparison test MockXxx Test with mocked dependencies FixtureXxx Test using fixture data All are zero-argument functions discovered and run by makori test. Testing with environment flags For tests that need external services (databases, network): fn TestLiveRedis() { let host = env_get("REDIS_HOST") if str_eq(host, "") { return // skip when not configured } let r = redis_ping(host, 6379) assert_eq_str(r, "PONG") } Run with the flag set: REDIS_HOST=127.0.0.1 mako test . -r TestLiveRedis Complete test file example // server_test.mko fn TestHealthEndpoint() { t_run("returns 200") let resp = health_response() assert_eq_str(resp, "{\"ok\":true}\n") } fn TestParsePort() { t_run("valid") match parse_port("8080") { Ok(p) => assert_eq(p, 8080), Err(_) => fail("expected Ok"), } t_run("out of range") match parse_port("99999") { Ok(_) => fail("expected Err"), Err(e) => assert(error_is(e, "out of range")), } t_run("not numeric") match parse_port("abc") { Ok(_) => fail("expected Err"), Err(e) => assert(error_is(e, "not a number")), } } fn TestAddTable() { let a = [1, 2, 10] let b = [1, 3, 5] let want = [2, 5, 15] for i in range 3 { assert_eq(add(a[i], b[i]), want[i]) } } mako test . -v # run: TestHealthEndpoint, TestParsePort, TestAddTable # PASS: TestHealthEndpoint # PASS: TestParsePort # PASS: TestAddTable # 3 passed, 0 failed Std testing packs testing/quick runs seeded property checks. Predicates return int 1/0 (native cannot lower fn(...) -> bool callbacks). testing/fstest is an in-memory file map — keep the value write returns. testing/slogtest checks level/message records. pull "testing/quick" pull "testing/fstest" fn commutes(a: int, b: int) -> int { if a + b == b + a { return 1 } return 0 } fn TestQuickAndMapFS() { assert_e ## Release Builds (howto/howto-09-release-builds) Release Builds Debug builds are the default during development. For deployment, use release mode to produce fast, small binaries. Debug vs Release Profile Compiler flags Behavior Debug (default) -O0 -g Full debug symbols, bounds checks enabled Release -O3 -flto -DNDEBUG Maximum optimization; safe indexing checks retained Building for release mako build --release main.mko -o server The binary is optimized with link-time optimization (LTO) across all compilation units. Stripping symbols Remove debug symbols for smaller binaries: MAKO_STRIP=1 mako build --release main.mko -o server Parallel compilation Speed up builds by compiling object files in parallel: mako build --release -j 8 main.mko -o server Or set it globally: export MAKO_JOBS=8 mako build --release main.mko -o server Timing the build See where time is spent: mako build --release --time main.mko -o server Incremental builds Mako caches compiled object files under .mako/cache/. Unchanged packages reuse their cached .o files. This is on by default. To force a clean build: mako build --release --no-incremental main.mko -o server Link-time optimization (LTO) Release builds pass -O3 -flto by default (native clang/gcc path). This is the product speed path. Disable LTO when link time matters more than peak speed (or a toolchain is flaky): MAKO_NO_LTO=1 mako build --release main.mko -o server The incremental cache fingerprints the release optimization mode and C compiler identity, so switching between default LTO and MAKO_NO_LTO=1 cannot reuse objects from the other mode. MAKO_CFLAGS and PGO builds bypass incremental reuse because external headers and profile contents are not fully represented by Makori source fingerprints. Profile-guided optimization (PGO) Two-pass PGO with the system C compiler (years-up servers: train on real traffic shapes — see LONG_RUNNING.md): # Recipe script (instrument → train → llvm-profdata merge → rebuild): ./scripts/pgo-build.sh main.mko -o server -- /* train args */ # Manual: # 1) Instrument MAKO_PGO_GEN=1 mako build --release main.mko -o server # 2) Train on representative load LLVM_PROFILE_FILE=default-%p.profraw ./server … # 3) Merge (clang) and rebuild llvm-profdata merge -o default.profdata default-*.profraw MAKO_PGO_USE=default.profdata mako build --release main.mko -o server Production allocators (optional) For multi-month processes, a purpose-built allocator can reduce fragmentation vs the system malloc (measure with scripts/long-run-soak.sh / scripts/http-long-run-soak.sh): MAKO_ALLOCATOR=mimalloc MAKO_LDFLAGS="-L$(brew --prefix mimalloc 2>/dev/null)/lib" \ makori build --release main.mko -o server MAKO_ALLOCATOR=jemalloc mako build --release main.mko -o server MAKO_ALLOCATOR=/path/to/libmimalloc.a mako build --release main.mko -o server Extra flags MAKO_CFLAGS="-march=native" mako build --release main.mko -o server MAKO_LDFLAGS="-L/opt/lib -lfoo" mako build --release main.mko -o server Static linking On a target with a static-capable toolchain, produce a fully static binary with no dynamic loader dependency: mako build --release --static-link main.mko -o server This is the default for Linux musl targets. On other platforms, use --static-link explicitly when supported. The repository CI contract currently verifies x86-64 and ARM64 Linux musl artifacts. Verify a produced artifact before shipping it: scripts/verify-target-artifact.sh \ x86_64-unknown-linux-musl ./server --static Windows GNU is also cross-compiled and checked as a PE32+ x86-64 artifact, but it is not claimed to be statically linked by Makori's default policy. To force dynamic linking: mako build --release --no-static-link main.mko -o server Cross-compilation Build for a different target triple: # Linux (static musl) mako build --release --target x86_64-unknown-linux-musl main.mko -o server # WebAssembly mako build --target wasm32-wasip1 main.mko -o app.wasm The target triple follows the pattern: arch-vendor-os-env. Docker deployment Generate a multi-stage Dockerfile for containerized deployment: mako deploy docker . --entry main.mko --bin server --port 8080 This creates: Dockerfile -- multi-stage build (compile in builder, copy to scratch) .dockerignore -- excludes build artifacts Default mode builds a static x86_64-unknown-linux-musl binary and copies it into a scratch container (minimal image size). For applications that need CA certificates or shell access: mako deploy docker . --entry main.mko --bin server --port 8080 --mode debian This uses debian:bookworm-slim as the runtime image. Serverless deployment Generate provider-specific deployment manifests: # Google Cloud Run mako deploy serverless . --provider cloud-run --name my-api # Fly.io mako deploy serverless . --provider fly --name my-api These build on the Docker scaffold and add the appropriate service configuration files. Performance practices For the fastest runtime performance: Pre-size slices and maps: let mut s = make( ## Collections: maps, slices, and bag values (howto/howto-10-collections) Collections: maps, slices, and bag values Everyday data structures in Makori use one monomorphized surface — no special collection package, no iterator types, no hand-rolled hashes for common keys. This guide covers: Slices []T and nested [][]T Maps map[K]V across the full key/value grid Sets, groups, nested maps Bag values map[K]Option[T] / map[K]Result[T,E] (incl. nested bags) Channel values, bag-field tuples, nested bag slices Wrapping maps in Option / Result Bulk helpers (maps_*) Compile cost: demand-driven monomorphs (only used map shapes) Identity and low-ceremony patterns: ERGONOMICS.md. Current syntax: GUIDE.md §4b–4c · book tour: ch03. Compile cost (demand-driven monomorphs) The language supports a large map/slice/bag surface, but codegen only emits C helpers for map[K]V shapes that appear in the compilation unit (AST walk). Large programs with many structs no longer pay N² unused map[StructA]StructB / bag monomorphs. Principle Practice Use what you need make(map[A]B) emits helpers for that pair only Annotate API maps Helps collection and call sites stay clear Prefer shallow nests Depth ≤3 nested maps; deep bag nests only where useful Measure big packs makori build --emit-c path.mko then check .c size This is what keeps multi-hundred-type packs (e.g. large libraries) compile-time friendly while still offering rich bag and channel map values. Slices fn main() { let mut xs = [1, 2, 3] xs = append(xs, 4) print(len(xs)) // 4 print(xs[0]) // 1 let mid = xs[1:3] // [2, 3] let tail = xs[2:] let head = xs[:2] // Pre-size when you know capacity let mut buf = make([]int, 0, 64) buf = append(buf, 10) // Nested slices let grid: [][]int = [[1, 2], [3, 4]] print(grid[0][1]) // 2 // Bool / string / float / struct / enum elements all work let flags: []bool = [true, false] let names: []string = ["a", "b"] // Option / Result elements (bag slices) let mut maybe = make([]Option[int], 0, 4) maybe = append(maybe, Some(1)) maybe = append(maybe, None) match maybe[0] { Some(v) => print(v), None => print("none"), } let xs: []Option[int] = [Some(10), None] let mut tried = make([]Result[string, string], 0, 2) tried = append(tried, Ok("yes")) tried = append(tried, Err("no")) } Op Notes len / cap length and capacity s[i] / s[i] = v bounds-checked (unless unsafe) append(s, v) may reallocate; reassign result s[low:high] sub-slice make([]T, len[, cap]) allocate ([]Option[T] / []Result[T,E] supported) Maps — keys and values Keys: int · string · float · bool · named struct · named enum (including pack-qualified types after pull). Values: the same set, plus: Value shape Example Scalar / struct / enum map[string]int, map[int]Point Set-style map[string]bool Slice map[string][]int, map[Point][]string Nested slice map[string][][]int Nested map (depth 2) map[string]map[string]int Nested map (depth 3) map[string]map[string]map[string]int Nested map + slices map[string]map[string][]int Slice of maps []map[string]int Map of slice-of-maps map[string][]map[string]int Option bag map[string]Option[int] Result bag map[int]Result[string, string] Slice of bags map[string][]Option[int], map[int][]Result[string,string] Bag of slices map[string]Option[[]int], map[int]Result[[]int,string] Tuple values map[string](int, int), map[string](Point, int), map[K](int,int,int,int) Bag of maps map[string]Option[map[string]int], map[int]Result[map[string]int,string] Channel values map[string]chan[int], map[Point]chan[string], map[string]chan[Point] Slice of channels map[string][]chan[int], map[Point][]chan[string] Optional channel map[string]Option[chan[int]], Option[chan[int]] Result channel map[int]Result[chan[string],string] Slice of optional channels map[string][]Option[chan[int]] Optional channel slice map[string]Option[[]chan[int]] Nested channel slices map[string][][]chan[int] Channel + scalar tuple map[string](chan[int], int), map[int](int, chan[string]) Channel 3-tuple map[string](chan[int], int, int), (int, chan[T], int) Nested optional map[string]Option[Option[int]], Option[Option[chan[int]]] Triple optional map[string]Option[Option[Option[int]]] Result of optional channel map[int]Result[Option[chan[string]],string] Option of Result map[string]Option[Result[int,string]], Option[Result[chan[int],string]] Result of nested optional map[string]Result[Option[Option[int]],string] Nested Result map[string]Result[Result[int,string],string] Slice of nested bags map[string][]Option[Option[int]], []Option[Result[int,string]] Optional bag slice map[string]Option[[]Option[int]], Result[[]Result[int,string],string] Bag-field tuples map[string](Option[int], int), (Result[string,string], int), (Option[chan[int]], int) struct Point { x: int, y: ## How-To Guides (howto/howto-README) How-To Guides Practical, hands-on tutorials for building with Makori. Each guide includes working code you can run immediately. Guides # Guide What you will build / learn 01 Getting Started Install Mako, create a project, build and run your first program 02 HTTP APIs Build a JSON API server with routing, request parsing, and a client 03 Errors and Debugging Handle errors with Result and ?, wrap context, debug with dbg and lldb 04 Packages Create reusable packages, manage dependencies, set up workspaces 05 Concurrency Use crew blocks, channels, select, fan, and actors for parallel work 06 Memory Ownership (hold/share), auto-free of slices/maps/strings, string_view, arenas 07 WASI Compile to WebAssembly, run with wasmtime, pass args and access files 08 Testing Write tests, run them, filter by name, measure coverage, use subtests 09 Release Builds Optimize binaries, cross-compile, static link, package for deployment 10 Collections Maps, slices, nested maps, bags/channels/tuples, demand-driven monomorphs, maps_* Prerequisites All guides assume you have Mako installed (makori version → mako0.6.2 …). Guide 01 covers installation from scratch. Related documentation The Makori Book — guided language tour GUIDE.md — syntax reference (Mako-native; §6 generics, §9 channels) LANGUAGE.md — language overview + 0.2.2 generics table ERGONOMICS.md — low-ceremony maps/slices/channels IDENTITY.md — our syntax identity + % COMPAT.md — dual forms / compatibility STDLIB.md — standard library surface BUILTINS.md — current documented builtin table STATUS.md / ROADMAP.md — verified matrix / next releases BUILD.md — incremental build system DEBUG.md — debugger integration PERFORMANCE.md · SPEED.md — measure & hot path ## Makori standard library (stdlib/stdlib) Makori standard library Makori is its own language with its own syntax and ownership model. Standard library parity means safe capability coverage, not Go/Rust syntax cloning and not importing their unsafe surfaces. Batteries for web and backends, with naming conventions adapted to Makori. Product tip: 0.6.5. Application packs have Go-equivalent surfaces (2026-08-18 wave) — snake_case, no panic-on-OOB, Result / (value, err) instead of nil. Not a syntax clone and not every Go toolchain package. Lower-level hot path remains builtins over C runtime headers. Memory-safety bar: safe stdlib APIs must be memory safe by construction. C/OS/crypto/compression-backed code is allowed only behind checked wrappers with documented ownership, cleanup, bounds, and handle lifecycle rules. Raw-memory or unverifiable behavior is excluded from safe parity or isolated behind an explicit unsafe boundary. See STDLIB_SAFETY.md. Package-level classification is tracked in STDLIB_SAFETY_MATRIX.md. Default-safe means safe plus audited checked-native packages with package-local evidence and passing hard gates. unsafe-boundary packages (os/exec, plugin, runtime, syscall) and external/environmental behavior are excluded from that claim unless a future release hardens and reclassifies them. Call builtins directly (str_split, path_join, …) or import std packages: import "strings" import "path" import "sync" let s = strings.concat(strings.split("a,b", ","), "-") let p = path.clean("/a/../b") let m = sync.rwmutex() Bare names like import "strings" resolve under std/ (override with MAKO_STD) and auto-alias so strings.split works. Relative import "./x.mko" unchanged. Note: method names that are keywords (join, match, …) use aliases (concat, matches, join_path). Performance bar: fast and lean on the same hardware — no mandatory GC, arena-per-request, few copies, structured concurrency. Book (stdlib chapter): book/src/ch07-stdlib.md · Working APIs with syntax: GUIDE.md · How-tos: howto/ · North star: VISION.md · Honest matrix: STATUS.md · Queue: ROADMAP.md. Runtime: runtime/mako_rt.h, runtime/mako_stdlib.h, runtime/mako_std.h, runtime/mako_http.h, runtime/mako_db.h, runtime/mako_security.h. Tests: examples/testing/stdlib_*, stdlib_parity_*_test.mko, plus area tests (base64_test, regex_*, errors_test, path_join_test, …). Demo: examples/stdlib/demo.mko. The claims gate also runs scripts/stdlib-gate.sh, which type-checks every checked-in std/**/*.mko package file so a stale wrapper cannot remain hidden because no application imports it. This proves package-surface validity, not symbol-for-symbol parity with Go or any optional platform integration. A package is not complete for safe parity until it also satisfies the stdlib memory-safety gate. Package index (synced 2026-08-18 · Go-equivalent + wave 3) Mako names are snake_case and keyword-safe (concat not join, matches not match). Indexes never panic: searches return −1, slices clamp. Parse failures are Result, never nil pointers. Package Status Role strings / bytes Done search/cut/split_n/fields_fn + []byte index/compare/clone strconv / fmt / print Done parse/format + quote/unquote/is_print io / io/fs / path / filepath Done Limit/Section readers, walk, glob matches, rel/abs bufio Done buffered reader/writer + scan_lines os / os/env / os/user / os/exec / os/signal Done env expand/lookup, uid/home, exec, signal Unix flag Done CLI flags net / net/netip / http / cookiejar / httputil / httptrace / net/url / net/mail / net/smtp Done host/port, IPv4/IPv6/prefix, HTTP, MIME/SMTP encoding/* + ascii85 / pem / gob / binary / yaml / toml / cbor / msgpack / avro / protobuf Done wire + config + binary codecs compress/gzip · flate · zlib · lzw · bzip2 · archive/tar · archive/zip Done C hot path; bzip2 optional mime / multipart / quotedprintable · context · crypto Done context values are string pairs (with_value / value) math / math/bits / math/cmplx / math/big / rand Done bits, complex pairs, big.Int add/mul, shuffle/perm text/template / html/template / text/tabwriter / text/scanner Done Go-style engine + tab align + token scan html · utf8 · utf16 · unicode · sync / atomic · slices / maps / cmp · iter · unique Done UCD + UTF-16 + compare + intern errors / testing / httptest / quick / fstest / slogtest / regexp / regexp/syntax / log / slog / sql Done RE2-ish + property checks + MapFS hash / hash/crc32 / hash/adler32 / hash/fnv Done IEEE CRC-32, Adler-32, FNV-1/1a index/suffixarray Done suffix index + lookup image / image/color / draw / png / gif / jpeg Done Point/Rect + LZW dict; DCT + Huffman; JFIF reflect Done POD value bag (N fields + nested POD flatten) + clone/equal; map fields rejected plugin Done product host (std/plugin): load/call/meta/reload/manifest + live dylib syscall Done portable OS primitives (std/syscall): pid/uid/host/pipe/dup/… time Done clocks + calendar + parse/format + Go-sty