Topaz is a small, closed language for application intent. It reads like Python or TypeScript, but it keeps the surface deliberately narrow: one canonical way to say each common thing, written by people and agents, checked by the toolchain.
Rust is still the right tool when you need to negotiate directly with the machine. Topaz lives one layer higher: CLI workflows, data transformation, backend glue, configuration-driven logic, SQL, shell, and path orchestration. It is meant for code where the important thing is not exposing every lever, but writing the intent clearly enough that the toolchain can run it, check it, and compile it to a self-contained native binary.
Every program on this page that shows output is executed against the toolchain by the site verifier. Each output block is pinned byte-for-byte to a captured run, and the remaining fences are parse-checked.
Lena Code interop. Topaz is part of the STUDIO HAZE product family alongside Lena Code. The two are designed to work together: Topaz can serve as both a source and a target language in Lena Code conversion workflows, so code you write in Topaz travels well into Lena Code pipelines and back out again. Topaz is also a small, closed, Unicode-first language written the same way by people and AI agents, with supported programs checked through run/build differential gates.
First proof: Unicode-first
Identifiers are Unicode from the lexer up. Domain words stay in your language instead of becoming romanized approximations:
function greet(name: string, language: string) -> string {
return match language {
case "한국어" => "안녕하세요, {name}님!"
case "Русский" => "Привет, {name}!"
case _ => "Hello, {name}!"
}
}
let 사용자 = "김토파즈"
print(greet(사용자, "한국어"))
print(greet("Topaz", "Русский"))안녕하세요, 김토파즈님!
Привет, Topaz!사용자 is an ordinary variable. Unicode identity is not a tolerated edge case. Identifiers are exactly the scalar sequences you wrote, with no silent normalization (§1), and the module resolver rejects look-alike module names across files under exact, NFC/NFD, and case-fold collision keys (§17).
Four things to know
A small, closed surface
For each intent there is one way to write it. Recoverable failure is Result, absence is optional, cleanup is defer, and match is exhaustive by design. The language decides these policies so every file does not become its own dialect.
function parsePort(raw: string) -> Result<int, string> {
let n = toInt(raw) ?? -1
if n < 1 {
return Err("not a port: {raw}")
}
return Ok(n)
}
function startup(raw: string) -> Result<string, string> {
defer print("config closed")
let port = parsePort(raw)?
return Ok("listening on {port}")
}
print("{startup("8080")}")
print("{startup("http")}")config closed
Ok(listening on 8080)
config closed
Err(not a port: http)The ? operator propagates the Err, and defer runs on every exit path. That is why config closed appears in both transcripts above.
Agent-ready by constraint
Topaz is designed for generated code, but not by asking agents to be careful. The spec is small, forbidden forms are named, canonical profiles are machine-checkable, and this site verifies its own examples. A language for agents earns trust by narrowing failure modes.
Templates keep intent structured
sql, sh, and path strings are templates. They are structured values whose parts and interpolations stay separate instead of collapsing into a string:
let table = "users"
let q = sql"select * from {table} where active = {true}"
print("{q}")<sql template, 3 part(s), 2 interpolation(s)>That placeholder rendering is the honest state today: the template value exists and nothing was concatenated, while the per-domain rendering policies are not yet specified.
Static, runnable, checked backends
Topaz is statically typed by specification. The shipped checker types a whole compilation unit before execution:
type TrafficLight = "red" | "yellow" | "green"
function next(light: TrafficLight) -> TrafficLight {
return match light {
case "red" => "green"
case "green" => "yellow"
case _ => "red"
}
}The interpreter is the reference: topaz run parses, resolves, type-checks, and computes the answer the toolchain treats as correct. From the same source, topaz emit / topaz build lower a program through two checked backend paths. The Rust backend produces a self-contained native binary. The Python backend writes program.py plus its runtime topaz_py_rt.py for server, data, and operations work.
Neither backend is trusted by intention. Each is checked against the interpreter over a measured surface, and the release proof records where the interpreter, Rust, and Python agree. Type-directed runtime guards carry over to both, so a compiled program keeps the behavior you see in the playground and the interpreter.
topaz build app.tpz --target python --out-dir py-out
The status page tracks the exact gates and the measured-surface proof behind each backend.
When not to use Topaz
Use Rust, C, or Zig instead if you need direct ownership and lifetime control, unsafe boundaries, embedded targets, hand-tuned performance, or full access to a systems ecosystem. Topaz's narrow road is a real cost when you want every lever.
Topaz is for the opposite shape of work: deployable application logic without a systems-level source surface, domain language kept in code, and a small grammar that people and agents can produce consistently.
Start here
- Getting Started: install Topaz and run the first program
- Philosophy: why Topaz treats code as an executable specification
- Syntax: the surface of the language, page by page
- Modules & Visibility: multi-file units
- Toolchain status: what runs today, and what proves it
One way to say it.