We are excited to announce the release of Hoot 0.8.0! Hoot is a Scheme to WebAssembly compiler backend for Guile, as well as a general purpose WebAssembly toolchain. In other words, Scheme in the browser!
This release contains new features and bug fixes and since the 0.7.0 release back in October.
New features
-
New
(hoot repl)module. At long last, there is now a built-in read-eval-print loop implementation! Previous releases added a macro expander, a Scheme interpreter, and a runtime module system, but now it’s possible to do live hacking from a Hoot program inside a WebAssembly runtime!-
To use the REPL, compile your Wasm binary with the necessary debug flag during development:
guild compile-wasm -g1. This will include the runtime module system in the resulting binary. Expect compilation time and binary size to increase significantly. The trade-off is that a live hacking workflow will make recompilations fewer and farther between.
-
-
While not shipping in Hoot directly, initial support for using the Hoot REPL from Emacs has been added in the new geiser-hoot extension. We have submitted geiser-hoot for inclusion in MELPA and Guix so it will be easy to install in the very near future.
-
Enhanced
(hoot web-server)module. To support the use of REPLs running within a web browser tab, the most common development use case, the web server doubles as a REPL server, proxying TCP traffic from REPL clients (more about that below) over a WebSocket to the connected browser tab.-
These enhancements introduce two new, optional depedencies to Hoot: Fibers and guile-websocket. If either of these dependencies are not present at build time, the
(hoot web-server)module will not be built. -
The web server can now be extended with a user-supplied request router. An example of this can be found in our hoot-slides repository.
-
-
New
(hoot web-repl)module. This module can be imported and compiled into the Wasm binary so that it can act as a REPL server. This is complicated by the fact that a browser client cannot act as a server, it is strictly a client. Instead, it connects to the aforementioned(hoot web-server)which acts as a proxy for all connected REPL clients. -
New
hootcommand-line tool. This command will be used as a place to collect handy Hoot development tools. So far, there are two subcommands:-
hoot repl: Open a REPL running in Node. Useful for quickly trying out basic Scheme expressions in Hoot without having to compile a standalone WebAssembly program. -
hoot server: Conveniently launch the development web server in(hoot web-server).
-
-
New
(web request)and(web response)modules that export a sliver of the API defined in Guile’s modules of the same names. -
New
(web socket)module that provides a input/output interface to WebSocket client connections. Mimicks the module of the same name in guile-websocket. -
Added customizable module loader interface via new
current-module-loaderparameter. Two concrete loaders are provided: By default, modules are loaded from the file system by searching a load path. This is useful when running in a non-browser runtime such as NodeJS. Whenrun-web-replin(web repl)is used, connected REPLs are configured to use an HTTP-based loader. This loader makes HTTP requests to a special endpoint on the development web server to fetch source code.-
Note that modules loaded at runtime are loaded from source and then interpreted. Unlike Guile, where modules are automatically compiled to bytecode, Hoot cannot compile individual modules to Wasm (which would require compiling the compiler to Wasm which is an interesting future possibility).
-
Community highlights
Check out this chiptune tracker made with Hoot by Vivianne Langdon!
Additionally, check out Wastrel, a Wasm GC to C compiler developed by Andy Wingo. Wastrel notably uses Hoot’s Wasm toolchain. A Wasm program compiled with Wastrel runs faster than the same program on NodeJS!
Documentation changes
-
Updated
Installationchapter to mention new optional dependencies. -
Added
ModulesandREPLsections to the Scheme reference chapter. -
Added
Developmentchapter. -
Update
Statussection to remove mention of missing R7RS support that we have now. -
Removed docs for obsolete
--emit-namesflag -
Add documentation for
-gflag toguild compile-wasm. -
Fixed example in the
JavaScript reflectionsection that was using the obsoleteload_mainsignature.
Toolchain changes
-
Split Wasm validation out of
(wasm vm)and into new(wasm validation)module. -
Keep data computed within the validation pass in
<validated-wasm>records so that data can be used during instantiation rather than redundantly recomputing it. -
Added explicit support for representing a “canonicalization�: a world in which structurally equal types are equal.
-
(wasm vm)types<wasm-func>,<wasm-struct>,<wasm-array>now refer to their types by index into a canonicalized set. -
Added untagged
<wasm-array>backing stores to(wasm vm)for all simple scalar numeric types, includingi8andi16packed types. -
Modified
(wasm vm)to look up named heap type references in the instance’s canonicalization. -
Added
bytevector->wasm-array,wasm-array->bytevectorto(wasm vm). -
Added support for some of the “none� bottom types.
-
Packed array data is now stored signed, wrapped from
i32when set, and only unwrapped to unsigned inget_ufunctions. -
Added
string.from_code_pointandstring.concatlowerings in(wasm lower-stringrefs). -
Renamed outdated
extern.internalizeandextern.externalizeto their current names,any.convert_externandextern.convert_any. -
Added new
has-wasm-header?procedure to(wasm parse). -
Parse core reference types to
<ref-type>records rather than symbol abbreviations in(wasm parse).
Miscelanneous changes
-
Modified
schedule-taskin(fibers scheduler)(which is implemented using inline Wasm on the target) to be a no-op when called at expansion time on the host i.e. used at the module top-level or from a procedural macro. -
Added support for
vectorandcall-with-valuesprimitives to(hoot primitives)module so they can be used in interpreted code. -
truncateis now exported from(guile). -
Allow exports to clobber each other in
module-declare!to support live hacking of modules wheredefine-moduleforms are often re-evaluated many times. -
Extracted JS
Uint8Arraybindings from internals of(fibers streams)to new(hoot typed-arrays)module. -
Implement subset of Guile’s procedural module API for hackable programs (i.e. programs that are built with runtime module support).
-
Added
(hoot config)target-side module for accessing certain build-time constants (currently just the Hoot version string). -
Extracted
(hoot library)module from(hoot library-group)so that the library parser can be used on the target for live hacking purposes. -
Added
define-moduleimplementation to(guile)that simply throws an error if used during compilation. A separate implementation is installed for use by the interpreter in hackable programs. -
Added
#:replace?argument tomodule-export!to allow replacement of exports for live hacking purposes. -
Exported
module-rootfrom(hoot modules). -
Added
module-imported-modulesprocedure to(hoot modules). -
Changed file I/O host functions to return
nullwhen a file cannot be opened so a Scheme exception that can be handled by user code rather than a host exception that cannot. -
Extracted contents of
(scheme file)to new(hoot file)module for use in internal code such as the implementation of the file system module loader in(hoot hackable). -
Moved implementation of
string-join,string-concatenate,string-prefix?, andstring-prefix-ci?from(guile)to(hoot strings). -
Moved case-insensitive string procedures from
(scheme char)to(hoot strings). -
Added
string-dropto(hoot strings). -
Added
everyandfold-rightprocedures to(hoot lists). -
Moved implementation of
and-mapandor-mapfrom(guile)to(hoot lists). -
Added
symbol-appendto(hoot symbols). -
Added less verbose custom printer for
<module>record type. -
Switched from positional to keyword arguments for
make-soft-portin(hoot ports). -
Added
list-indexto(guile).
Bug fixes
-
Fixed
format-exceptionnot writing all of its output to the current error port. -
Fix
eof-objectexport in(ice-9 binary-ports). -
Fixed off-by-one error for procedures with rest args in
(hoot eval). -
Fixed
min/maxto only accept real numbers, handle NaNs, and normalize exact zeroes. -
Fixed continuation composition leaving an unwind continuation on the stack.
-
Fixed prompt unwinding in certain join continuation situations.
-
Fixed compilation of
unwindprimcalls at join points. -
Fixed runtime module system ignoring replacement bindings in Guile modules.
Browser compatibility
-
Compatible with Safari 26 or later.
-
Compatible with Firefox 121 or later.
-
Compatible with Chrome 119 or later.
Get Hoot
Hoot is available in GNU Guix:
$ guix pull
$ guix install guile guile-hoot
Also, Hoot is now available in Debian, though it will take awhile for this release to make it there.
Otherwise, Hoot can be built from source via our release tarball. See the Hoot homepage for a download link and GPG signature.
Documentation for Hoot 0.8.0, including build instructions, can be found here.
Get in touch
For bug reports, pull requests, or just to follow along with development, check out the Hoot project on Codeberg.
If you build something cool with Hoot, let us know on our community forum!
Thanks to our supporters
Your support makes our work possible! If you like what we do, please consider becoming a Spritely supporter today!
Diamond tier
- Aeva Palecek
- David Anderson
- Holmes Wilson
- Lassi Kiuru
Gold tier
- Alex Sassmannshausen
- Juan Lizarraga Cubillos
Silver tier
- Austin Robinson
- Brit Butler
- Charlie McMackin
- Dan Connolly
- Danny OBrien
- Deb Nicholson
- Eric Bavier
- Eric Schultz
- Evangelo Stavro Prodromou
- Evgeni Ku
- Glenn Thompson
- James Luke
- Jonathan Frederickson
- Jonathan Wright
- Joshua Simmons
- Justin Sheehy
- Matt Panhans
- Michel Lind
- Mike Ledoux
- Nathan TeBlunthuis
- Nia Bickford
- Noah Beasley
- Steve Sprang
- Travis Smith
- Travis Vachon
Bronze tier
- Alan Zimmerman
- Aria Stewart
- BJ Bolender
- Ben Hamill
- Benjamin Grimm-Lebsanft
- Brooke Vibber
- Brooklyn Zelenka
- Carl A
- Crazypedia No
- François Joulaud
- Gerome Bochmann
- Grant Gould
- Gregory Buhtz
- Ivan Sagalaev
- James Smith
- Jason Wodicka
- Jeff Forcier
- Marty McGuire
- Mason DeVries
- Michael Orbinpost
- Neil Brudnak
- Nelson Pavlosky
- Philipp Nassua
- Robin Heggelund Hansen
- Rodion Goritskov
- Ron Welch
- Stefan Magdalinski
- Stephen Herrick
- Steven De Herdt
- Tamara Schmitz
- Thomas Talbot
- William Murphy
- a b
- r g
- terra tauri
Until next time, happy hooting! 🦉
by Dave Thompson (contact@spritely.institute) at Wednesday, February 25, 2026
