Sigil 0.13.0
Sigil ships as a native binary. The release CLI is compiled end-to-end through the native C backend — no bytecode, no interpreter loop, no runtime-compile on startup. Every sigil invocation on 0.13.0 exercises the native runtime. This release also introduces a full Language Server Protocol implementation (sigil lsp serve), restructures the native compile pipeline for visibility and parallelism, and lands the cell-elision and escape-analysis codegen optimizations default-on.
Native sigil CLI
sigil build sigil-cli -c release produces a fully native binary. No extra flags required — the workspace release config declares backend: 'native. All shippable configs (release, prerelease, and every cross-compile target) now declare backend: 'native; the WASM target keeps the bytecode VM.
Linux x86_64 ships in two variants:
sigil-linux-amd64— dynamic glibc, cross-compiled via zig. The default download for normal distro users: smaller, faster startup, plays with system libc.sigil-linux-amd64-static— static musl. Self-contained bootstrap binary for unknown distros, containers, and downstream CI that needs "runs anywhere."
Showcase: Cinder Cantata
Cinder Cantata v0.2.0 — a music-reactive bullet-hell built on Sigil — ships alongside this release as a demonstration of the native backend's performance. The full game loop runs on the 0.13.0 runtime: native codegen for the per-frame hot path, goroutines for audio streaming, FFI for graphics/audio sokol bindings, and the motif audio composition engine driving enemy bullet patterns in lockstep with the soundtrack. Download a playable binary for Linux x86_64 from the release page.
Language Server (sigil lsp serve)
Sigil now ships a full LSP 3.17 implementation, invoked as sigil lsp serve. Editors and coding agents can wire it up over stdio for:
- Diagnostics — reader errors, compile errors, and lint warnings reported inline with source spans
- Hover — signature + full docstring for any binding at point, with fallback to the runtime spec when source isn't available
- Completion — context-aware completion items with proper
filterTextandtextEditfor editors like eglot - Go-to-definition — jumps to the exporting
.sglsource line; descends into library re-exports - Formatting — full-document and range formatting via
(sigil format) - Quick-fix code actions —
suggest-importproposes imports for undefined bindings andremove-unused-importcleans up lint warnings; both offered on cursor position, not just on diagnostics - Unused-import linter — detects unused imports with precise source spans, including inside re-exporting libraries
The server warms its docs index at initialized so first hover/completion is snappy. sigil lsp serve --log-file ... --log-level ... gives you traceable logs when debugging editor integrations.
Per-config backend: declarations
Build configs now declare their backend directly: (config name: 'release backend: 'native ...). Replaces the previous pattern where users had to use --backend native at build time. Each project's dev/release configs now declare their own backends (bytecode for fast iteration, native for shipping).
Per-package native compile pipeline
The native build pipeline was restructured to emit mod_*.c and compile to .o inside each package's build step instead of at the end in a silent 200K-line blob. Visible COMPILE mod_X.o per-package progress, parallelizable, better cache locality.
Cache correctness
Cache keys now include compiler identity + SGB version. Three caches (deps fetch, SGB auto-compile, runtime native) are keyed honestly against the exact compiler + runtime fingerprint they were produced with. Fresh checkouts and compiler rebuilds now produce consistent results instead of resurrecting phantom bytecode from a prior compiler version, eliminating a whole class of compiler errors.
Codegen optimizations (default-on)
- Escape analysis — closures whose captures don't escape the enclosing frame are now stack-allocated instead of heap-allocated. Includes a trampoline-frame fix for
TAIL_CALL.proc. - Cell elision v2 — post-conversion pass removes cells for variables that are read-only after definition. Register-allocator clobber bug that had blocked enabling cell elision by default (in 0.12.0) is fixed.
Both can be disabled via SIGIL_CPS_NO_CELL_ELISION=1 and similar env vars for the escape-analysis pass.
MCP server reliability
sigil-mcp (the Model Context Protocol server that lets Claude Code drive sigil) got a reliability pass:
- Subprocess isolation for the
sigil/testtool (was inheriting sigil-mcp's environment) - Per-server
--log/--log-levelflags for traceable multi-worker setups - JSON-RPC
id: nullcompliance for notification-shaped messages
Worker fleets running sigil-mcp across many concurrent Claude Code sessions are now stable.
Bug Fixes
- Self-rebuild trampoline crash — fixed a dangling
inline_argspointer in the native-bridge trampoline. The pointer referenced a stack slot that had already been unwound by the time the trampoline bounced back through it. Harmless in short-running programs, fatal on the self-rebuild cycle where the compiler recursively compiles itself. - Closure serialization across threads — cell elision could leave some captures as raw values while siblings remained upvalue cells. Value-level serialization now carries a per-capture is-cell flag, so deserialized closures rebuild with the exact capture shape the code expects. Fixes cross-thread closure passing under default codegen settings.
- Nested-guard codegen — exception-unwinding flag is now cleared after a tail handler fires, fixing a latent bug in deeply-nested
guardforms. - Compiler self-bootstrap — 0.12.0 compilers can now build 0.13.0 source without guarded-reference crashes (
SIGIL_ABI_VERSIONreference is#ifdef-gated).