Skip to content

Add herdr as an alternative multiplexer backend - #237

Open
GregoryTomy wants to merge 1 commit into
raine:mainfrom
GregoryTomy:herdr-backend
Open

Add herdr as an alternative multiplexer backend#237
GregoryTomy wants to merge 1 commit into
raine:mainfrom
GregoryTomy:herdr-backend

Conversation

@GregoryTomy

Copy link
Copy Markdown

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 add and workmux remove therefore delegate to herdr worktree create and herdr worktree remove rather than running git directly. That difference is expressed as a
capability predicate on the Multiplexer trait, 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

  • HerdrBackend implements Multiplexer over herdr's JSON CLI. It holds no session state and needs no daemon socket, so it follows the WezTerm backend's shape.
  • New trait hooks for backends that own their worktrees: supports_atomic_worktree_workspace, create_worktree_and_workspace, remove_worktree_and_workspace, ensure_worktree_workspace and shell_remove_worktree_and_workspace_cmd. Every one has a default that opts out, so existing backends see no behavior change.
  • Backend detection checks $HERDR_PANE_ID after $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=herdr still overrides.
  • herdr reports failures in band, exiting 0 with an error object instead of result. Envelope decoding keeps the two cases distinct, since treating a missing result as an empty payload would turn every backend failure into "nothing there" and silently drop live agents during reconciliation.
  • Worktree removal is atomic where it can be. When workmux remove runs 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.
  • Docs: new guide page, nav entry, README entries, and the previously undocumented $HERDR_BIN_PATH and $HERDR_SOCKET_PATH.
  • tests/conftest.py scrubs HERDR_PANE_ID from the base MuxEnvironment. Without it, running the suite inside a herdr session drives the developer's live session and creates real worktrees.

Testing

  • cargo test --bin workmux
  • Integration suite: 450 passing. Eight failures reproduce identically on a clean origin/main checkout (seven TestSetupNoPrompt timeouts and one flaky dry run test), so they are environmental to my machine and unrelated to this change.
  • cargo fmt --check and cargo clippy --all-targets clean, no new diagnostics.
  • Exercised by hand against a live herdr session: add then remove; add with --target-name set, 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.

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.
@raine

raine commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Thanks. What problem does this solve if herdr has its own worktree commands? It doesn't have worktree lifecycle management (hooks, symlinking etc.) or?

@GregoryTomy

Copy link
Copy Markdown
Author

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.

@raine

raine commented Aug 16, 2026

Copy link
Copy Markdown
Owner

I understood none of that. Why does one need to run workmux if herdr has worktree support?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants