Introduction
Sakura Lang is an agent-first, general-purpose programming language in which the signature is the contract.
Pre-alpha
The source-built compiler runs the core language and much of M3 on JavaScript: contracts, typed effects and failures, std handlers, permissions, LSP and MCP. M3 is still in progress; no release or stable compatibility contract exists. See the roadmap for implemented features and remaining gates.
Sakura Lang is the language agents write: code that keeps its promises.
Most new code is now written by AI agents. Reviewing every line of that code does not scale, and the parts that matter most (what a function touches, how it can fail, what it guarantees) are usually invisible in mainstream languages. Sakura Lang is designed so that those parts are always written down, in one place, and checked by the compiler.
The core idea
The signature is the contract. Humans review signatures. The compiler checks that the code keeps its promises.
A Sakura Lang signature states the inputs (with refinements), the output, every effect the function may perform, every way it can fail, and its requires/ensures clauses. The body cannot do anything the signature does not allow.
type Email = String where String.len(it) <= 254 && String.contains(it, "@")
type User = { id: Uuid, email: Email, created: Instant }
error EmailTaken(email: Email)
error Banned
type SignupError = EmailTaken | Banned
effect Users {
fn email_exists(email: Email) -> Bool
fn is_banned(email: Email) -> Bool
fn insert(user: User) -> Unit
}
fn signup(email: Email) -> User ! {Users, Clock, Random, Fail<SignupError>}
ensures result.email == email
{
if Users.is_banned(email) { fail Banned }
if Users.email_exists(email) { fail EmailTaken { email } }
let user = User { id: Random.uuid(), email, created: Clock.now() }
Users.insert(user)
user
}
fn memory_users() -> Handler<Users> {
handler Users {
var users: List<User> = List.empty()
fn email_exists(email) { List.any(users, fn(u) { u.email == email }) }
fn is_banned(email) { false }
fn insert(user) { users = List.push(users, user) }
}
}
test "duplicate email fails" {
with memory_users() {
let _ = signup(Email.from("a@b.co"))
expect_fail(fn() { signup(Email.from("a@b.co")) }, EmailTaken { email: Email.from("a@b.co") })
}
}Reading only the signature of signup, a reviewer learns that it:
- accepts only a string that satisfies the
Emailrefinement, - performs
Users,Clock, andRandom, and nothing else (no network, no file system, no environment), - can fail only with
EmailTakenorBanned, - returns a user whose email is the one passed in. This
ensuresclause is checked at runtime on every return.
The test installs an in-memory handler for Users. Clock and Random need no handler in a test, because tests run under deterministic defaults (Clock.fixed, Random.seeded). No mocking library is involved: these are just different handlers for the same effects.
Six pillars
1. Effects you can see. Every function type carries an effect row after !. Expected failure is the built-in Fail<E> effect over a union of error tags. There are no exceptions and no null. Defects such as overflow or a violated contract are not effects; they terminate the task. See Effects and Handlers.
2. Memory without a borrow checker. Every value has value semantics: no aliasable mutation, no reference cells, no cycles in the safe heap, no lifetimes. The first backend is JavaScript and uses the host GC. The native backend (milestone M5) inserts reference counting at compile time with Perceus-style reuse and has no tracing GC. Speed is a design goal; nothing has been measured. See Memory model.
3. Contracts, always checked. Refinement types (where), requires, and ensures are checked at runtime in every build mode, including --release. The planned sakura test --contracts will generate property tests from them. Later, sakura verify (M4) uses an SMT solver to prove individual obligations and remove only those checks. See Contracts and Testing.
4. Secure by construction. Effects are requirements; handlers are authority. The host supplies root handlers only for the std effects main declares, limited by [permissions] in sakura.toml, and code can only narrow that authority. Untrusted<T> marks outside data, Secret<T> cannot be shown or serialized, and tagged templates such as sql"..." never splice raw text. See Capabilities and security.
5. Built for agents. A grammar that fits on one page, one way to do each thing, typed holes (?name), JSON Lines diagnostics with byte spans and fixes labelled by impact, specs frozen during agent repair, and a compiler MCP server. See For Agents.
6. Batteries included. One sakura binary for new, check, build, run, test, fmt, fix, doc, packages, LSP, and MCP. The v0 standard library covers HTTP client and server, routing, SQL (SQLite first), JSON with derived schemas, CLI parsing, testing, and typed LLM calls with tools and budgets. See Standard library.
Status
- Design: docs/design.md is the authoritative v0 design. Anything it does not specify is not in v0.
- Compiler: a Rust workspace in compiler/. It parses, resolves, type- and effect-checks and executes the core language and implemented M3 features on JavaScript.
- Code on this site follows the v0 design. The repository examples have executable coverage; planned features are labeled and the roadmap records the remaining M3 gates.
The roadmap lists every milestone, M0 to M5.
Where to go next
Why Sakura Lang
The problem with agent-written code and the design principles behind Sakura Lang.
Language Tour
Nine short pages covering the whole language, from bindings to concurrency.
For Agents
llms.txt, the MCP server, JSON diagnostics, and typed holes.
Prior art
What Sakura Lang takes from other languages, and what it rejects.