- five stories under docs/stories/runtime-v2/: 1 streaming subprocess (42's follow-up; five forks incl. the mailbox-cap collision), 2 PTY, 3 signals-as-events (signalfd lean), 4 termios adoption, 5 SCM_RIGHTS fd passing; 00-story states the arc — the plane learned sockets in 8/11/35, files in 6, this adds processes/terminals/signals - build order 1 -> 2 -> 3; 4 and 5 startable alone; all readiness: refine, brainstormed on demand - board: Five tracks; "▸ runtime-v2" pending section; wmux section now points at it; graph section 6 nodes carry runtime-v2 numbers + links - wmux stories re-reference the track; prefix `rt2` claimed - linkcheck: 0 broken Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> (cherry picked from commit e0451cb4889bb3d03429c0276d03c090269a5ced)
5.5 KiB
| track | iteration | was_language_iteration | status | readiness |
|---|---|---|---|---|
| wmux | 1 | 43 | pending | refine |
wmux 1 — the terminal multiplexer, writeonce's tmux alternative
Part of Story — wmux, the writeonce terminal multiplexer. The product the tmux study scoped and iteration 42 unblocked first — a terminal multiplexer in pure
.wo, driving every remaining native-workload gap into the open the way log-watcher drove the language and chat drove the actors.Why this workload. tmux is ~112k lines of C with two dependencies, but its multiplexer kernel is ~27k and a third of the rest is a hand-rolled command/format/options DSL that dissolves into writeonce language features. Its architecture — one server owning sessions and PTYs, thin clients over a unix socket — is the actor tree writeonce already has, with the concurrency written down instead of locked. And wmux can give the one demo tmux cannot: sessions, layout and scrollback in
durable: truetables, so reattaching after a server restart replays everything from the WAL.
The dependency remap (graph section 6 carries the edges)
Iteration 42 (bounded subprocess) is DONE and was the first domino. The
runtime seams now live as the runtime-v2/
track, each brainstormed on demand — the order below is the build order:
- Streaming subprocess (runtime-v2 1) — 42's named follow-up: a long-lived child whose output arrives as mailbox messages in the owning actor; stdin transport. The registry/pidfd/cap machinery is already built.
- PTY allocation (runtime-v2 2) —
openpty, the child on the slave as its controlling terminal, resize
ioctls. Extends the same
wo_childslot;.dev/reference/tmuxspawn.c/compat/fdforkpty.care the reading. - Signals as events (runtime-v2 3) — SIGWINCH (and SIGCHLD beyond the pidfd path) as mailbox messages; the seam iteration 42 deliberately deferred to its real consumer. This is that consumer.
- termios adoption (runtime-v2 4) — the CLIENT puts its own tty into raw mode and restores it on exit. Creating terminals is gap 2; adopting one you were given is this. Startable alone.
- SCM_RIGHTS fd passing (runtime-v2 5) — the client hands its tty fd to the server over the unix socket; detach/attach is built on it. Startable alone.
- VTE grid in pure
.wo— the escape parser and cell grid, pinned by replaying recorded sessions against the referenceinput.c/grid.cbehaviour. Needs unicode width tables in the stdlib. This one is wmux's own, not runtime work. - wmux itself — server (session/window/pane actors, durable tables), client (thin: raw mode, fd handover, restore), the gate.
Not on the critical path, recorded: time.mono's return (status-line
clock, repaint pacing — v2), and the terminfo fork below.
Info — the forks (open; why this is refine)
- Terminfo. Answer "what does the client's terminal speak" by
parsing the compiled terminfo database in pure
.wo(a documented binary format — a parser, not a linked library) versus emitting a fixed xterm-256color profile and refusing exotic terminals by name. The tmux study leans fixed-first with a named refusal; confirm at brainstorm. - v1 surface. Sessions + one window each, no split panes (tmux's
layout.cis 2,022 lines of split-tree bookkeeping) versus splits in v1. Lean: no splits — detach/attach + durability IS the product's proof; splits are v2. - Scrollback residency. Scrollback rows in a
resident: keystable (the 120 GB-audit-table machinery, databasev2 2) versus resident with a row cap. Real fork: scrollback is append-mostly and read-rarely — keys-resident's exact profile. - Command surface. tmux's 63
cmd-*.c+ yacc grammar versus wmux taking commands as... writeonce source? a tiny line protocol? The DSL third of tmux should dissolve, not be rebuilt — decide what into. - Verb shape of the streaming form (gap 1's own brainstorm): one
proc.spawnreturning an actor-addressable handle, versus spawn options onproc.run_dl.
Acceptance sketch (firmed when the last gap lands)
- Given a wmux server with one session running a shell, when the client detaches and its process is killed, then the shell keeps running and a NEW client attaches from a different terminal with the screen intact.
- Given a server stopped with SIGTERM and restarted against the same
WO_DATA, when a client reattaches, then sessions, layout and scrollback are replayed from the WAL — the beyond-tmux leg. - Given SIGTERM with live shells, then every child is gone before exit (iteration 40 + 42's guarantee, now with PTYs).
- Given a
vttest/asciinema replay corpus, then the grid matches the reference implementation's final state (stage B's pin, kept green). - Gate:
scripts/wmux-accept.sh+just wmux, log to/tmp/wmux.log.
Consumers and siblings
The alacritty study's stages A–C become wmux's gaps 1–6 verbatim; its stage D (Wayland shm terminal) reuses gaps 5 and 6. The zen study's CDP driver shares gap 1 only. skillhost (28) consumes gap 1's stdin transport. Every remaining item in 28's old fan-out except fs-metadata and FFI-vs-out-of-process now has wmux as its driving workload.