Why Rust
Supernova’s predecessor is a Python platform whose failure modes — event-bus socket drops, database bloat, memory spikes, restart churn — are the project’s origin story. The rewrite’s answer was not “Python, but more carefully”; it was to move every guarantee that used to live in convention into something a machine checks: a compiler, a crate graph, a validator. Rust is the language where that move is cheapest.
The ruling
The implementation language was ruled on 2026-06-21:
“it’s okay to have exceptions if there’s a sane boundary but strongly prefer rust” — Matt
A sane boundary means a process boundary — an isolated Python or TypeScript service behind Kafka or HTTP — never in-process mixing. A follow-up directive the same day (“it’s rust now… if you see python change it to rust”) rewrote the Python framings across the specs, while preserving the dated rationale in the decision ledger — including Matt’s blunt “python will always be slow.”
The exception clause has never been exercised. Both candidates that were expected to need it stayed Rust: the agent runtime went custom-built over raw HTTP model APIs with tools lifted from Codex (which is itself Rust — see agents), and workflows went to the official Temporal Rust SDK rather than a Python/TS sidecar. The clause remains a flagged fallback, not a used door.
The viability analysis that backed the ruling put it plainly: the design is ~75–80% language-neutral by substance — every bought substrate (Kafka, Temporal, Postgres, OTel/Prometheus, Vault, git, OS users/groups) is polyglot with mature Rust clients, and the contracts say what, not how. No hard blocker remained.
One binary
All of Supernova compiles into a single static binary: sun. 19 systems (the set is open-ended), 22 crates, one process. The CLI is a thin wrapper over per-system client libraries; inter-system calls are direct in-process library calls, never routed through the CLI. Any system can also be hosted as an HTTP service from the same binary (sun <system> serve). Next to the heavyweight bought substrates — Kafka brokers, a Temporal cluster, Postgres — the platform itself is one small artifact to build, ship, and reason about.
Modularity is enforced structurally by the crate dependency graph, not by convention:
flowchart TD bin["sun binary - composition root"] -->|links| lib["sun-lib - client library aggregator"] lib -->|links| sys["19 system crates: issue, workflow, agent, bus, core, config, ..."] sys -->|depend on| contract["sun-contract - typed contracts, zero implementation"] sys -.- note["few typed cross-system exceptions: agent, link, monitor, ops depend on sun-permission; workflow on sun-review and sun-test; ops on sun-config"]
(The graph is deliberately flat: every system crate depends on sun-contract, not on other systems, apart from a handful of typed cross-system crate edges. The sun-lib crate implements the sun_lib client-library layer described on the shape page.)
The type system carries the contract discipline
At the bottom of that graph sits sun-contract, ratified 2026-06-22: a dependency-free crate holding the typed inter-system interfaces — the “headers” of Supernova, pure definitions, zero implementation. Trait surfaces like PermissionGate, ApprovalEngine, VcsRepo, and BusPublish live there; each system’s interface documentation references these types rather than re-describing them, so per the interfaces design, spec and contract “cannot drift — they are one artifact, not two that need reconciling.”
The crate exists because Rust forbids cyclic crate dependencies — and that prohibition did real design work. The first Rust spec pass surfaced a circular dependency between the core and config systems that the Python-shaped design had never exposed. The fix (a contract trait plus composition-root injection) became the platform’s interfaces layer. The type system performed an architecture review.
This matters because agents write most of the code. cargo check enforces implementation-matches-contract for free: per the interfaces layer design, an agent doing a wire task “literally cannot drift from the interface.” Editing a contract type breaks every dependent at compile time — the typed form of the existing rule that modifying a requirement unchecks it, with the compiler enumerating exactly which wire tasks must be revisited.
The trace-annotation gate
The distinctive discipline: every code-bearing Rust line must sit under an active // @R# annotation span tying it to a file-local requirement in a per-file spec, which in turn covers design requirements. The span semantics, evidence kinds, and coverage joins are owned by the requirements page; the enforcement machinery by the wiki page. What Rust contributes is a codebase where this is actually livable — annotations scope to brace-delimited blocks, and the validator (sun wiki validate) checks coverage mechanically on every run.
The density is the striking number: roughly 37,600 lines of the workspace carry @R annotations — about 12% of all lines are traceability. The gate runs green today in the repository: zero errors, with the remaining findings all non-blocking audit-tier warnings.
The workspace, measured
All figures measured directly against the workspace on 2026-07-04. This is an engineered, in-repo-proven codebase, not a deployed one [built in-repo] — the CLI itself reports production_ready: false on workflow starts, and non-probe production starts fail closed.
| Measure | Value |
|---|---|
| Cargo workspace members | 22 crates |
| Systems | 19, mostly one-system-one-crate |
| Rust source | 582 files, 317,657 lines |
| Test functions | 2,711 across 331 test files |
| Per-file specs | 250 under the wiki spec tree |
| External dependencies | ~362 crates in the lockfile |
| Annotation-bearing lines | ~37,600 (~12% of all lines) |
The ~362-crate dependency closure is deliberately small for a 19-system platform: heavy things (Kafka, Temporal, Grafana, Docker) are owned services, not linked dependencies. The Kafka client is rskafka — pure Rust, no librdkafka C dependency (see the bus); workflows use the official Temporal Rust SDK at 0.4 (see workflows). Even binary size is engineered in the open: the debug-info story lives as a checked-in comment in the workspace manifest (541MB full DWARF, 83MB stripped), escape hatch included; the line-tables-only dev binary it settles on comes in at 224MB today.
What this costs
- Build times and fat dev binaries. One workspace, one binary means
cargo test --workspacewall-clock and 224MB dev binaries are the daily tax, mitigated but not eliminated by the debug-info profile. - A 156K-line CLI crate. The single-binary, thin-wrapper pattern concentrated roughly half the workspace in the
sunbinary crate (much of it integration tests and serve hosts). It is a compile-time and review hot spot. - Agent-written Rust has friction. The annotation rule applies to every edit; in practice files over-annotate even validator-exempt lines. The audit still counts 1,210 uncovered source lines (non-blocking, tracked), plus 340 doc-level and 49 mock-backed done-evidence warnings — honesty debt in numbers.
- Prerelease Temporal authoring SDK. The Rust core engine is the battle-tested one all Temporal SDKs wrap, but the authoring API is Public Preview (May 2026): churn, thinner docs, some glue. An earlier analysis mislabeled this as engine immaturity; the correction is on record in the wiki.
- No official Anthropic Rust SDK. The model transport is hand-rolled over raw HTTP, with the OAuth path a small reimplementation using Codex’s login crate as its spec — and a documented subprocess fallback if that proves too hairy.
- A smaller talent pool. If Supernova is ever a shareable product, Rust narrows who can contribute — a real cost accepted knowingly, hedged only by the never-yet-used sane-boundary clause.
- One superseded design on record: an agent once added a
sun-kernelcrate without asking; it was deleted (2026-06-22, Matt: “you should ask for permission before adding whole systems like that”). The crate DAG is now guarded socially as well as structurally.