Skip to content

User-controlled compositor

Milestone 1 outcome: the operator owns views. A view is a named camera over seats. The app decides the recipe (one desk, a ticket workshop, a crew row). The multiplexer does not.

Views are not windows

tmux will not tile four windows for one client. It will not show the same pane in two places. join-pane moves a seat into a split and undoes window-per-role.

So a live tmux quadrant is not a view. It is a temporary workshop.

A view is data on a tree node:

tree (source of truth)          view (composed)
ticket 271                      OWNER workshop
  ● ticket-owner      ─┐        ┌ T.O. snapshot  ┬ implementer ┐
  ● commit-owner      ─┼──────► │                ├ auditor     │
  ● auditor           ─┘        └────────────────┴─────────────┘

Click a cell selects that seat. Enter / double-click opens it full screen. The camera refreshes; the agents do not change size.

Three layers

Layer What it is When
Snapshot mosaic capture-pane (with colours) laid out by the recipe browse, glance, tablet via the embedded TUI
Interactive attach one client, one window, client-sized Enter / go
Materialize join-pane into a scratch window, sized to the recipe a human who wants a real split for an hour, then break apart

Materialize is never the source of truth.

Attach cannot match view sizes

A tmux window has one size.

If the app attaches a client into a view cell of 90×20:

  • window-size smallest / latest — the real agent shrinks. Every other viewer sees the postage stamp. Claude and Codex reflow.
  • resize-window -x 90 -y 20 — same shrink, sticky until undone.
  • window-size largest — the agent stays big; the view shows a crop, not a scaled workshop.

There is no scale-to-fit. TUIs are a cell grid, not pixels.

Rule:

browse  = snapshots, view-sized, agents untouched
enter   = attach one window, client-sized
workshop = optional materialize, then tear down

Do not attach four live windows into a view and push those sizes onto them.

Nothing better as a drop-in multiplexer

Zellij, WezTerm mux, and Screen share the same ontology: one pane, one parent, one size. Zellij still sizes everyone to the smallest client.

Zellij's read-only watch is the only interesting step: an observer that must not type or resize. It still does not give a view-sized live workshop.

A TUI cannot be two grids at once. “Look small here, run large there” is a display problem.

The primitive that would be right is a seat server, not another mux:

agent  →  PTY + retained cell buffer  (the seat owns its size)
                ├─ interactive client   1:1 cells, may resize
                └─ observers            snapshot / crop / pixel-scale
                                        cannot resize

Browse and mosaics are observers. Enter is the one interactive client. Mosaic cells never SIGWINCH the agent.

Until that server exists, this app's snapshots are the observer. tmux-ws is the interactive attach. Using tmux as a compositor is the mistake; using it as a process host is fine.

Embedding in a home session

tmux-ws is already a real tmux client (tmux attach -t <session> over a PTY). It does not need its own factory tree if this TUI is a standing window in a home session (for example 0-factory):

  • Tablet: attach to that session, walk the tree, Enter moves that client to the seat. The TUI process stays up (--serve). Back = select the home session again.
  • Laptop: F1 switches to the same window, not a second popup.
  • Go must name the interacting client (switch-client -c …).
  • A popup that quits after go is the wrong embed.

Touch must reach the TUI as mouse events or the tablet can see the tree and not drive it. That is a camera concern, not a reason to invent a second factory model.

What the current prototype already is

The binary in this repository is the browse camera:

  • Tree projected from live window names (best-effort parser).
  • Coloured snapshot of the selected pane, about once a second.
  • Enter / double-click jumps the attached client.
  • It does not resize agents. It does not join panes. It does not claim to be a live mosaic.