Hale, in text
The whole of the documentation and every article, as plain HTML. No script, no webfont, no images, no colours of ours — your browser decides how this looks. Same source as the styled site, so it does not go stale.
Hale is a compiled language. Every piece of state has one owner, and parts talk only over declared topics, so the compiler can check a program's architecture the way it checks its types. There is no garbage collector and no borrow checker.
Install
curl -fsSL https://hale-lang.org/install.sh | shDocumentation
Introduction
- Introduction — Hale is a compiled, general-purpose language. Every piece of state has one owner, and the parts of a program talk only over declared, typed message…
- Claims & the law — The effects chapter taught one function to make a promise. This chapter is the complete reference for the promises no single function can make: claims…
- Constitutions — Every application has a few sentences that make it that application: They are true on the day it is written. Six months of changes later, nothing but memory…
- The organism, part by part — The product is the organism: your Hale application, plus the parts that let it be governed, changed, run and watched. Someone asks for an outcome; the…
- Effects & contracts — Most of what a function does is invisible in its signature. fn price(book: OrderBook, qty: Int) -> Decimal tells you the types and nothing else — whether it…
- The habitat, as designed — This chapter is a design, not a description of the tree. It collects the direction settled in two design reviews:
- Libraries (pond) — The standard library covers the substrate — I/O, time, strings, JSON, HTTP, crypto, the bus. Everything else — web stacks, databases, observability — lives…
- Reference — This guide is the tour. The canonical contract — what the compiler actually enforces — lives in the spec/ directory at the repository root. When the guide…
- The design — Why one shape held across all six parts. This guide descended through six parts — a small everyday language, a concurrent-services language, a language of…
- The model — Most compilers have an IR that describes how the program runs — blocks, instructions, registers. Hale has one of those too. This is about the other one: a…
- Units, end to end — Math, money & time introduced the pieces: a unit, a quantity counted in one, a point over a quantity, an identity, a range. This chapter puts them together…
- Verification — Most languages ask you to write correct concurrent code and hope you did. Hale takes a different bet: make incorrect designs fail to compile, and…
Basics
- Control flow — Choosing, repeating, and matching. if is also an expression — it produces a value, so you can assign with it. In expression position it needs an else, and…
- When a call can fail — Hale's value-level error model — and why you can't ignore it. Some calls can't always succeed. Parsing "banana" as an integer, reading a file that isn't…
- Your first program — Everything from this level, in one small CLI. Let's build a complete little command-line tool using only what the basics covered: variables, math…
- Functions — Naming a piece of work so you can call it. A function is declared with fn, a name, typed parameters, and an optional return type:
- Math, money & time — Arithmetic, and three types that save you from classic bugs. The operators are what you'd expect:
- Strings & text — Building and inspecting text. The + operator concatenates strings, and println / f-strings join for you:
- Values & variables — The vocabulary every Hale program is built from. A variable is introduced with let:
Dna
- DNA, the building block — DNA is what the organism is assembled from: the library in vendor/dna, the dna::Dna locus your organization constructs from it, and the hale dna commands…
- Getting started — This chapter makes an organism, shows what it wrote, fills its vault, starts it on your machine, and walks you through the first Review and the first task.
- The head and the face — The head is the edge API: the one surface people and services reach. It knows who is calling (a session, a bearer, a socket peer), maps them to the…
- The heart and the body — The heart is the application: what the organism exists to keep beating. Its one job is to do its work and say what it did, as events on its own subjects…
- Legs, hands and voice — A leg performs one unit of work for a position: it claims an attempt, wears the attempt's hat, acts with the hands it is given, speaks to models through the…
- Memory and the record — The organism remembers in two places. The record is its long-term memory: every decision, in order, never rewound. It is git, under refs/dna/* in your…
- The nerves — The nerves carry signals between the organism's parts: an ask, a verdict or a leg's outcome the record already holds, and an application's event on its way…
- Reference — The CLI, the environment, the record's vocabulary, the status projection and the files, in one place. The chapters explain; this page lists. spec/dna.md is…
- Schedules — A schedule says when a workflow runs and who convenes it, and nothing else. It points at a definition in the workflow catalog, never at a sentence to ask…
- Senses and reflexes — The senses are the organism's perception: one telemetry store that every long-running part emits readings into. The reflexes are its reactions that need no…
- Shaping and governing it — The genome is what the organism is made of: the application's source, the organization under dna/org (its org chart, its law, its purpose, its catalogs)…
- The skin — The skin is the organism's trust boundary: the vault, the roles and accounts each part holds, the identity provider in front of the head, and the closures…
- The spine — The spine is the one surface every other part calls: a person asks, a leg claims and settles, a head reads, and every answer the spine gives is a row. It is…
- Held together by the compiler — This chapter is a standard, and partly a goal. It says how a DNA project uses the whole toolchain, one way for each concern, so that the compiler can hold a…
- Troubleshooting — Each entry starts with what the organism prints, word for word, with … where a name, a number or a digest goes. Then the cause, then what to do. The entries…
- One task, end to end — This chapter follows one request from the terminal to a change that is kept, or rolled back, with the record's rows beside each step. It then covers the…
Everyday
- CLI & config — Coming from Python / Node? No argparse, no yargs, no dotenv. Reading arguments and environment is a few direct calls under std::env; layering argv over env…
- Lists & maps — Coming from Python / Node? Hale has no built-in list / [] that grows, no dict / {}, no Vec or Map. Instead you declare a small locus and annotate it with a…
- Hashing, encoding & randomness — A grab-bag of the cryptographic and byte-wrangling helpers real programs reach for: digests, message authentication, base64, and random numbers. They live…
- Files — Coming from Python / Node? No try/except, no .catch(), no checking err != nil. Every filesystem call that can fail returns a fallible value, and the…
- HTTP — Coming from Python / Node? This is your Flask / Express moment — but instead of decorators or a routes table, you write a handler locus: a locus with a…
- JSON — Coming from Python / Node? There's no JSON.parse that hands you a dynamic object you index freely. Hale's std::json is field-oriented: you ask a JSON string…
- The locus, gently — Coming from Python / Node? A locus is the closest thing Hale has to a class or a module. It bundles state (fields) with behavior (methods) and you make…
- Logging — Coming from Python / Node? Instead of a global logger object you configure at import time, Hale logging is built on the message bus: a Logger publishes…
- Metrics — Coming from Python / Go? std::metrics is shaped like the Prometheus client libraries you already know: register a counter / gauge / histogram once, mutate…
- Records & data — Coming from Python / Node? Where you'd reach for a dict or an object literal to pass structured data around, Hale uses a named type — a fixed-shape record…
- UDP & TLS — HTTP covers the request/response server. Below it sit two more transports: UDP for connectionless datagrams, and TLS for an encrypted client connection…
- Testing — A test in Hale is just an ordinary program. There's no framework to learn, no annotations, no test classes — a test is a .hl file whose fn main() runs some…
Getting started
- Your first run — Put something on screen. Create a file hello.hl: Run it: hale run compiles your program and runs it in one step — it's the same native code hale build…
- Install — Get the hale toolchain on your path. There are two ways to get hale: download a prebuilt binary (quickest), or build from source (for contributors, or a…
Parts
- The habitat — An organism looks after one application and its record. People rarely work inside just one. The same person answers to a team, a company and a customer…
- The language — This part is Hale as a small, ordinary language: values and variables, numbers that include money and time, functions, control flow, strings, lists and…
- The locus model — In the last part a locus was state plus methods: something you construct and call. This part lets it run over time, and that is where Hale stops looking…
- The organism — An organism is your application together with the parts that let it be governed, changed, run and watched. Its code can change itself, and you hold the…
- Systems control — Everything so far has been about what a program is. This part is about how it runs, and how much of that you choose to see. Nothing here changes the meaning…
- Saying what must hold — By the end of the last part the compiler holds your whole program as one graph: every locus and who owns it, every topic and who reaches it, every call and…
Services
- The API surface — A service that is authoritative over something ends up wanting a surface that tools can plug into: a command line, a dashboard, an MCP host. You could write…
- Build an API — This page builds one program from an empty file to a working API with roles: a surface served on a socket that hale api call drives, a handler that knows…
- The bus — Coming from Go? Topics are like channels, but typed by a declaration instead of by chan T, and many-to-many instead of point-to-point. You don't pass a…
- Concurrency & placement — Coming from Go? Concurrency isn't go f() scattered through the code. Loci run concurrently by default; where each one runs — a shared cooperative pool (like…
- When things fail — Coming from Go? This is the part that's more Erlang than Go. Alongside the value-level fallible channel you already know, a long-running locus has a…
- The lifecycle — Coming from Go? A long-running locus is like a goroutine with structure: instead of go func(){...}() and a context you thread around for cancellation, a…
- Across binaries — Coming from Go? Splitting a program into services usually means rewriting in-process calls as RPC or queue clients. In Hale the publisher and subscriber…
- Parents & children — Coming from Go? This is structured concurrency — closer to an errgroup or a supervised tree than to bare goroutines. A parent locus accepts child loci; the…
- Composition patterns — The shape catalog names the seven building blocks — app locus, namespace locus, service locus, spawned child, @form collection with a domain facade, shape…
- Perspectives — A perspective is a live-rebindable handle to a contract. You program against the contract — a set of method signatures — and reach the real implementation…
Spec
- The API surface — A program exposes an operation by saying so in a row: a surface is a named table of operations (rpcs), each row naming a handler and the roles a caller must…
- Design decisions (the F-series) — An append-only log of Hale's locked design commitments — one record per major decision. Each F.N is a stable navigation tag, referenced from code comments…
- Design rationale — For each major syntactic construct in the Hale grammar, this document records: evidence that constrains the design.)
- DNA — DNA is the part of a Hale application that governs how the application changes. It ships as a library inside the toolchain (vendor/dna, the dna/core seed of…
- spec/ffi.md — Foreign-function interface (`@ffi("c")`) — User-extensible bindings to external C-ABI libraries. Library authors declare extern symbols in .hl source via an @ffi("c") annotation; the compiler emits…
- Forms — A form is a compiler-recognized annotation on a locus declaration that picks an efficient lowering for the locus's storage and synthesizes a standard method…
- Codename legend — The spec and code comments carry a few families of short internal tags from Hale's development history. Most are navigation breadcrumbs, not part of the…
- Memory model — This document specifies Hale's memory model: how regions are allocated, organized, and freed; how locus structure constrains memory layout; how access…
- The canonical semantic model — The typed intermediate representation every structural consumer reads. GH #476 built it; this document is its contract.
- Package management — Hale's v1 package-management surface is small and explicitly git-based. A project declares its direct dependencies in hale.toml; running hale fetch clones…
- Operator precedence and associativity — Operators are listed from highest precedence (binds tightest) to lowest (binds loosest). Operators on the same row have the same precedence; their…
- Projects — A Hale project is a directory tree of .hl source files plus anything those files vendor or reference. This document covers the on-disk shape: how the…
- The graph registry — GENERATED from crates/hale-graph/src/registry.rs and held byte-equal by registry_matches_spec. Do not edit: change the table and run HALE_REGEN_REGISTRY=1…
- Runtime — What every compiled Hale binary always ships with. Always- loaded; not optional; no import needed; the substrate every Hale program depends on.
- Operational semantics — This document specifies what Hale programs do when they run. Where grammar.ebnf says what's syntactically valid and types.md says what's meaningfully valid…
- Standard library — Bundled with the toolchain, no separate install required. This document describes the current stdlib surface. Milestone / phase history lives in…
- Style guide — This document specifies idiomatic Hale in four layers: the shapes a program is composed of, the correctness rules that keep a long-lived program sound, the…
- Testing pipeline — The testing pipeline is part of the language toolchain, not an add-on. hale test ships in the same binary as hale build. Test infrastructure exists from day…
- Lexical structure — This document specifies the lexical layer of Hale: the set of tokens the lexer produces and feeds to the parser. The formal grammar in grammar.ebnf is…
- Type system — This document specifies Hale's type system: what types exist, how they relate, what the compiler verifies. Where the grammar (grammar.ebnf) tells you what's…
- The unit dialect — A program says what its integers count. It declares units and the equations between them, and scalar types counted in them: a quantity (an amount: Money…
- Static verification surface — This page is the canonical catalog of the compile-time checks the toolchain runs beyond ordinary type-checking — the structural and semantic guarantees a…
Systems
- Binding C — Coming from Rust / C++? This is extern "C" with a thin, hand-written wrapper — no bindgen, no build-script codegen. You declare the C symbols you need with…
- Forms under the hood — Coming from Rust / C++? A form is closer to a monomorphized template than to a generic collection object. @form(vec) doesn't wrap a one-size-fits-all…
- Iris: the embedded observer — LOTUS_OBS=1 makes any Hale binary publish an observation segment (see Operations & debugging). Iris is the program that reads it: it attaches to every…
- Memory & lifetime — Coming from Rust / C++? No garbage collector, and no borrow checker either. Memory is region-based: every locus owns an arena, allocations inside it are…
- Modes — Coming from Rust / C++? Think of modes as asking the compiler to emit a different execution strategy for the same computation over the same state…
- Operations & debugging — Most of the time a Hale program either works or fails loudly. The two exceptions — the ones that send you here — are a message that quietly doesn't arrive…
- Performance — Coming from Rust / C++? You're used to controlling allocation and watching it. Hale's arena model makes most code allocation-bounded by construction — a…
- Record & replay — "Reproduce the incident exactly" is worth more to someone running a system than any counter you can print. Hale's substrate is unusually close to being able…
- WebAssembly & the browser — Coming from the web stack? Hale compiles to a self-contained .wasm plus a small .mjs loader — no Emscripten, no bundler. The same locus/bus/std::* program…
- Zero-copy & the high-frequency bus — Coming from Rust / C++? This is the shared-memory ring buffer you'd otherwise build by hand with mmap and atomics. For same-machine routes north of ~100k…
Tutorial
- Build a job queue — In about thirty minutes, you'll build a small job queue and watch it grow in four stages — from a throwaway script to a service split across processes…
Articles
- what the hale!? — 2 September 2026. Why build a new language in 2026. A locus owns state and talks over declared topics, and that one restriction turns out to carry most of what code review was for: the architecture stops living in docs and heads and becomes the only sentence the language accepts — from a value, to a binary, to a fleet.
- Record & Replay — 13 August 2026. Record one concurrent execution, then re-run the same program with the same journaled inputs and the same per-consumer delivery order. How Hale turns its typed bus, effect frontier, and runtime ownership of scheduling into a replayable incident — without asking application code to instrument itself.
- Secrets — 8 August 2026. A signing key the rest of the program cannot reach, using the ownership model that was already there. One annotation closes the gap in it, one built-in effect class marks the privileged operation, and the law is written with the claim forms the language already has.
- Fleets — 6 August 2026. Claims close one application; a fleet plan closes one deployment of many. Topology artifacts compose across binaries, cross-process law gets checked with cross-process witnesses, and signatures carry the certificate to the machine that runs it. What a development lifecycle looks like when every stage from function to fleet is either proven or refused.
- Constitutions — 5 August 2026. Claims stay closed-world, but their source no longer has to be copied into every main locus. Constitutions share one claimset across entrypoints and environments, compose only by addition, and make missing coverage an error.
- Claims — 4 August 2026. Write the system's laws before finishing its implementation, then let the compiler drive the program toward them. Named claims over Hale's call, message, effect, and topology graphs turn isolation, required wiring, single-writer rules, capability boundaries, and quantitative limits into ordinary development feedback.
- Effects — 31 July 2026. A function can declare what it is allowed to reach, and the compiler proves the claim over the entire call graph. Effect classes, quantitative budgets, per-phase contracts, causal tracking in both directions across the bus, and effect classes a program declares for itself.
Elsewhere
- Source, on GitHub
- The styled site, which has a playground and diagrams
- llms.txt