Add herdr as an alternative multiplexer backend - #237
Conversation
herdr is a terminal multiplexer built for running AI agents. This adds it as a Multiplexer implementation alongside tmux, WezTerm, Zellij and Kitty. HerdrBackend drives herdr through its JSON CLI rather than a daemon socket, so it follows the WezTerm backend's shape and carries no tmux dependency. Backend detection checks $HERDR_PANE_ID before $TMUX, letting workmux select herdr on its own when run inside it; $WORKMUX_BACKEND=herdr still overrides. The workflow modules gain the backend-specific worktree and workspace plumbing the existing backends already have.
|
Thanks. What problem does this solve if herdr has its own worktree commands? It doesn't have worktree lifecycle management (hooks, symlinking etc.) or? |
|
It is not really about herdr's worktree commands. Without this backend workmux does not run under herdr at all. Detection falls through to tmux, tmux is not running, and the command fails. So a workmux user who moves to herdr today has to either abandon workmux or run tmux inside herdr, which defeats the point of herdr. That is the problem this solves. You are right that some lifecycle is reachable in herdr through plugins: worktree.created listeners cover post-create hooks and file copying, and several published plugins do exactly that. What is not covered is a blocking pre-remove hook, since herdr's events are fire-and-forget and fire after the worktree is already gone, plus merge, rebase, rename and resurrect. The worktree delegation is an implementation detail. herdr tracks the workspace to worktree association itself, so creating the worktree separately and then opening a workspace leaves herdr unaware the two are related. For what it is worth, herdr's own compare page describes worktree and diff review flow as "pairs with it". On maintenance cost, every new trait method defaults to opting out, so the existing backends are untouched. |
|
I understood none of that. Why does one need to run workmux if herdr has worktree support? |
Summary
Adds herdr as an alternative multiplexer backend alongside WezTerm, kitty and Zellij, closing #195. herdr is an agent multiplexer built for running AI coding agents, so the overlap with workmux is close to exact.
Unlike the other backends, herdr manages git worktrees itself.
workmux addandworkmux removetherefore delegate toherdr worktree createandherdr worktree removerather than running git directly. That difference is expressed as acapability predicate on the
Multiplexertrait, not as a check on the backend name, so the workflow layer stays backend neutral and the other backends are untouched.I use this daily, which is how the label and deferred cleanup edge cases below were found.
Changes
HerdrBackendimplementsMultiplexerover herdr's JSON CLI. It holds no session state and needs no daemon socket, so it follows the WezTerm backend's shape.supports_atomic_worktree_workspace,create_worktree_and_workspace,remove_worktree_and_workspace,ensure_worktree_workspaceandshell_remove_worktree_and_workspace_cmd. Every one has a default that opts out, so existing backends see no behavior change.$HERDR_PANE_IDafter$TMUX. herdr exports that variable into every descendant process, so a tmux server started inside a herdr pane sets both and the inner multiplexer has to win.$WORKMUX_BACKEND=herdrstill overrides.errorobject instead ofresult. Envelope decoding keeps the two cases distinct, since treating a missingresultas an empty payload would turn every backend failure into "nothing there" and silently drop live agents during reconciliation.workmux removeruns from inside the workspace being removed, the backend supplies the command for the deferred script instead of the generic rename-to-trash and prune sequence.$HERDR_BIN_PATHand$HERDR_SOCKET_PATH.tests/conftest.pyscrubsHERDR_PANE_IDfrom the baseMuxEnvironment. Without it, running the suite inside a herdr session drives the developer's live session and creates real worktrees.Testing
cargo test --bin workmuxorigin/maincheckout (sevenTestSetupNoPrompttimeouts and one flaky dry run test), so they are environmental to my machine and unrelated to this change.cargo fmt --checkandcargo clippy --all-targetsclean, no new diagnostics.--target-nameset, where the workspace label diverges from the work-tree directory name; remove run from inside the workspace being removed, which takes the deferred script path; and reopening a worktree whose workspace had been closed.CI installs no herdr, so the unit tests are the real gate there. The integration job is unaffected.