Sigil 0.17.12

release

A records-and-methods release, with a native-async correctness fix that was silently breaking MCP servers. Two new core libraries, (sigil record) and (sigil method), bring extensible typed records and cached multimethod dispatch to the standard library, and a compiler fix lets procedural macros export across module boundaries at last. Alongside them, browser programs can now route DOM events straight into Sigil, a native-backend regression that dropped an async server's response mid-request is fixed, and two toolchain footguns are gone. Existing projects build without changes.

Download 0.17.12Get started

(sigil record): extensible typed records

(sigil record) adds define-record, a dict-backed record with a unique type identity, declared fields, a constructor, a predicate, and per-field accessors, plus single inheritance through include:. Records are the open, extensible counterpart to (sigil struct)'s fixed-slot types: a record is a dict underneath, so it carries arbitrary namespaced keys alongside its declared fields, updates immutably while preserving its type, and datafies carrying its own type tag. The tag is deliberately visible, so a record serializes and inspects as what it is, and a plain dict is never mistaken for one. A derived type declared with include: inherits its parent's fields and answers the parent's predicate.

(sigil method): multimethods with cached dispatch

(sigil method) adds define-multi and define-method, open dispatch over records, structs, or core values through a generic type walk. A method registers from any module, so a package can add a type and its behavior without touching the code that dispatches on it, and a base type's method serves as the inherited default up the parent chain, with a :default fallback. Dispatch is cached for hot paths: a per-multimethod memo backed by a monomorphic fast path, invalidated on every method (re)definition, so redefining a method at the REPL always takes effect. One primitive covers both protocol-style dispatch on type and multimethod-style dispatch on data.

Procedural macros export across modules

A procedural macro (a define-syntax transformer, including syntax-case) now exports from a define-library and works in an importing module exactly like a syntax-rules macro does. Until now it silently did not, so a macro that synthesizes identifiers, the kind syntax-rules cannot write, could not be shared across modules as a library. This is what lets (sigil record) ship its generated accessors as an ordinary library, and it fixes procedural-macro export for every package.

DOM events into Sigil, in the browser

(sigil web client) can now wire a DOM event straight to a Sigil closure. An sxml attribute of the form on-click:, on-input:, or on-key: whose value is a procedure is registered as a real event listener through a new addEventListener bridge in sigil-wasm-dom, and the closure is called with the event's useful properties: key, target value, caret, and the keyboard modifiers (ctrl, meta, alt, shift). Browser UI event handling can now live in Sigil instead of hand-written JavaScript.

A native-async fix that was silencing MCP servers

An MCP server built against 0.17.11 answered its initialize request and then went quiet on tools/list: it exposed no tools, logged no error, and was useless. This release fixes it. The bug lived in the native backend's async runtime, where a background task interrupted at the wrong moment could drop the response it was in the middle of building. Any native-compiled async server is affected, an MCP server or an HTTP server running handlers on goroutines, and now completes its request correctly. If you build on the native backend, upgrade to pick this up.

Toolchain fixes