Code that keeps
its promises.
Sakura Lang is the language agents write. Every signature declares its effects, errors and contracts, and the compiler holds the code to them.
agents GET /llms.txt, or any page + .md
error V3001 src/users.sakura:12:11
function signup performs Http, which its signature does not allow.
- interface_changeadd Http to the signature: needs review
- agentremoves the call instead← keeps the promise
The signature is the contract.
Five lines a person can review. The compiler holds the body to every one of them.
fn withdraw(acct: Account, amount: Cents)Takes.Typed inputs.
Centsis a refinement: anIntthat is never negative.-> AccountReturns.The updated account. Nothing else comes back.
! {Ledger, Fail<Overdrawn | Frozen>}May do.Only
Ledger: no network, files or clock. It fails in exactly two named ways.requires positive: amount > 0Requires.The caller's duty. Breaking it is the caller's defect,
D020.ensures result.balance == acct.balance - amountEnsures.The promise, checked on every return in every build,
D021.{ … }the body: checked against the clauses above, then out of the way
- Reviewed by
- a person, reading five lines
- Held by
sakura check, on every change
Review promises, not diffs.
An agent can rewrite six hundred lines before you finish your coffee. Nobody reviews that well. In Sakura Lang, everything a function is allowed to do lives in its signature, so review shrinks to the lines that change a promise.
agent/billing-retries
5 files +612 −388
- src/billing/retry.sakura+214 −90signatures kept
- src/billing/ledger.sakura+131 −122signatures kept
- src/billing/charge.sakuraReview: promise changed
Removed: pub fn charge(card: Card, amount: Cents) -> Receipt ! {Payments, Fail<ChargeError>}
Added: pub fn charge(card: Card, amount: Cents) -> Receipt ! {Http, Payments, Fail<ChargeError>}
charge now makes HTTP calls. That is a decision for a person, so the diff surfaces it, and nothing else.
- src/billing/webhooks.sakura+156 −104signatures kept
- test/billing_test.sakura+73 −61signatures kept
Effects are requirements. Handlers answer them.
signup says it needs a database, a clock and a way to fail. It never says which. Whoever calls it installs handlers, so a test swaps the database for memory with no mocking library and no change to the code.
with sql_db() { Serve.listen(router, addr) }sql_db()
clauses call Sql.sqlite
Clock.host()
reads the system clock
try/catch
turns it into a 409
signup(email, pw) · the body is the same in both
EffectsHandlersHandlers are tail-resumptive: a clause returns the result once. No resume, no Async.
Authority only narrows.
An effect says what a function needs. The handler around it decides how much it gets. Root handlers come from the host, capped by sakura.toml; every with below can narrow that, and nothing can widen it. There is no ambient authority to import.
hosteverything the machine can do
sakura.toml [permissions]fs.read = ["./data"], net = [], the ceiling
main() ! {Console, Cli, Fs, …}root handlers for these effects only
with Fs.rooted(Dir.subdir(…, "data"))paths resolve inside ./data
word_counts(text) -> Map<String, Int>pure: no row, no authority at all
Fs.read("../.ssh/id_ed25519")FsErroroutside the rooted directory; symlink escapes are rejected toomain declares Http, net = []exit 75refused at startup, not at first usea captured Dir outlives its withV6002capabilities cannot escape the scope that made themLog.event(Level.Info, "{token}", [])V2031Secret<String> is not Show, so it can never be logged
Every claim says how it is known.
Sakura Lang never calls a program verified because it compiled. Each obligation gets exactly one status, and the tools report it.
- 01proved
the type and effect checker, on every build
- every effect has a handler
- every Fail tag is caught or declared
- every match is exhaustive
- no null, no unchecked index
- 02runtime_checked
a check at the boundary; a violation is a defect
- requires ordered: lo <= hi
- where it >= 0 && it <= 100
- Int overflow
- 03tested
sakura test, on the inputs that ran
- property "normalize is idempotent"
- sakura test --contracts
- snapshots
- 04trusted
assumed, and listed in the build manifest
- @external bindings
- @trust("reason")
- host handlers
In v0 every contract is runtime_checked, in every build including --release. From M4, sakura verify can move a single obligation to proved and drop only that check. Contracts
How an agent works with Sakura Lang.
The compiler is the agent's other half. Every answer it gives is data a model can act on, and every change it would make says how far it reaches.
writeagentdrafts the body, leaves
?holeswhere it is unsuresakura check --jsoncompilerdiagnostics and hole records as JSON Lines
apply fixesagentlocal fixes go in; signature changes go to a person
sakura testcompilerdeterministic handlers, fixed seed, shrunk failures
- ↺ until check and test are clean
# Sakura Lang > Sakura Lang is an agent-first programming language. Every signature declares its effects, errors and contracts, and the compiler seals them on every build. Sakura Lang is pre-alpha and nothing is released. The v0 language design is written (docs/design.md in the repository). The compiler builds from source and checks and runs M0 to M2 programs (effects, handlers, typed errors, holes) on JavaScript; the M3 standard library (http, sql, fs, cli, ai, task) is not built yet, so examples that use it do not run. Build it: https://sakura-lang.vercel.app/docs/quickstart - The core language for agents, in one file: https://github.com/icantcodefyi/sakura-lang/blob/master/docs/llms.txt- Every docs page is available as Markdown: append `.md` to its URL (for example https://sakura-lang.vercel.app/docs/tour/effects.md).- All docs in one file: https://sakura-lang.vercel.app/llms-full.txt ## Start- [Introduction](https://sakura-lang.vercel.app/docs): Sakura Lang is an agent-first, general-purpose programming language in which the signature is the contract.Live from this site. Open llms.txt or llms-full.txt.
Diagnostic and hole records are what sakura check --json emits today; the MCP server is planned for M3.
Values, without a borrow checker.
Every value is independent: no aliasing, no lifetimes, no cycles. Native code (M5) counts references at compile time and updates a uniquely owned value in place. The JavaScript backend uses the host GC; the semantics are the same.
One binary for the whole loop.
Checker, runner, formatter and test runner already share one compiler library; packages, LSP and MCP join them in M3, with a standard library for HTTP, SQLite, JSON schemas, CLIs and typed LLM calls.
- sakura check
- types, effects, exhaustiveness, holes
- sakura run
- build to JavaScript and run main
- sakura test
- deterministic handlers, properties, snapshots
- sakura fmt
- one canonical format
- sakura explain
- any code, with a wrong and a fixed program
- sakura prompt
- the language guide for agents
- sakura fix
- fixes gated by impact classplanned
- sakura mcp serve
- the compiler as MCP toolsplanned
For code an agent writes, defaults decide.
Every language below can be written carefully. The question is what holds when nobody is being careful: what the compiler enforces by default.
Side effects in the signature
Sakura Lang: Yes, checkedTypeScript: No, hiddenPython: No, hiddenRust: No, hiddenEffect-TS: Yes, R channelErrors in the signature
Sakura Lang: Yes, Fail<E> error unionsTypeScript: No, untyped throwPython: No, untyped raiseRust: Yes, ResultEffect-TS: Yes, E channelNo null, no exceptions
Sakura Lang: YesTypeScript: Partly, strict nulls, throw remainsPython: No, None, raiseRust: Partly, Option, panics remainEffect-TS: Partly, JS throw remainsMemory without GC pauses or lifetimes
Sakura Lang: Yes, native RC with reuse; JS GCTypeScript: No, tracing GCPython: Partly, RC plus cycle GCRust: Partly, no GC, lifetimesEffect-TS: No, tracing GCContracts and refinement types
Sakura Lang: Yes, always checked at runtimeTypeScript: NoPython: No, runtime librariesRust: Partly, external verifiersEffect-TS: Partly, Schema, at runtimeAuthority you grant, not ambient
Sakura Lang: Yes, handlers grant authorityTypeScript: NoPython: NoRust: NoEffect-TS: Partly, services, not enforcedTaint and secret types
Sakura Lang: Yes, Untrusted, SecretTypeScript: NoPython: NoRust: Partly, newtypes by conventionEffect-TS: Partly, RedactedDiagnostics as data, with fixes
Sakura Lang: Yes, fixes declare impactTypeScript: Partly, tsserver code fixesPython: Partly, varies by toolRust: Yes, JSON, applicable fixesEffect-TS: Partly, via TypeScriptOne way to do each thing
Sakura Lang: Yes, small grammarTypeScript: NoPython: Partly, by conventionRust: NoEffect-TS: No, many styles
enforced by default partly, or by convention or library not providedThe Sakura Lang column states design goals; the M0 to M2 parts run today.
Designed. Running in part.
The compiler checks and runs M0 to M2 programs on JavaScript today. M3 is under way, in the open, and nothing is released yet. Full roadmap
M0Runs today
Hello, effects
Lexer, parser, Console, inference, CPS JavaScript, sakura run and sakura check --json.
M1Runs today
Pure language, typed errors
Records, variants, exhaustive match, Fail with try/catch, std in Sakura Lang, tests, sakura fmt.
M2Runs today
Handlers and holes
User effects and handlers, row variables, deterministic test handlers, typed holes.
M3In progress
Contracts and agents
Runtime contracts, permissions, Secret and Untrusted, Task, Http, Sql, LSP and MCP.
M4
WASM and verify
WASM backend; sakura verify discharges contracts with Z3 and drops proved checks.
M5
Native
Cranelift backend with Perceus reference counting and in-place reuse.
Read the design. Then hold us to it.
The docs are written for people and for the agents that work with them. Every page is one fetch away as Markdown.