Yurt
Upcoming
Updated 2026-10-28 · not released yet; plans may change
Work that is in progress or in review for a later train. None of it is
on the live playground yet.
Dynamic loading (dlopen)
-
The kernel and libc sides of
dlopen ship in
playground-2026.10.20-22366ef. Still in progress: a shared
libc.so, so ordinary CPython native extensions can load
(yurt-toolchain #180, #236; yurt-ports #173).
-
Thread-local storage in runtime-loaded libraries ships for the
desktop host in playground-2026.10.26-3d32068; the browser-host half
is in progress (kernel #4034).
JavaScript JIT (experimental)
Node on Yurt runs SpiderMonkey's interpreter. The JIT work adds a tier
that compiles hot JavaScript to WebAssembly inside the guest
(NightMonkey) and mounts it through the kernel's JIT interface. It is
not in the image and stays off by default.
-
Opt-in node build with NightMonkey (yurt-node #42),
for measurements. On the desktop host, Octane benchmarks ran
2–47× faster and hot loops up to 178×. Compiling
costs 0.3–24 s per run, only the first batch of code is
compiled so far, and Gemini CLI does not speed up yet.
-
Kernel: JIT code now survives
fork
on the desktop host (kernel #3677). Still open: slot reservation and
module loads over 1 MiB on the browser host (#2981, #3319), and fork
and checkpoints across JIT frames (#3335). Tracked in yurt-ports
#110.
Go
-
Go runs on Yurt as Linux: yurt-go adds a
GOOS=linux GOARCH=wasm32 port on top of upstream Go's
wasm32 work (golang/go#63131, not merged upstream yet). Go programs
build into ordinary Yurt processes that use Linux system calls, not
WASI.
-
The Go toolchain runs inside the sandbox: the
yurt-ports
go package (Go 1.28.0-devel, 59.4 MB) installs
go and gofmt under
/usr/lib/go, so go build and
go test work in a sandbox. The GitHub CLI (gh) is built with it.
-
Neither is in the playground image; both install as
packages. Go programs run on one thread,
and signals reach them only between system calls.
Later trains
-
Root can search and create in a directory that has no execute bits,
as on Linux (#3714).
Planned
-
Ctrl-C and
kill -INT reach a CPU-bound Python program,
so KeyboardInterrupt works (#2811).
Packages
Updated 2026-10-28 · released independently of trains
Packages come from the signed
YurtOS/yurt-packages
repository and are published on their own schedule, not with a train.
In a sandbox with a network, sudo pkg update then
sudo pkg install NAME installs the newest version, and
sudo pkg upgrade moves to newer ones. In the browser the
Packages panel does the same. pkg verifies every
signature before it installs anything.
python, numpy, pyzmq, jupyter-kernel, python-seal and python-dev are one set,
built together: numpy and pyzmq are compiled into the interpreter.
Install them together, at the same build.
playground-2026.10.29-3d32068
2026-10-29 · replaces playground-2026.10.27-3d32068.2
A new image only: pkg now keeps a plain list of what is
installed. The kernel, the desktop app and the yurt CLI are
unchanged.
Highlights
-
pkg lists what is installed. Every install now
also writes
/var/lib/yurt-pkg/installed.list,
one line per package (name, version and build, separated by tabs).
Anything can read it without running pkg.
-
The instant-Python snapshot was captured again
for the new image, so reloads still have Python ready in seconds.
playground-2026.10.27-3d32068.2
2026-10-28 · replaces playground-2026.10.27-3d32068
A reload now has Python ready in about 11 seconds instead of about 85,
an install that stalls says so and offers a fresh start, and the
desktop app's image is a third smaller. The kernel is unchanged.
Highlights
-
Python is instant on later visits. After the
first install, the page keeps the installed files in this
browser (one compressed layer, about 31 MB). On a reload, or
offline, it writes them back in about a second instead of running
the install again, as long as the package repository still offers
the same Python set. Nothing is downloaded. A newer set is
installed normally and kept in turn.
-
A stalled install says so. When the Python
install stops making progress for a minute, or one run of
pkg takes more than five minutes, the cell says so and
offers Try again. Try again starts a fresh sandbox and
installs again, without reloading the page. Before, the page could
stay on “verifying and installing” for good.
-
pkg needs far less memory to install.
It now streams each file to disk while it checks the archive,
instead of holding every package in memory. Installing the Python
set peaks at 79 MB instead of 259 MB (measured natively).
Nothing reaches the system before every signature and checksum has
passed, as before. This fixes
“memory allocation of … bytes failed” in Safari.
-
A smaller desktop image. The full image is now the
slim image plus the published Python set, Node, Gemini CLI and
Datasette: 91.9 MB instead of 144.0 MB. The CPython headers and
static library moved to the new
python-dev
package; sudo pkg install
python-dev brings them back for building extensions.
/usr/local/bin/cpython3.wasm stays, as a link to
python3.
-
Trains no longer rebuild good packages. An image
release takes the Python set, Node and Gemini CLI from their
signed, published packages, and builds only the tools. The image
build dropped from about 98 minutes cold to about 49, and to 10 to
16 minutes warm.
-
The yurt CLI's built-in image pins are current.
Signed in to GitHub, the previous CLI pulled the image of a train
from mid-October instead of its own.
-
The Notebook page no longer logs a 404 for
/favicon.ico.
Measured
On the live site (Apple M-series laptop, Chromium):
4 of 4 cold starts on the live site succeeded with no stall and no
console errors.
Known issues
-
Safari: the first Python install may not finish.
The memory error is fixed, but in our automated Safari 27 runs the
sandbox stops answering partway through the install, and after five
minutes the cell offers Try again. It is not yet known
whether the automation itself causes this, as a browser debugger
does in Chrome (kernel #4170). The shell works in Safari. Chrome
and the desktop app run all of it.
-
In a tab driven through a browser debugger, the Python install can
stop partway (kernel #4170); it now ends with Try again
instead of waiting for good.
playground-2026.10.27-3d32068
2026-10-27 · replaces playground-2026.10.26-3d32068
The browser now boots a slim image: 23.5 MB instead of 144 MB. Python
is no longer baked into it. Every page that runs Python installs the
newest Python set from the package repository, with the sandbox's own
pkg, the first time it needs it. The kernel, the desktop
host and the yurt CLI are the previous train's.
Highlights
-
A slim browser image. The tab loads 23.5 MB
instead of 144 MB before the shell starts. It holds the shell, the
command line tools (git, curl, jq, sqlite3, zsh, make, zstd, xz),
sudo, pkg and the CA bundle. Python,
Jupyter, Node and Gemini CLI install as
packages when you need them.
-
Python installs itself. The Python pane, the
Notebook, JupyterLab and the agent install the newest complete
Python set (python, numpy, pyzmq and jupyter-kernel) before the
kernel starts. Progress shows in the cell and the status line, and
the shell works meanwhile. The archives stay in the browser's
cache, so a reload downloads only the package index and its metadata. A reload
still installs again, because the sandbox's files do not survive
it. If the install fails, the cell says why and offers
Try again.
-
Packages are released on their own. A newly
published Python set reaches the page with no new train. The page
reads the signed index and takes the newest complete set; a set
that is only partly published is never chosen. See
Packages for what is published.
-
Suspend/Resume runs the set's own Python (its
python-seal), after the sandbox's pkg has
verified it. A suspended notebook resumes only on the Python set it
was suspended with. When a newer set is out, an older suspend is
discarded, and the panel names both sets. Suspends made by earlier
trains are discarded the same way.
-
The package repository is read from
raw.githubusercontent.com instead of GitHub's API. The
API allows 60 requests an hour per address, and a cold
pkg update plus one install takes about 20 of them.
Signatures are verified as before.
-
The desktop app and the CLI know what the image
ships. The full image records Python, numpy, pyzmq, the
Jupyter kernel, Node and Gemini CLI in
pkg's
database. sudo pkg install pyzmq numpy now says there
is nothing to install, and packages that depend on them install.
-
Phones get the shell without Python. A phone tab
has too little memory to install Python, so on a phone the home
page (opened with
?start-anyway) starts the Linux
shell and the agent without the Python install, and says so. You
can still install python from Packages, but
the tab may run out of memory. The Notebook and JupyterLab pages
do not start a sandbox on a phone. Tablets keep the shell-only
page they had. A desktop browser, or the desktop app, runs all of
it.
Measured
On the live site with a cold cache (Apple M-series laptop; Chromium,
and Chrome 156):
26 of 26 cold starts on the live site and locally succeeded with no stall (23 in Chromium, 3 in Chrome 156). Most of the install
time is the sandbox writing the files (kernel #4169); a faster path
is planned.
Known issues
-
In a tab driven through a browser debugger (the DevTools protocol,
as browser-automation extensions use), the Python install can stop
partway and stay on “verifying and installing” (kernel
#4170). Reload the page without the debugger attached.
-
The Notebook page logs a harmless 404 for
/favicon.ico (#247).
playground-2026.10.26-3d32068
2026-10-26 · replaces playground-2026.10.25-f884f16
This train moves the Guest SDK from 0.0.29 to 0.0.31, and the image
gains everyday command line tools and a working pkg
install. The kernel adds bind and move mounts, thread-local
storage in dlopen'd libraries on the desktop host, and
live shared mappings of memfd and /dev/shm.
Highlights
-
Guest SDK 0.0.31. The kernel and every program in
the image are built with it. Programs built with 0.0.29 keep
running; you don't need to rebuild them. We ran the
previous train's whole image (built with 0.0.29) on this train's
runtime: the shell,
python3 with threads,
fork and TLS, and node all work. Rebuild
with 0.0.31 to pick up two SDK changes. In C, syscall(...)
takes any number of arguments, including structs (this was planned
as 0.0.30, which was never released on its own). And the loader now
tells the kernel when a library's constructors have finished, so
another thread is never handed a half-initialised library (#4063).
Programs built with 0.0.29 keep the previous train's behaviour for
both.
-
More tools in the image:
git,
curl, jq, sqlite3,
zsh, make, zstd,
xz, pkg and sudo, with a CA
bundle so curl and git verify HTTPS
(yurt-ports #249). The default user has passwordless
sudo, as in a dev container.
-
pkg install works against the signed
YurtOS/yurt-packages repository, for example
sudo pkg install rtk. The image ships its own
busybox outside pkg, so install the
busybox package into another root with
--root.
-
mount with MS_BIND,
MS_BIND|MS_REC and MS_MOVE
(#3107).
-
Thread-local storage in
dlopen'd
libraries on the desktop host, in the loading thread and
its fork children (#4017, #4059).
-
Live
MAP_SHARED for memfd and
/dev/shm: processes that map the same object
see each other's writes (#4067).
Kernel
Playground
-
Upload files from your device into the sandbox (playground #230).
-
Install packages from YurtOS/yurt-packages in the browser tab
(playground #231).
playground-2026.10.25-f884f16
2026-10-25 · replaces playground-2026.10.20-22366ef
A kernel train on the same Guest SDK (0.0.29), so programs built for
the previous train keep running. It fixes epoll on standard input and
output, makes runtime-loaded libraries behave more like Linux, writes
shared file mappings back reliably, and rebuilds the image's
python3 as a plain Linux/musl CPython.
Highlights
-
epoll on stdin, stdout and stderr. A watch on a
standard stream survives closing an unrelated descriptor and ends
when its file's last descriptor goes, however that happens (close,
dup2, exec, exit). EPOLLEXCLUSIVE is
refused where Linux refuses it, and unknown event bits are ignored
(#3837).
-
python3 is a plain Linux/musl CPython
(yurt-ports #236, #245).
-
A
#! script on a host-mounted folder
can name its interpreter, from execve,
posix_spawn and the shell (#3961).
-
Shared file mappings are written back at exit, on
a fatal signal and at exec (#3963), and
msync reaches
host files (#4061).
-
A TCP send to a host socket never stalls the sandbox.
A blocking send waits for room instead (#3325).
Kernel
Image
-
python3 is configured as plain Linux/musl, and its
Linux API smoke now checks os.getrandom (yurt-ports
#236, #245).
- New ports: zstd and pkgconf (yurt-ports #134, #133).
Playground
-
The snapshot demo and both notebook kernels tell you to reload when
the browser runs out of memory for new processes, as the main page
already does (playground #226).
playground-2026.10.20-22366ef
2026-10-21 · replaces playground-2026.10.15-230cfe2.2
This train moves everything to Guest SDK 0.0.29, brings a new Node.js
build with many fixes, brings back checkpoint sealing, and ships the
kernel side of dlopen with a large set of kernel and CLI
fixes.
Highlights
-
Guest SDK 0.0.29 everywhere. The kernel, the image
and Node are all built with it. Time values in
rusage, itimerval, ppoll,
timex and socket timeouts are 64-bit (#3638).
-
Old programs that start threads now get an error.
A program built with Guest SDK 0.0.26 or older that starts a thread
gets
EAGAIN (Python says "can't start new thread")
instead of running the thread on the main stack and corrupting
memory (#3906). Rebuild such programs with 0.0.27 or later. Images
saved from earlier trains carry programs built with 0.0.26, so they
are affected.
-
Node.js 22.23.3-yurt.3 replaces yurt.2, with the
license texts of every bundled component and many fixes (see below).
-
Checkpoint sealing is back (kernel
#3497–#3499). The kernel records each module's execution state
again. On the browser host only programs built for checkpoints
(Guest SDK 0.0.27 or later) are sealed; anything else is refused
instead of sealed into an image that cannot resume. The desktop host
refuses these seals for now.
-
Notebook Suspend/Resume works. The notebook's
sealable Python is now a C-only CPython built for checkpoints, which
the kernel accepts, so a running cell can be suspended and resumed
where it stopped (yurt-ports #242, kernel #3924). The image's regular
python3 is unchanged.
-
No more first-run compile wait after install.
yurt warm precompiles the image's programs; the Linux
installers and yurt pull run it (a cold first
node took 49 s, a warm one 0.7 s).
Kernel
Image
-
Every program is built with Guest SDK 0.0.29 and Rust 1.98.1
(yurt-rust release rust-v1.98.1-0.0.8)
- Node.js 22.23.3-yurt.3 (#239); Gemini CLI stays at 0.64.0
- CPython's
select.epoll is available (#235)
-
SQLite is stock, with no Yurt changes, so it uses
mmap and WAL like on Linux (#234)
-
Every downloaded source is checked against a pinned SHA-256, and
file modes no longer depend on the build machine's umask (#221,
#222)
-
The notebook's sealable CPython is C-only (no zmq, numpy or C++), so
the checkpoint host accepts it; the seal build fails if the kernel
would refuse its output (#242)
- Build fixes for the new SDK (#230, #231, #241)
Node.js
yurt-node release node-v22.23.3-yurt.3, built with Guest SDK 0.0.29.
-
The license text of every bundled component is packaged, including
SpiderMonkey's MPL-2.0 (yurt-node #33)
-
process.on('SIGINT') and other signal handlers run
(#30)
-
util.inspect(err) formats err.stack as V8
does (#29), and AsyncLocalStorage keeps its context
across promise jobs (#31)
-
fetch sends request bodies, follows redirects the way
the Fetch standard does, and checks the body against
Content-Length (#57, #64, #74)
-
TLS refuses renegotiation and handles issuer chains and
dhparam; HTTP honours
--max-http-header-size (#43, #55)
-
fs.cpSync, opendirSync and
fs.watchFile work, without fd leaks (#53)
-
execSync and spawnSync honour
timeout and maxBuffer (#49)
-
require() of an ES module with top-level
await fails with the right error, and dynamic
import() works in plain scripts (#50, #62)
-
process.env is the real C environment, and changing
TZ changes the time zone (#60, #67)
-
Command-line options take values the way Node does (#52)
-
WebAssembly function references keep working across calls (#54)
-
Range checks in Buffer, zlib and crypto can't wrap on 32-bit wasm
(#45, #70, #71)
-
Opt-in startup cache:
YURT_NODE_STENCIL_CACHE keeps
parsed ES modules on disk; gemini --version drops from
2.2 s to 1.4 s. Off by default (#38, #73, #79, #81)
- 24 more Node tests are enabled (#36)
yurt CLI and desktop host
-
yurt warm precompiles the image's programs without a
daemon; the installers and yurt pull run it, and the
daemon warms the caches in the background when it starts (#334,
#337, #342, #343)
-
yurt exec -i never drops a signal, and stops its
command when the client goes away (#339)
-
A sandbox's idle time counts from when it is running (#339)
-
yurt cp -r again over read-only files it copied works
(#338)
-
~/.yurt/sandboxes.json is private to the user (#340)
-
The daemon stays responsive while it warms caches or restores a
checkpoint (#346, #348, #351)
-
Error messages name their cause once, and a failed command no longer
says "request refused as malformed" (#345, #350, #353)
Playground page
-
iPads in landscape, 13″ iPads and Android tablets asking for
the desktop site are treated as tablets and run the Linux shell only
(#211, #219)
-
Phones asking for the desktop site are treated as phones (#215,
#218)
-
A process killed by a real-time signal is named correctly (
SIGRTMIN is 35 in the guest; #212)
-
The snapshot demo's program is rebuilt with Guest SDK 0.0.29 so the
checkpoint host accepts it (#223)
Not in this release
-
A shared
libc.so for ordinary CPython
native extensions (yurt-toolchain #180, #236).
-
The NightMonkey JIT stays out of the image.
Known issues
-
Programs built with Guest SDK 0.0.26 or older can't start threads
(see Highlights). Rebuild them with 0.0.27 or later.
-
Gemini CLI takes a long time to start the first time in the browser
(JS host). Startup under the desktop host is quicker.
-
On iPad Safari the shell-only page can run out of memory after many
commands (playground #200).
playground-2026.10.15-230cfe2.2
2026-10-15 · replaces playground-2026.10.13-68259fc
This train brings Node.js and Gemini CLI 0.64.0 to the playground
image, along with a set of kernel and CLI fixes.
Highlights
-
Node.js is in the image.
/usr/bin/node
is Node v22.23.3 on Yurt (yurt-node release node-v22.23.3-yurt.2),
with Node's own lib/ running on SpiderMonkey over
libuv.
-
Gemini CLI 0.64.0 is in the image as
/usr/bin/gemini. It's a single bundle with no
dependency tree. 0.64.0 fixes the project-registry race that broke
0.35.1 (yurt-ports #217). Auto-update is turned off in
/etc/gemini-cli/settings.json. You need your own Gemini
API key to use it.
-
getconf is in the image. BusyBox has
no getconf, and Node programs call
getconf LONG_BIT.
Kernel
yurt CLI and desktop host
-
yurt exec -i forwards signals and exits when its client
goes away, and -t passes TERM through
(#327).
-
sandboxd actually runs the idle reaper. The new
--sandbox-idle-timeout flag controls it (#326).
-
sandboxes.json is written under a lock, starting from
the latest copy, so concurrent commands no longer lose each other's
changes (#325).
Not in this release
-
The host_checkpoint seal work (kernel #3497, #3498,
#3499) is reverted in this train. It needs checkpoint-typed guests,
which ship with Guest SDK 0.0.27 and later, and it will come back
with that SDK.
-
Guest SDK 0.0.27 is published, but the playground
still uses 0.0.26. 0.0.27 is the first SDK without Rust, and moving
to it is still in progress.
-
Recent yurt-node fixes (yurt-node #29, #31, #33,
#36) aren't in the image yet. They need a new yurt-node release.
Known issues
-
Gemini CLI takes a long time to start the first time in the browser
(JS host). Startup under the desktop host is quicker.
playground-2026.10.13-68259fc
2026-10-13 · replaces playground-2026.10.12-5ddc591.2
Socket and thread fixes in the kernel, and a tablet now gets the Linux
shell only.
Highlights
-
A process that exits while its pthreads are still running no longer
kills the sandbox (#3556)
- On a tablet the page runs the Linux shell only (#195)
Kernel
-
AF_UNIX sockets: names are taken at
bind, with correct
EADDRINUSE, ENOENT and autobind behaviour
(#3562)
-
Loopback TCP:
shutdown(SHUT_WR) delivers EOF to the
peer, and a linger-0 close resets it (#3557)
-
A process ending with live pthreads no longer kills the sandbox
(#3556)
-
The browser host keeps every executor scratch range for reuse
(yurt-playground#203) (#3555)
- CI and test changes
Image
-
No change to the image contents; JavaScript agent-runtime spike work
and documentation (#204, #205, #207, #208, #209, #210)
yurt CLI and desktop host
-
yurt cp keeps the host file's permission bits when
copying in (#324)
Playground page
- A tablet runs the Linux shell only (#195)
- The agent pane says why when no sandbox will start (#202)
-
window.yurt reports the guest's wait status (#205)
-
Guest Workers talk to the coordinator over a direct MessagePort
(#181)
-
Release tooling:
--resume keeps an --image-release train's repos (#201)
playground-2026.10.12-5ddc591.2
2026-10-12 · replaces playground-2026.10.12-5ddc591
A respin of the same kernel and image with a re-pinned desktop host
and CLI, and clearer messages on phones.
Highlights
-
On a phone the page says "not on phones" instead of "failed", and
?start-anyway lets you try anyway (#192)
yurt CLI and desktop host
-
The desktop host and CLI are pinned to train
playground-2026.10.12-5ddc591 (#322)
Playground page
-
Phones get "not on phones" instead of "failed", with
?start-anyway to try anyway (#192)
- The page lists the supported packages (#183)
-
Release tooling:
--resume names the train it means, and
failures print the exact resume command (#193)
playground-2026.10.12-5ddc591
2026-10-12 · replaces playground-2026.09.27-a3198c7
Two weeks of kernel work (filesystem sync, HostFS xattrs,
capabilities, signals, CPU accounting and browser-host memory) on
guest SDK 0.0.26, and new image packages including git, Perl, Go, jq
and gh.
Highlights
-
New image packages: git, Perl 5.44, Go, jq, gh, rtk, gettext tools,
the
xz command and Datasette (#148, #154, #188, #144,
#186, #185, #139, #187, #192)
- CPython 3.14.7 (#165)
-
epoll uses the guest's 16-byte epoll_event, with guest SDK 0.0.26 (#3014, #3538)
-
fsync, fdatasync, syncfs and
sync reach the backing store (#3150)
-
The page shows a reload banner when the browser refuses a process
its memory (#180)
Kernel
-
Guest SDK 0.0.26, with musl's 16-byte
epoll_event
(#3538)
-
epoll uses the guest's 16-byte epoll_event, not a 12-byte wire format (#3014)
-
fsync, fdatasync, syncfs and
sync reach the backing store (#3150), with follow-ups
(#3157, #3180, #3178, #3209, #3276, #3297)
-
HostFS extended attributes, in the native and in-memory backends and
the browser host (#3455, #3457, #3432)
-
HostFS
rmdir works (it was always EROFS)
(#3461)
-
HostFS truncate: no runtime SIGBUS, and the guest gets SIGBUS past
EOF (#3118)
-
Capability sets:
capset, securebits, bounding and
ambient sets, and exec (#3434)
-
chown family is authorized on fsuid/fsgid and CAP_CHOWN, like Linux (#3392); one DAC-override rule (#3433)
-
chmod, chown, truncate and
utimens follow a terminal symlink (#3042)
-
A trailing slash on a non-directory is
ENOTDIR (#3057)
-
/proc/filesystems, with one filesystem-type list behind
mount(2) (#3195)
-
mount(2) accepts the atime, sync, dirsync, mand,
nosymfollow and iversion flags (#3040), enforces MS_REMOUNT read-only (#3049), and honours tmpfs mount
options (#3062)
- The running executable is exposed through procfs (#2967)
-
/proc/cpuinfo reports each host's real Wasm feature set
(#2990)
-
Overlay filesystem: renames of populated directories work (#3187);
renaming a lower-layer directory is
EXDEV (#3211);
base-layer link counts are reported (#3190)
-
Blocking
eventfd, timerfd and splice/tee waits park instead of spinning
(#3055)
-
Signals: a blocked signal stays pending even when ignored (#3027); a
process signal reaches the parked leader (#3011); an ignored or
blocked fault signal is forced to
SIG_DFL (#3041); a
trapping process dies by the matching signal (#3142)
-
CPU accounting:
wait4/waitid report the
child's own rusage (#3054); process CPU timers count exited threads
(#3103); exec keeps discarded threads' CPU time (#3087); fork, spawn
and exec set-up is charged correctly (#3058, #3086, #3075)
-
setitimer no longer expires early when busy (#3148)
-
RLIMIT_CORE defaults to {0,
RLIM_INFINITY}, as on Linux (#3145)
-
getrandom above 1 MiB returns a short count, not E2BIG (#3048)
-
MAP_FIXED over more than 1 MiB of a mapping no longer
returns EFAULT (#3099)
-
pread64/pwrite64 reject a negative offset
before checking the fd (#3322)
-
Sockets: AF_UNIX keeps
SOCK_NONBLOCK/SOCK_CLOEXEC across connect/listen (#3096); UNIX datagram
SO_SNDBUF and whole-message sends (#3349); UDP receiver
overflow drops instead of blocking the sender (#3340); exit closes
host sockets (#3098)
-
Orphans nothing can wait for are released in a sandbox without init
(#3007)
-
One process can use the sandbox's whole memory, and memory is
reported truthfully (#3005)
-
Browser host: guest memories are sized to what each guest needs, not
the 1 GiB budget (#3115, #3001); a refused memory fails exec with
ENOMEM (#3122) and is reported to the page (#3116); a
refused thread TLS block fails pthread_create with
EAGAIN (#3126)
-
Browser host: guest processes and threads start on a pre-started
Worker (#3339), and per-syscall and per-fork host cost is cut
(#3239)
-
Browser host:
execve from a pthread or a shared vfork() child (#3133, #3104); pty reads no longer starve
guest syscalls (#3003); alarms fire correctly (#3056, #3085);
long-lived Workers on Safari (#3108)
-
Native host:
execve while a thread is in vfork(), and vfork from a pthread (#3138); fork
+ exit + wait is about 5x faster (#3238)
-
Native host: a complete host-to-Linux errno table (#3213, #3267),
and broker diagnostics shown as Linux errnos (#3273)
-
JIT mounts: table-slot reservation and wider instruction decoding
(#2995, #2988, #3524); JIT start helpers can re-enter syscalls
(#3334)
-
A missing files helper is named instead of a bare
ENOENT (#3097)
-
yurt commit's disk sync stays out of /dev
and /proc (#3084)
-
Checkpoint and restore fixes (#3251, #3253, #3257, #3305), and
sealed-host executor regions are reused on restore (#3000)
-
Wasm cache memory is bounded and staged modules are reused (#3037)
- OPFS host I/O for the browser host (#3082, #3179)
-
CPython runtime loader and relocation repairs are preserved (#3078)
- CI and test changes
Image
-
New packages: git (#148), Perl 5.44 (#154), Go (#188), jq (#144), gh
(#186), rtk (#185), gettext tools (#139)
- The
xz command (#187)
- Datasette, from upstream (#192)
-
CPython 3.14.7 (#165), with
signal.pthread_kill, sigwaitinfo and sigtimedwait (#160) and more
Linux syscalls enabled (#172)
- SQLite is built thread-safe (#190)
- curl handles IPFS and IPNS URLs (#132)
-
BusyBox
ps prints its column header (#152), and ash
blocks job-control signals across fork (#162)
-
Boot sets
/ to 0755 and /tmp to 1777
(#151)
- CI and build changes
yurt CLI and desktop host
-
yurt explains on a machine's first run that each
program's first start compiles (#306, #314)
-
yurt pull has help, --version carries the
train, and yurt cp names a missing sandbox (#305)
-
yurt cp writes only where the sandbox user could (#304)
-
The daemon removes a sandbox whose create reply reached nobody
(#303)
-
yurt-desktop-host stops on stdin EOF or SIGTERM during
boot (#310)
- CI, build and dependency changes
Playground page
-
A reload banner when the browser refuses a process its memory (#180)
-
Each guest process reserves 256 MiB, not the 1 GiB sandbox budget
(#179)
- Notebook tracebacks start at the user's cell (#158)
-
The agent's model is stored in 64 MiB parts, so it persists in
Safari (#162)
-
The page reaps every process it spawns (#155), runs each exec in its
own session and signals its group (#156), and gives the exec stdin
staging file to the login user (#157)
-
Desktop: the launcher cleans up on signals and runs once per user
(#159); release checksums, a menu icon and
yurt-playground
--version (#160)
- Page text and small UI fixes (#161)
-
The kernel is taken from a pre-built kernel release (#145, #165)
playground-2026.09.27-a3198c7
2026-09-27 · replaces playground-2026.09.22-1617082
A local WebGPU agent pane and the ability to stop a running cell, curl
in the image, and guest SDK 0.0.25.
Highlights
- A local WebGPU agent pane (#143)
-
Stop a running cell, and see what it prints while it runs (#138)
- curl and CA certificates in the image (#125)
Kernel
- Guest SDK 0.0.25 (#2969)
-
rlimit resources 10 to 15 are accepted at Linux's defaults (#2958)
-
The process address space is reported as vsize, so
ps
stops saying SW (#2936)
-
The sandbox user has no password, rather than an empty one (#2935)
-
files.* operations run as the guest helper (#2929)
-
A fork child's GOT TLS relocation is fixed without resetting
inherited TLS (#2946)
-
A write to a readerless session pipe is not clamped (#2940); the
replay ring frees a pipes session's pipe (#2933); SIGPIPE is
restored before a broker command runs (#2943)
- HostFS file writes are sent in capped chunks (#2942)
-
An exited process's thread-host registration is retired (#2957)
-
JIT mounts: generic signatures, guest import bindings and
host-assigned table base (#2954, #2963)
-
Continuous checkpoints: repeatable compaction, lossless decoding and
retained overlay generations (#2930, #2941, #2947)
- kernel.wasm is published as a GitHub Release (#2974)
- CI and test changes
Image
-
curl and CA certificates (#125), with WebSocket protocols enabled
(#131)
-
BusyBox
tar creates archives, not only reads them
(#103)
-
/usr/libexec/yurt-files ships in the image (#109)
-
Rust crate ports: Rustix, filetime and libc 0.2.189, published as
Cargo registry outputs (#107, #106, #127)
-
libc++ is taken from the SDK sysroot when the SDK ships it (#142)
- CI, test and build changes
yurt CLI and desktop host
-
yurt pull playground works with no token and no desktop
app (#279)
-
yurt cp moves files over the 8 MiB frame limit in
pieces (#290)
-
A foreground run takes its sandbox with it when the client is killed
(#283)
-
yurt build installs /usr/libexec/yurt-files into images (#291)
- CI, test, docs and dependency changes
Playground page
- A local WebGPU agent pane (#143)
-
Stop a running cell, and see what it prints while it runs (#138)
- Staging applies the image's directory modes (#141)
- Each install choice has its own accessible name (#139)
- The "another tab" note goes away when that tab closes (#136)
- Every disclosure on the home page is styled (#135)
-
The playground image is published beside the installers (#128)
-
A security policy for reporting boundary issues privately (#127)
- CI changes
playground-2026.09.22-1617082
2026-09-22 · replaces playground-2026.09.21-7eb03a7
Kernel fixes for shared mappings, suspend and pipes on guest SDK
0.0.23, and Intel macOS is dropped.
Highlights
-
Intel macOS is no longer supported: no download, build target or
release asset (#121)
Kernel
- Guest SDK 0.0.22, then 0.0.23 (#2911, #2921)
-
A
MAP_SHARED overlay follows the file it maps when the
file grows (#2924)
- A host-spawned process's fds 0 to 2 are real pipes (#2833)
-
Suspending a sandbox during an exec holds the reply until resume
(#2906)
-
session.close and a blocking sandbox.exec
leave the dispatcher with their command (#2897)
-
Worker threads are joined before sandbox teardown is reported
(#2914)
- A process killed by a trap names the signal (#2922)
- Parked-fork backoff is bounded per drain (#2885, #2870)
-
Fork and seal share one Asyncify continuation (#2926), and
incremental seals avoid a full memory copy (#2923)
-
tty runtime operation numbers are pinned to the ABI contract (#2872)
- CI, test and script changes
Image
- The playground session broker is preserved and verified (#99)
- Linux-musl target metadata is canonicalized (#62)
- Test changes
yurt CLI and desktop host
-
yurt exec -i with piped stdin runs the command on a
pipe session (#277)
- Inline guest files can be staged for sandbox runs (#276)
-
Intel macOS is dropped from the desktop host, CLI and release builds
(#274)
- Test changes
Playground page
-
Desktop: the notebook kernel runs in the page's own host session,
not as a job of the user's shell (#122)
-
Intel macOS is dropped: no download, build target or release asset
(#121)
-
Release tooling: the pin PR is merged after its checks, and
--resume finds it (#120)
playground-2026.09.21-7eb03a7
2026-09-21 · first train
The first release train: kernel, image, desktop host and yurt CLI
built and released together from these revisions.