60197678
docs: the invariants learn the pane era and its sidecar
a73x 2026-08-25 09:10
Commit message
CLAUDE.md
| Old | New | ||
|---|---|---|---|
| @@ -59,12 +59,19 @@ real pty), `wsclient` (browser stand-in), `rawmode`, `delaypipe`, `render`. | |||
| 59 | - **One replay core.** CLI, wasm, and test fixtures all go through `replica.zig`. | 59 | - **One replay core.** CLI, wasm, and test fixtures all go through `replica.zig`. |
| 60 | Do not hand-roll a second applier. | 60 | Do not hand-roll a second applier. |
| 61 | - **Latest wins.** The grid follows the most recently active client. | 61 | - **Latest wins.** The grid follows the most recently active client. |
| 62 | - **Every tile claims its rect.** Attach sends the rect, relayout resends | 62 | - **Every tile claims its rect.** The layout tree (`layout.Tree`) is |
| 63 | it. Focus is client-local and sends nothing on the wire: the keyboard | 63 | client-local, owned by the keyboard thread under `paint_mu`; `relayout` |
| 64 | writes the outgoing tile's `session_release` under `paint_mu`, then | 64 | is the single flatten point that turns it into tile rects. Attach sends |
| 65 | doorbells the old pump (release) and the new (claim). `mux [TARGET]` is a | 65 | the rect, relayout resends it. Focus is client-local and sends nothing |
| 66 | wall of one tile whose rect is the whole terminal — ONE interaction loop, | 66 | on the wire: the keyboard writes the outgoing tile's `session_release` |
| 67 | a tile pump. | 67 | under `paint_mu`, then doorbells the old pump (release) and the new |
| 68 | (claim). `mux [TARGET]` is a wall of one tile whose rect is the whole | ||
| 69 | terminal — ONE interaction loop, a tile pump. | ||
| 70 | - **Resize is gain-only.** `layout.Tree.resize` never shrinks a pane; the | ||
| 71 | shrink keys grow a neighbor at the focus's expense in `wallview.doResize`. | ||
| 72 | - **Rails are painted from `relayout` and tiles cannot reach them.** Every | ||
| 73 | tile clear is span-bounded ECH, never line-wide, so a tile cannot erase | ||
| 74 | a neighbor's cells or a rail. | ||
| 68 | - **`muxa` attaches at 0×0** so an agent never resizes a human's session. | 75 | - **`muxa` attaches at 0×0** so an agent never resizes a human's session. |
| 69 | - **OSC 133 marks are opt-in** (`MUX_SHELL_INTEGRATION=1`); without them `muxa` | 76 | - **OSC 133 marks are opt-in** (`MUX_SHELL_INTEGRATION=1`); without them `muxa` |
| 70 | falls back to `pgid`/`settle` and there is no real exit code. Every `muxa` | 77 | falls back to `pgid`/`settle` and there is no real exit code. Every `muxa` |
| @@ -82,6 +89,18 @@ real pty), `wsclient` (browser stand-in), `rawmode`, `delaypipe`, `render`. | |||
| 82 | on a successful dial, so a refused attach cannot strand a line — which is why | 89 | on a successful dial, so a refused attach cannot strand a line — which is why |
| 83 | there is no `unrecordTile`. `--via` and `muxa` record nothing; `mux wall`'s | 90 | there is no `unrecordTile`. `--via` and `muxa` record nothing; `mux wall`'s |
| 84 | argv is a view, not an attach. | 91 | argv is a view, not an attach. |
| 92 | - **The layout sidecar is derived convenience, not authored intent.** | ||
| 93 | `$XDG_STATE_HOME/mux/layout` stores the pane tree on last detach, hydrated | ||
| 94 | walls only (no-argv `mux wall` or post-fold; argv walls and `mux TARGET` | ||
| 95 | never write). Restore is verbatim; the aspect rule applies only when no | ||
| 96 | saved tree exists. Healing is per-leaf against wall drift. `wall.load` | ||
| 97 | stays strict (a wall line is authored intent) while the sidecar is | ||
| 98 | lenient — every failure degrades silently to the default cut. The | ||
| 99 | asymmetry is deliberate: a bad wall line is a user's mistake to fix; a | ||
| 100 | stale layout is a convenience to forget. | ||
| 101 | - **Detach is a goodbye, not a tear.** A pump that has sent its detach frame | ||
| 102 | never redials — redial checks `detach_ack` — so the daemon's close after | ||
| 103 | a detach is final, not a network event to recover from. | ||
| 85 | - No socket stealing: `muxd run` refuses a path another daemon owns. | 104 | - No socket stealing: `muxd run` refuses a path another daemon owns. |
| 86 | 105 | ||
| 87 | ## Working rules | 106 | ## Working rules |
README.md
| Old | New | ||
|---|---|---|---|
| @@ -56,7 +56,8 @@ shell, laid out beside or below the focus. The wall places tiles side by | |||
| 56 | side when the terminal is at least twice as wide as it is tall, and stacks | 56 | side when the terminal is at least twice as wide as it is tall, and stacks |
| 57 | them otherwise. Fullscreen is a layout where the focused pane takes the | 57 | them otherwise. Fullscreen is a layout where the focused pane takes the |
| 58 | whole terminal; resize mode trades cells between the focus and its | 58 | whole terminal; resize mode trades cells between the focus and its |
| 59 | neighbors, one per keystroke. | 59 | neighbors, one per keystroke. The layout survives detach and comes back |
| 60 | the next time the wall does — `mux wall`, or `Ctrl-\ w` from a plain `mux`. | ||
| 60 | 61 | ||
| 61 | The focused tile has the terminal, and only the prefix is held back: | 62 | The focused tile has the terminal, and only the prefix is held back: |
| 62 | 63 | ||