Repository navigation
feat: add herdr as an alternative multiplexer backend - #304
Open
rubenfiszel wants to merge 4 commits into
Open
rubenfiszel wants to merge 4 commits into
rubenfiszel wants to merge 4 commits into
Conversation
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
webmux | b0b508a | Commit Preview URL Branch Preview URL |
Aug 11 2026, 07:33 AM |
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…SION Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rubenfiszel
marked this pull request as ready for review
August 17, 2026 16:38
|
Hello, I would like to know more about the limitation you're referring to: "Not supported in herdr mode: the web terminal" If the shown terminals are snapshots only, what does it mean practically? Your webmux become a mux without the web?
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds herdr as an alternative to tmux for backing a project's panes, plus a
webmux multiplexercommand to move an existing project between the two. Default staystmux; projects that don't opt in are unaffected.Verified end to end
Against live herdr 0.8.0 / protocol 19, in isolated named sessions:
Worktree lifecycle on herdr —
webmux addproduced one workspace, one tab, 2 panes matching the profile, withpane.process_infoconfirmingclaudein the agent pane andzshin the shell pane.list→open,close→ tab removed,open→ recreated, and a second worktree added a second tab to the same workspace.Switching, both directions — on a throwaway repo:
…and
webmux multiplexer tmuxput it back exactly.Switching is a rebuild, not a handoff
A pane cannot be moved between multiplexers — the PTY belongs to whichever server spawned it, and neither exposes a way to transfer one. So the switch closes each open worktree on the outgoing multiplexer, flips the config, and re-opens on the incoming one.
Survives: which worktrees were open, and agent conversations — reopening relaunches in resume mode (
claude --continue).Does not: scrollback, in-flight agent turns, and every running process. Profile
commandpanes (dev servers, watchers) restart from scratch, which is expensive on a large project.The ordering is load-bearing. Closing happens strictly before the config flips, and a close failure aborts the switch with the config untouched. Otherwise a half-switched project strands windows in a multiplexer webmux can no longer reach — unrecoverable except by hand. Two tests pin this:
persistmust come after the lastclose, and a failed close must produce no persist and no reopen.The choice is written to
.webmux.local.yaml— which multiplexer is running is a per-machine fact, not something a project commits for everyone.What changed
SessionGateway(backend/src/adapters/session-gateway.ts) — the oldTmuxGateway, renamed and made multiplexer-agnostic. Two cleanups came with it:setWindowOptionis gone from the interface —session-serviceno longer pokespane-base-index/automatic-rename/allow-rename;BunTmuxGateway.createWindowapplies them itself. A newfocusWindowreplaces the CLI's hand-rolledtmux select-window.HerdrGateway(backend/src/adapters/herdr.ts) — maps session→workspace, window→tab, pane→pane, joined by label rather than id, because webmux persists names and herdr ids don't survive a restart.multiplexer-switch-service.ts— the switch orchestration, with IO injected so the ordering guarantees are unit-testable.herdr 0.8.0 quirks this works around
The socket API accepts more parameters than it honours. Each was found by running it, and three only surfaced once more than one tab existed:
events.subscribeis long-lived.pingreportsdetached_server_daemon: false; everything else returnsserver_not_running. Unliketmux start-server,ensureServer()spawns and detachesherdr serveritself, then polls.pane.listignorestab_id/tab/workspace_idand returns every pane in the session. The adapter filters by each pane's owntab_id— without it, pane index 0 of a worktree resolves into a different tab.pane.splitignorespane_idand splits whatever is focused. The adapter focuses the anchor first and restores prior focus, preserving tmux's detachedsplit-window -dbehaviour for parked panes.pane.swapneedssource_pane_id/target_pane_id— a shape the CLI doesn't expose, so the adapter uses the socket directly. This is what lets the existing parked-pane tab system work unchanged.pane.send_textandpane.readdo honourpane_id.EXPECTED_PROTOCOLis pinned and a mismatch logs a warning, since herdr is pre-1.0.Not supported in herdr mode: the web terminal
A real limitation, not an oversight. The browser terminal attaches a tmux grouped session (
new-session -t+window-size latest) so each tab gets an independently-sized view of a shared window. herdr has no equivalent: no method accepts rows/cols (panes live on a server-side virtual screen), andpane.readis a snapshot, not an incremental stream. Attaching now returns an explicit error pointing at your own terminal. Everything else — worktree lifecycle, dashboard, git state, PRs, Linear, conversations — is unaffected.Reviewer notes
ProjectManager.reload(prefix)if wanted.bin/is not covered by any tsconfig and has never been typechecked. I checked it with an ad-hoc config while working: 10 pre-existing errors, unchanged by this PR (verified by stashing). Worth a follow-up; out of scope here.Tests
778 pass, 0 failacross backend + bin + api-contract (738 baseline + 40 new: 24HerdrGatewaytests against a stub socket reproducing the quirks above, 8 switch-ordering tests, 4 CLI tests, 4 misc). Backend typecheck andsvelte-checkclean. Frontend's 35 test failures are the pre-existinglocalStorage/jsdom baseline — identical with these changes stashed.Docs:
docs/herdr.md.🤖 Generated with Claude Code