Why Sailfin?
In most languages any function can do anything — read files, call APIs, open sockets — and there is no way to know which until you read the implementation. Sailfin makes those capabilities explicit and compiler-checked, so a function's signature tells you what it is able to touch.
As more code is generated rather than written, the useful question shifts from what codedoes to what it can do — and that is a question a compiler can answer.
Effect Types: The Core Idea
Every function in Sailfin declares what it can do. A function that reads files declares![io]. A function that calls an API declares ![net]. A function that does neither declares nothing.
// Missing ![net] — the effect checker rejects this at compile time
fn main() ![io] {
let data = http.get("https://api.example.com").body; // needs ![net]
}Go, Rust, and Zig track side effects by convention and documentation — their type systems have no way to express "this function may touch the network." Sailfin's effect checker makes it a build gate: an undeclared ![io], ![net], or![clock] operation fails the build, and cross-module propagation means a caller inherits its callees' declared effects.
Effect systems are not new. Koka, Flix, and Effekt have deeper ones, and Effekt's are capability-based. What is unusual here is the combination: effect typing in a self-hosted systems language that compiles to native binaries, with each function's effect surface tied to a package manifest the compiler cross-checks.
Two limits worth stating plainly. ![gpu] and ![rand] are enforced at specific standard-library entry points rather than by general call detection, so an extern declaration can still reach past them; ![model] is declarable but not yet enforced. Enforcement is complete on Linux x86_64 and partial on macOS arm64 (#613).
A Verification Layer for AI-Generated Code
Reviewing generated code means establishing two separate things: that the logic is correct, and that the code cannot reach resources it was never meant to touch. The second is mechanical and transitive, which makes it a better job for a compiler than for a reader.
Sailfin puts that second property in the function signature. A generated function that declares ![io] but calls http.get has the mismatch caught by the effect checker at compile time — a build error rather than a production incident.
This narrows what review has to establish. It does not replace review: the effect checker proves a function's declared capability surface, not that its logic is correct, and a function honestly declaring ![io, net] can still do the wrong thing with both. What you get is a machine-checked answer to "what can this touch?", which is the part that is tedious and error-prone to establish by reading.
The compile-check-fix loop is wired for tooling today: sfn check --json emits structured diagnostics with spans and fix-its, and an MCP server exposes them to agents directly.
Use Cases
Capability-Controlled Services
Build backend services where every module's capability surface is visible in the type signature. Code review becomes capability review: a handler declaring only![io] cannot reach the network, and widening it to ![io, net]is a signature change that shows up in the diff rather than a line buried in the body.
Supply-Chain Security
Every capsule (package) declares the capabilities it requires in its manifest, and the compiler cross-checks that declaration against the effects the capsule actually uses (E0403). A workspace can cap what its members are permitted to require at all. Auditing inferred effect surfaces across a full transitive dependency tree is still in progress — see the roadmap.
Systems Programming
Sailfin compiles to native code via LLVM with a self-hosted compiler: single-binary output, no interpreter, and no garbage collector — locals are arena-allocated, with atomic refcounting for values that escape their scope.
Developer Tooling & CLI
Explicit effects, single-binary output, and a small standard library fit CLI tools, build systems, and developer infrastructure — where knowing exactly what a tool is able to touch is worth more than it is in most software.
Security by Design
Sailfin makes security properties visible in function signatures. Effects are explicit and compiler-checked, so code that needs network, file system, or clock access must declare those capabilities up front. Full transitive dependency-tree capability auditing and the runtime syscall seal are on the roadmap.
How It Compares
Sailfin is pre-1.0, and each language below is more mature than it is. The useful comparison is one axis, not a scorecard.
vs. Go
Go has a battle-tested runtime, a large ecosystem, and a scheduler that Sailfin's v0 concurrency does not approach. Both compile to native binaries. What Go's type system cannot express is a function's capability surface — in Go, "does this touch the network?" is a question you answer by reading the code. That is the axis Sailfin adds.
vs. Rust
Rust's borrow checker gives compile-time memory safety without a garbage collector. Sailfin does not match that today. It enforces moves, use-after-move, and aliased mutation on owned buffers as a correctness floor, but &T /&mut T exclusivity is parsed and not checked — the analysis is written up in SFEP-0018 and not currently prioritized. Effects and capabilities are what Sailfin offers that Rust does not; memory safety is not on that list.
vs. Zig
Zig's comptime and explicit allocator model give more direct control over memory than anything Sailfin offers, and Zig is considerably further along. Both target LLVM. Sailfin's addition is the type-level effect system — if what you want is control over allocation, Zig is the better tool.
Where Sailfin Is Today
Sailfin is pre-1.0 and under active development. The compiler self-hosts and passes its test suite on Linux x86_64, Linux arm64, and macOS arm64; the Windows build is cross-compiled and smoke-tested rather than self-hosting. Effect checking, capsule capability cross-checks, and a v0 structured-concurrency surface work end-to-end.
The runtime capability seal — enforcing declared grants at the syscall boundary, so that a capsule manifest is a cage rather than a lint — is a 1.0 blocker and is not implemented today. Until it lands, Sailfin's capability guarantees are compile-time proofs, and anextern declaration can still reach past them.
Performance is instrumented against regressions in CI, but there are no published cross-language benchmarks yet — if you need Sailfin to be fast for a particular workload, measure it. The specification and theroadmap track all of this in detail, and thecommunity is open if you want to get involved.