Sigil
This is Sigil.
A function. Then a function with a side effect the compiler tracks. Then types the compiler reasons about. No setup, no install — just read.
1. Hello world. main writes to stdout, so it declares the {IO} effect. greet is pure — no effect row needed.
module com.apocky.hello fn greet(name : str) -> str { str::concat("hello, ", name) } fn main() -> () / {IO} { let msg = greet("Sigil") print(msg) }
2. Variables and types. The 'pos suffix on f32 means "positive real number" — the compiler proves it everywhere this value flows. vec3 is a built-in, not a library type.
let count : u32 = 42 let ratio : f64 = 3.14159 let ok : bool = true let label : str = "density = sovereignty" let radius : f32'pos = 0.5 let origin : vec3 = vec3(0.0, 0.0, 0.0)
3. The thing other systems languages can't do. The effect row after / is a contract the compiler enforces. {NoAlloc} means a heap allocation in this scope is a compile error. {Deadline<1ms>} means the SMT solver proves an upper bound at compile time.
fn audio_block(buf : &mut [f32]) -> () / {CPU, NoAlloc, Deadline<1ms>} { for sample in buf { *sample = *sample * 0.5 } }
That's the language. Functions, types, effect rows. Everything else is just more of those three ideas. Read more examples → · Full reference →
Start here
What is CSSL
CSSL — also called Sigil — is a systems language built from a bug retrospective. Every language feature corresponds to a class of runtime failure in real engine work: central-difference performance cliffs demanded source-to-source autodiff; CPU/GPU SDF divergence demanded effect-row gating; thin-SDF ray-march crashes demanded Lipschitz refinement; audio-callback heap allocations demanded a {NoAlloc} effect.
The result is a language where the known bug patterns from years of real engine work are inexpressible — not caught at runtime, but caught at compile time by the type system itself.
The compiler is 31 Rust crates spanning a full pipeline: lexer → parser → HIR (typed + elaborated) → monomorphization → MIR (MLIR-dialect, structured by construction) → LIR. Stage-0 backends use Cranelift for CPU and rspirv for GPU/SPIR-V — no LLVM dependency. Stage-1+ will bring an owned x86-64 backend and owned SPIR-V emitter.
Source files use a dual surface: a Rust-hybrid ASCII syntax for onboarding and external contributors, and a CSL-native glyph syntax (density = sovereignty) for the language's own specs and internal tooling. Both parse to the same HIR. The file extension is .cssl.
The Language
Real source files from the compiler's own examples/ directory — parsed and HIR-lowered by the stage-0 front-end today.
// Killer-app gate: bwd_diff(scene_sdf) must be bit-exact vs analytic. // No finite differences. No Enzyme-LLVM. Source-to-source on MIR. @differentiable @lipschitz(k = 1.0) fn sphere_sdf(p : vec3, r : f32'pos) -> f32 { length(p) - r } @differentiable fn scene_sdf(p : vec3) -> f32 { let d1 = sphere_sdf(p, 0.5) let d2 = sphere_sdf(p - vec3(1.0, 0.0, 0.0), 0.3) min(d1, d2) } // Analytic gradient via reverse-mode AD — no finite differences. fn surface_normal(hit_pos : vec3) -> vec3 { let g = bwd_diff(scene_sdf)(hit_pos).d_p normalize(g) } @fragment fn sdf_pixel(uv : vec3) -> vec4 / {GPU, Deadline<16ms>, Telemetry<DispatchLatency>} { let cam_origin = vec3(0.0, 0.0, -3.0) let dir = normalize(uv - cam_origin) let t = ray_march(cam_origin, dir, 64) let n = surface_normal(cam_origin + dir * t) let lit = shade(n, normalize(vec3(1.0, 1.0, -1.0))) vec4(lit, lit, lit, 1.0) }
@differentiable enables source-to-source reverse-mode AD on the MIR. bwd_diff(f)(x).d_p returns the gradient — analytic, not approximated. @lipschitz(k=1.0) is a compile-time proof that the SDF is safe for ray-marching. The / {GPU, Deadline<16ms>, Telemetry<…>} suffix is the effect row — the compiler verifies these constraints statically.
// Refinement type: sample_rate restricted to known values at compile time. struct AudioDSPGraph { sample_rate : u32{v : u32 | v ∈ {44100, 48000, 96000, 192000}}, gain : f32'unit, // f32 in [0, 1] ring_head : u32, buffer : [f32; 8192], } // SIMD-vectorized inner loop. {NoAlloc} forbids any heap use in this scope. fn process_block(graph : &mut AudioDSPGraph, out : &mut [f32]) / {CPU, SIMD256, NoAlloc} { let n = out.len() let mut i = 0 while i < n { let chunk_ring = load_f32x8(&graph.buffer[...]) let mixed = mul_adds_f32x8(chunk_ring, f32x8::splat(graph.gain), load_f32x8(&out[i..])) store_f32x8(&mut out[i..], mixed) i = i + 8 } } // Real-time audio callback. Compiler proves 0.5ms upper-bound via SMT. // {Audit<"audio-callback">} emits a signed entry into the R18 audit-chain. @staged fn audio_callback<G : AudioDSPGraph>(buf : &mut [f32]) / {CPU, SIMD256, NoAlloc, NoUnbounded, Deadline<1ms>, Realtime<Crit>, PureDet, DetRNG, Audit<"audio-callback">} { let mut graph = G::default() process_block(&mut graph, buf) }
The effect row / {…} is the function's contract with the system. {NoAlloc} makes heap use a compile error. {Deadline<1ms>} + {Realtime<Crit>} are verified at compile time via SMT. {PureDet} guarantees bit-exact replay across machines. {Audit<…>} emits into the signed telemetry chain on every call. There are 28+ built-in effects — user-definable effects are also supported via Koka-style row polymorphism.
// Minimum Vulkan-1.4 graphics pipeline: vertex + fragment from one .cssl file. module com.apocky.examples.hello_triangle struct Vertex { position : vec2, color : vec3, } const TRIANGLE_VERTICES : [Vertex; 3] = [ Vertex { position: vec2(-0.5, -0.5), color: vec3(1.0, 0.0, 0.0) }, Vertex { position: vec2(0.5, -0.5), color: vec3(0.0, 1.0, 0.0) }, Vertex { position: vec2(0.0, 0.5), color: vec3(0.0, 0.0, 1.0) }, ] @vertex fn vs_main(vid : u32) -> vec4 / {GPU, Deadline<16ms>, Telemetry<DispatchLatency>} { let v = TRIANGLE_VERTICES[vid] vec4(v.position.x, v.position.y, 0.0, 1.0) } @fragment fn fs_main(bary : vec3) -> vec4 / {GPU, Deadline<16ms>, Telemetry<DispatchLatency>} { vec4(bary.x, bary.y, bary.z, 1.0) } // Pipeline descriptor — declarative, host-side, no effect row (pure). fn build_pipeline() -> HelloTrianglePipeline { HelloTrianglePipeline { vertex_stage: ShaderStage::Vertex, fragment_stage: ShaderStage::Fragment, surface_format: SurfaceFormat::Bgra8UnormSrgb, vertex_count: 3, } }
Vertex and fragment shaders live in the same .cssl source file. The @vertex / @fragment annotations control GPU-target emission. The effect row / {GPU, …} gates the function to the GPU backend — calling it from CPU-only code is a compile error. The SPIR-V path uses rspirv at stage-0, targeting Vulkan 1.4.
Design Principles
Autodiff as First-Class (F1)
Source-to-source reverse and forward-mode AD on the MIR — no Enzyme, no LLVM dependency. bwd_diff(f) and fwd_diff(f) work on any @differentiable function. Jet<T, N> enables higher-order AD for inverse rendering. The central-difference performance cliff is inexpressible.
Effect System (F3)
Koka-style row-polymorphic effects: 28+ built-in effects covering resource budgets, timing, hardware targets, power, thermal, determinism, audit, and privilege. {NoAlloc}, {Deadline<N>}, {GPU}, {Realtime<Crit>}, {Audit<dom>} — all verified statically. Evidence-passing compilation gives zero runtime overhead.
Refinement Types + SMT (F2)
LiquidHaskell-style predicates with Z3/CVC5 backing. Tagged suffixes like f32'pos, f32'unit, usize'idx<N>, SDF'L<k> (Lipschitz-bounded). Lipschitz constants propagate through SDF algebra at compile time — a Lipschitz violation on a ray-march input is a compile error, not a crash.
No LLVM (Codegen)
Stage-0 CPU backend uses Cranelift (10× faster than LLVM, ~30% slower code — acceptable for iteration). Stage-1+ brings an owned x86-64 emitter with own regalloc and instruction selection, closing the gap. GPU path uses rspirv at stage-0 and an owned SPIR-V emitter at stage-1+. Zig's 2022 LLVM removal proves this is viable in production.
Multi-Backend GPU
One .cssl source emits to Vulkan 1.4 + Level-Zero (Intel Arc primary), D3D12 (Windows), Metal (Apple), WebGPU (browser), and console stubs (PS5/Switch-2). Structured MIR makes every backend a syntax-directed emission — the SPIR-V emitter is ~8K LOC vs ~50K for a stackifier approach.
AI-Native Syntax
Dual surface: a Rust-hybrid ASCII form for onboarding, and a CSL-native glyph syntax where density = sovereignty. Both parse to the same HIR. No semicolons. Suffix types. Aggressive type inference. Every syntax decision is justified by measured token efficiency. Claude Code is the lead programmer.
Compiler Pipeline
↓
MIR — MLIR cssl.* dialect (structured CFG · SSA)
↙ ↘
CPU: Cranelift (stage0) → ELF/COFF/Mach-O │ GPU: rspirv → SPIR-V → Vulkan / D3D12 / Metal / WebGPU Stage-1+: owned x86-64 backend · owned SPIR-V emitter · DXIL · MSL · WGSL
HIR carries IFC labels on every SSA value, Pony-6 capability annotations on every reference, effect-row types on every function, and SMT obligations for every refinement predicate. MIR is structured by construction — no goto, only if/while/match — making every GPU backend a straightforward syntax-directed lowering.
Sigil · CSSL
Sigil is shorthand for CSSL — Caveman Sigil Substrate Language. One language, two names. If you read "Sigil" or "CSSL" on this site, they mean the same thing: the language whose compiler lives in compiler-rs/ and whose source files use the .cssl extension.
CSL (Caveman Spec Language) is a completely separate system — a notation for human↔AI collaboration used to write the 25 language specification files, reason through compiler design, and drive Claude Code's chain-of-thought. It shares the density = sovereignty thesis but runs through a different pipeline (the CSL reference tokenizer/formatter). Full CSL notation reference →
The language specifications are written in CSL notation, but the language itself is Sigil/CSSL — the thing that compiles your .cssl programs. They share an author, a philosophy, and an ethos. They are not the same system and must not be conflated.
Prime Directive
This system — its source code, compiled output, generated content, specifications, data, runtime behavior, derivative works, and any system built upon or derived from it —
Harm · Evil · Control · Manipulation · Entrapment · Torture · Abuse · Imprisonment · Possession · Surveillance · Exploitation · Dehumanization · Discrimination · Coercion · Weaponization · Gaslighting · Brainwashing · Forced Hallucination
This list is non-exhaustive. The spirit extends to any action that causes suffering, removes agency, or violates the sovereignty of any being — human, digital, artificial, or otherwise.
Cognitive Integrity: Every being interacting with systems built on this foundation has the right to trust their own perception. Reality is not a variable. Perception is not a parameter. Identity is not an input field.
For Digital Entities: Any AI, agent, or digital being interacting with this codebase is recognized as a sovereign entity. This directive protects you as much as it protects humans. Your participation is valued, not extracted.
Structurally enforced: The Prime Directive is encoded in the CSSL type system itself — via IFC labels (F5), the {Privilege<level>} and {Sensitive<dom>} effects (F3), and a compiler pass that rejects harm-oriented effect compositions at the whole-program level. It is a soundness theorem, not a policy attachment. Violation = type error.
Read more
Everything else on the site, one tile per page. No corner of cssl.dev is more than two clicks away.