Cluster Verbs
Cluster verbs
The user's number one priority is managing several hosts: "I have ... four [hosts] in a cluster ... two main keyboards". They want convenience functions like "bring everything to the DELL" and "make the Dell main", in both the CLI and the app.
The setup
| Machine | OS | Keyboard | Role |
|---|---|---|---|
| mini (this Mac) | macOS | yes | drives the others; Dell (main) + U32 (elsewhere) |
| arts-mini | macOS | yes | drives the others; probably on the U32's other input |
| Archie | Linux / Hyprland | no | visited (packages/host-linux) |
| air | macOS (MacBook Air) | no | visited |
Both keyboards are on Macs. So every Mac sends and receives visits (both
sides exist in the app now: VisitController sends, MacVisitHost receives),
and Archie only receives. Lattices hosts are in ~/.lattices/hosts.json
(lats hosts, bin/hosts.ts, callHost). Visit pairing is per direction:
see docs/visit.md.
1. One CLI for every host
lats @<host> <command...>runs a lats command against another host's daemon.lats @archie display listis the same as runninglats display listthere. Route through the host's daemon API (callHost), not ssh. Any subcommand that's a thin wrapper over a daemon call should work remotely; the rest should say they're local-only.@localis this machine.lats machineslists every machine on one screen. It merges hosts.json, visit pairings and the local machine. For each it shows: reachable, Lattices version/commit (host.describealready reports build identity on Linux; add it on the Mac if it's missing), OS, display count, whether it's paired to receive visits from here, and where it's placed.--jsontoo.
2. Convenience verbs
Short commands for the things the user does by hand, each a daemon method so
it works with @host and from the app. They build on what exists: don't
duplicate display.gather, visit.main, etc. Alias or compose them.
lats bring <display>: every window from every other display onto this one (display.gatherfor each). "bring everything to the DELL" =lats bring dell.lats bring --undorestores.lats main <display>: make it the main display (the existingvisit.main15s trial).--keepkeeps it at once.lats elsewhere <display> [machine]/lats here <display>: top-level aliases of thevisitones.lats visit <machine>: start a visit now without pushing against an edge (enter at the middle of its touching span).lats homeends it (alias ofmouse home).- Displays are named by number or by any part of their name, case-insensitive
(
dell,u32), everywhere a display is taken. Use the same resolver asdisplay.gather.
Add them to bin/cli/usage.ts in one "Machines and displays" group, and to
docs/api.md.
3. The app
- Machines page:
- Per display: Bring everything here, Make main, Elsewhere.
- Per machine: Visit now; reachability with version/commit, flagged when it's behind this Mac's; Open (the existing still/live view).
- Keep row geometry equal; coral only for live state; no explainer copy.
- Command bar (
Core/Overlays/UnifiedCommandBar): the same verbs as commands, e.g. "Bring everything to DELL", "Make U32 main", "Visit archie", generated from the current displays and machines. - Menu bar: a Machines submenu with Visit
for each paired one, and Bring everything to for each display.
Out of scope
Deploying to or configuring arts-mini, air or Archie. I'll do that with the user. Don't ssh anywhere and make no calls to real hosts.
Constraints
- Work in this worktree (
feat/machines-tab, pushed; don't push). - Don't launch, quit or restart the running app.
- No real display, pairing, arming or window changes while developing; tests use
mocks/injection (see the existing
MachinesTests,tests/machines-cli.test.ts). cd apps/mac && swift build -c release, Swift tests, bun tests andbun run check:typespass.- Gitmoji on every commit, small focused commits, no co-author lines or footers. Bun only.
- Report to
~/.cache/cluster-verbs-report.md.