What Kotoba is
Kotoba is a small Clojure-shaped language profile for compiling capability-checked programs to WebAssembly. It’s aimed at code that should be inspectable, portable, and constrained: AI-generated cells, sandboxed automation, repository policy, and other untrusted programs where the host decides which capabilities are available.
Three things up front, since ‘Clojure-shaped’ invites the obvious pushback:
-
It’s a Clojure-family profile/subset, not a full Clojure or ClojureScript implementation. Canonical source extension is
.kotoba;.clj,.cljc, and.cljsare accepted as compatibility formats. It is not “any JVM Clojure or ClojureScript program runs.” -
Compilation target is WebAssembly, compile-first. The public surface is
kotoba -e/kotoba wasm ...– not an interpreter with a Wasm backend bolted on. -
Capability-confined safety is the point, not an add-on. Capabilities are explicit, scoped, typed values (never ambient strings a module can summon by name); a host-side guard intersects what a module was actually handed against policy before any call runs.
30-second tour
kotoba -e '(+ 1 2)'
kotoba wasm build examples/hello.kotoba -o hello.wasm
kotoba wasm safe-policy examples/policy-demo.kotoba
kotoba wasm safe-build examples/policy-demo.kotoba --policy policy.edn -o policy-demo.wasm
A few design notes
The compiler, CLI, and conformance tooling that process this Clojure-shaped language are themselves written in Clojure/ClojureScript – an earlier Rust implementation was fully retired in favor of this CLJC authority.
Safety is benchmarked against Rust, not copied from it: capability confinement (deny-by-default, typed capabilities, signed audit receipts) is designed to exceed Rust-style memory safety alone, not just match it. Rather than a full ownership/borrow/lifetime system, we shipped a narrow affine check scoped only to capability values – a handle can be consumed at most once per execution path – with a documented limitation instead of a broader, harder-to-verify mechanism.
The rest of the stack
Alongside the language, kotoba-lang/kotobase plays the role Datomic plays for Clojure – same datom/EAVT/Datalog model, but reimagined for the distributed web: content-addressed blake3/CIDv1 blocks instead of a single transactor over SQL/DynamoDB, a Prolly Tree instead of a B-tree, an immutable commit DAG instead of a single log, and a CACAO-authenticated edge runtime instead of a JVM peer with a direct storage connection.
Where to look
-
Language contract: https://github.com/kotoba-lang/kotoba-lang
-
Compiler/runtime (CLJC, Rust-free): https://github.com/kotoba-lang/kotoba
-
Distributed-web Datomic: https://github.com/kotoba-lang/kotobase
Question for this community
We shipped a narrow affine-typing check scoped only to capability values instead of a general ownership/borrow system, on the reasoning that it’s what the actual threat model needs and it’s small enough to verify exhaustively. It has a documented gap (tracked per binding name, not per value) that doesn’t weaken runtime enforcement but is a real limitation. Where do you draw the line between “ship the narrow useful slice, gaps documented” and “go build the complete thing first”?"