general-purpose · memory-safe · supervised
Build a monolith. Deploy a distributed system.
Hale collapses the linguistic layers between a domain and the machine. One primitive — the locus — with Erlang-style supervision, memory freed by structure (no GC, no borrow checker), and a compiler that enforces the design principles we've always carried as conventions.
locus Greeter {
params { name: String = "world"; }
run() { println(f"hello, {self.name}"); }
}
fn main() { Greeter { name: "hale" }; } main locus App {
params {
ingest: Ingest = Ingest { };
rollup: Rollup = Rollup { };
api: MetricsServer = MetricsServer { port: 9100 };
}
placement {
ingest: pinned(core = 1); // its own OS thread
rollup: cooperative(pool = compute);
api: cooperative(pool = io);
}
bindings {
// dev: delete this block -> one binary, in-process bus.
// prod: keep it -> same code, separate processes.
Samples: unix("/run/samples.sock");
}
} the deployment seam
Change a block, not your code.
Placement and transport are deployment seams, not
properties of your logic. With no bindings, your loci run
as a single in-process binary. Bind a topic to a transport and the
same source runs as separate processes — your code never
changes.
one source → dev monolith → pinned threads → a cross-process fleet
Structure is the lifetime. Failure is supervised. Bad designs don't compile.
pillar 1 — one primitive
Everything is a locus.
An app, a service, a worker, a pipeline stage, a bus subscriber — one
recursive shape. Pure data is a type; anything with flow is
a locus. There is no third thing. Learn it once; it's the
whole language.
locus Counter {
params { n: Int = 0; }
fn inc() { self.n = self.n + 1; }
} fn handle(fd: Int) {
let s = std::io::tcp::Stream { conn_fd: fd };
s.send(b"ok");
// s dissolves at scope exit:
// fd closed, region freed. no GC, no free().
} pillar 2 — memory you can reason about
No GC. No borrow checker.
Every locus owns a region, freed wholesale when it dissolves — deterministically, no tracing pauses, no lifetime annotations. Not “memory is free”: memory is structural and instrumentable, with built-in residency tooling for the rest.
How memory works →pillar 3 — reliable by construction
Let it crash — supervised. And checked first.
Failures flow up to a parent's on_failure (restart /
quarantine / bubble). There are no exceptions; recoverable errors are
addressed inline with or. And the compiler rejects whole
classes of design bugs — bus cycles, cross-thread races — at build time.
fn port(s: String) -> Int fallible(ParseError) {
return std::str::parse_int(s) or raise;
}
locus Pool {
accept(c: Worker) { }
on_failure(c: Worker, err: ClosureViolation) {
restart(c); // let it crash, supervised
}
} locus Cache {
// a method that hands out a managed entity:
fn get(key: String) -> Entry {
return self.lookup(key);
}
} Cache.get may not return a locus value (CQRS).use parent-child + contract, a bus topic, or delegation.
pillar 4 — design you can't drift from
Good design, enforced.
Encapsulation. Actor isolation. CQRS. Aggregates, bounded contexts, dependency direction. The principles we've carried for decades — in books, in review comments — keep describing one underlying shape: a recursive graph of isolated state joined by typed messages. Hale makes that shape the language itself, so breaking a principle isn't a style nit — it's a compile error, like the CQRS violation on the left.
What the compiler checks →tooling
One binary, the whole loop.
hale check answers in ~10 ms with structured,
location-precise diagnostics; the LSP wires it into any editor, and
build, test, fmt, doc, bench, and an MCP server all ship in the same
binary. The compiler is the oracle — it says precisely what's wrong,
whoever the author is.
write a locus
→ hale check (~10 ms)
→ structured diagnostic
→ fix → green
more in the box
The parts that make it cohere.
Closure tests
Runtime structural invariants that audit themselves at each epoch.
Projection classes
Memory strategy tuned to how many children a locus fans out to.
Structural interfaces
Satisfy an interface by shape. No impl, no ceremony.
Transport-agnostic bus
The same publish/subscribe over in-process, unix, udp, or shm.
Verification catalog
The compiler rejects bus cycles, cross-pool races, and CQRS breaks.
One seed, one binary
A directory is a program. Focused executables are cheap.
ecosystem
pond — the “non-std stdlib.”
Vendor what you need. Extensible by tier, from infrastructure to agents.
httpdbpqroutersessionsjobsmetricstracingwebsocketcryptoagent/llm