d7159783
docs: roadmap banner + the home-screen section; handoff marked historical
a73x 2026-08-20 08:28
Commit message
docs/handoff.md
| Old | New | ||
|---|---|---|---|
| @@ -1,8 +1,14 @@ | |||
| 1 | # Handoff: Linux-only multiplexer prototype | 1 | # Handoff: Linux-only multiplexer prototype |
| 2 | 2 | ||
| 3 | **Status:** design handoff, no code written yet | 3 | **Status:** HISTORICAL — the design handoff as written, before any code. |
| 4 | **Audience:** whoever picks up implementation | 4 | Kept unedited on purpose: what it got wrong is the record. M1–M5 below all |
| 5 | **Scope:** Linux only. No macOS, no iOS, no web, no network. | 5 | cleared; everything it declares out of scope (network, auth, TLS, |
| 6 | prediction, web) shipped anyway, and where it guessed (GPU/GTK rendering, | ||
| 7 | msgpack, `$XDG_RUNTIME_DIR/muxd.sock`, systemd socket activation) the built | ||
| 8 | thing differs. For what mux is now: `README.md`. For how each of those calls | ||
| 9 | was actually made and measured: `docs/decisions.md`. | ||
| 10 | **Audience:** whoever wants the original reasoning. | ||
| 11 | **Scope (as stated then):** Linux only. No macOS, no iOS, no web, no network. | ||
| 6 | 12 | ||
| 7 | --- | 13 | --- |
| 8 | 14 | ||
docs/roadmap.md
| Old | New | ||
|---|---|---|---|
| @@ -1,12 +1,16 @@ | |||
| 1 | # Roadmap | 1 | # Roadmap |
| 2 | 2 | ||
| 3 | > This file is the ranked queue as of 2026-08-16 and has not moved since; | ||
| 4 | > the tracker is the live order and `decisions.md` is current. Sections | ||
| 5 | > below marked complete are accurate; the ranking is not. | ||
| 6 | |||
| 3 | The forward view, one item per line, ranked. History and evidence live in | 7 | The forward view, one item per line, ranked. History and evidence live in |
| 4 | `decisions.md` — every item here points back at its entry there. Update | 8 | `decisions.md` — every item here points back at its entry there. Update |
| 5 | this file at each milestone close and whenever the queue reorders; the | 9 | this file at each milestone close and whenever the queue reorders; the |
| 6 | queue's order is set by the user, not by this file. | 10 | queue's order is set by the user, not by this file. |
| 7 | 11 | ||
| 8 | **Now:** M1–M15 and M17 complete, plus the agent surface; published as a | 12 | **Now:** M1–M18 complete, plus the agent surface and the wall; published as |
| 9 | Linux tarball, tagged through `v0.0.1-5`; in | 13 | a Linux tarball, tagged through `v0.0.1-10`; in |
| 10 | field trial on real VMs, and the trial is now producing the queue. | 14 | field trial on real VMs, and the trial is now producing the queue. |
| 11 | Trial feedback outranks everything below — what actually hurts in use is | 15 | Trial feedback outranks everything below — what actually hurts in use is |
| 12 | better data than any of this ranking, and the proof is that the three | 16 | better data than any of this ranking, and the proof is that the three |
| @@ -404,6 +408,56 @@ that understood the name can produce. | |||
| 404 | the M18 block drives it by name and asserts it returns one session's | 408 | the M18 block drives it by name and asserts it returns one session's |
| 405 | grid and not its neighbour's. `--diff-since` is still owed. | 409 | grid and not its neighbour's. `--diff-since` is still owed. |
| 406 | 410 | ||
| 411 | ## The wall is the home screen — complete | ||
| 412 | |||
| 413 | Shipped 2026-08-18..20 (the runtime wall, the wheel, then `f9e45eb..180db14`). | ||
| 414 | `mux [TARGET]` is now a wall of one tile entered zoomed, and `mux wall` is | ||
| 415 | the same program entered on the wall. There is **one interaction loop in the | ||
| 416 | tree, and it is a tile pump** — `client.zig`'s session loop is gone. | ||
| 417 | |||
| 418 | **Zoom is a lens, not a spawn.** An unzoomed tile claims nothing; zooming | ||
| 419 | resizes that tile's existing connection from 0×0 to the terminal and starts | ||
| 420 | forwarding keystrokes down it, so the client that types is a full-size one | ||
| 421 | claiming under latest-wins like any other. Nothing is dialled, no frame was | ||
| 422 | added, and `server.zig` did not change by one line. Demote is client-local | ||
| 423 | and sends nothing: a 0×0 "relinquish" would be refused by `applySize` | ||
| 424 | anyway, and a tile that is never active again claims nothing under | ||
| 425 | latest-wins. Moving the zoom is therefore a repaint, not a reconnect — every | ||
| 426 | tile's pump keeps running, so every replica is hot and `Ctrl-\` `n`/`p`/`l` | ||
| 427 | land instantly. | ||
| 428 | |||
| 429 | **The wall file became attach history.** Any attach that claims the grid | ||
| 430 | records its own tile, and the seam is inside the pump rather than in | ||
| 431 | `mux_main` — the chord switches re-dial without ever returning to `main`, so | ||
| 432 | a seam up there would have recorded the session you started at and none of | ||
| 433 | the ones you visited. It fires on the first STATE, not on a successful dial: | ||
| 434 | a dial that comes up can still be refused, and a refusal that had already | ||
| 435 | written its line would strand a tile naming a session that never existed. | ||
| 436 | That is why nothing ever needs to un-record. `muxa` and `--via` record | ||
| 437 | nothing; `mux wall`'s argv is a view, not an attach; `muxweb`'s argv ADDS | ||
| 438 | rather than replaces, because the file stopped being "the last wall muxweb | ||
| 439 | was told to show" the moment attaches started writing to it. Forgetting | ||
| 440 | stays explicit: the page's `×`, the wall's `x`, `mux wall rm`. | ||
| 441 | |||
| 442 | **The wheel, and who owns the mouse.** Spinning the wheel used to walk the | ||
| 443 | shell's history, because nothing in mux read the wheel at all: a terminal | ||
| 444 | asked for no mouse reporting answers a notch on the alternate screen by | ||
| 445 | synthesising arrow keys (DEC 1007), and those went to the pty as input. The | ||
| 446 | client now asks for real wheel events (1000 in 1006) and spends them on the | ||
| 447 | scrollback it already had — asking is also what stops the synthesis, so one | ||
| 448 | change removes symptom and cause. An application that wants the mouse still | ||
| 449 | gets every byte of it. | ||
| 450 | |||
| 451 | **What the convergence had to invent.** A session that ends under the zoom | ||
| 452 | ends `mux` with the shell's exit code when it was the wall's only tile — `mux` | ||
| 453 | is what people put in scripts — and drops to the wall when it was not, | ||
| 454 | landing on `[exited]` beside the survivors. `w` unzooms and `d` detaches and | ||
| 455 | leaves; they were the same key while the zoom was still a child-spawn's | ||
| 456 | replacement, and are not any more. `Transport.adopt` carries the dialled | ||
| 457 | connection from the main thread to the pump, legal only while the out-queue | ||
| 458 | is empty — the one moment between `open` and the first frame, asserted | ||
| 459 | because there is no other. | ||
| 460 | |||
| 407 | ## Side-channel passthrough — complete | 461 | ## Side-channel passthrough — complete |
| 408 | 462 | ||
| 409 | Shipped 2026-08-16. The three discovery issues are now accounted for: | 463 | Shipped 2026-08-16. The three discovery issues are now accounted for: |
| @@ -589,7 +643,10 @@ next one that arrives outranks all of it. | |||
| 589 | multiplexed inside ONE connection, which needs QUIC stream surgery | 643 | multiplexed inside ONE connection, which needs QUIC stream surgery |
| 590 | the M18 design deliberately refused (a connection IS a session). | 644 | the M18 design deliberately refused (a connection IS a session). |
| 591 | Worth doing only if the connection count per host ever becomes the | 645 | Worth doing only if the connection count per host ever becomes the |
| 592 | cost, which on a four-tile wall it is not. | 646 | cost. The wall is now unbounded attach history rather than a fixed |
| 647 | handful of tiles, so that count is whatever a user's history grew to — | ||
| 648 | the old "a wall is four tiles, so who cares" argument is dead, and | ||
| 649 | nothing has replaced it with a measurement. Measure before building. | ||
| 593 | 9. **Scrollback retention tuning** — policy decided (engine-native 10k | 650 | 9. **Scrollback retention tuning** — policy decided (engine-native 10k |
| 594 | ring); making the limit configurable is what remains, and nobody has | 651 | ring); making the limit configurable is what remains, and nobody has |
| 595 | hit the ceiling. | 652 | hit the ceiling. |