Skip to content

claude: --mux herdr runs Claude in herdr instead of tmux - #1233

Merged
cdalar merged 1 commit into
mainfrom
feat/claude-mux-herdr
Oct 23, 2026
Merged

cdalar merged 1 commit into
mainfrom
feat/claude-mux-herdr

Conversation

@cdalar

@cdalar cdalar commented Oct 23, 2026

Copy link
Copy Markdown
Owner

What

Ports boxctl's --mux to onctl claude. tmux stays the default; --mux herdr (or ONCTL_MUX=herdr) runs Claude in herdr instead, installed on the box the first time. One herdr server per box, one workspace per session labeled with the session's name (claude, claude-<task>), so an attached herdr shows every task on the box with what its Claude is doing, and onctl claude ls shows herdr's status (working, blocked, idle) in the ACTIVE column instead of tmux's last-activity time. Ctrl-b q detaches.

The box records which multiplexer its sessions started in (/root/.boxctl/mux, returned by the project check), so later runs, --repo runs and claude ls look for the session where it is without being told. --mux given explicitly while Claude runs in the other one is refused rather than starting a second Claude beside it.

Difference from boxctl: a box here always outlives the run, so herdr's pane only runs Claude. When Claude exits, the server stays for the box's other sessions and the attached client shows a plain shell workspace to detach from. boxctl's shellAfter is not ported.

Changes

  • cmd/mux.go (new): the multiplexer interface, tmuxMux, herdrMux, --mux resolution and the box marker.
  • cmd/claudesession.go: the session field is name (its label in either multiplexer); tmuxCommand moved into tmuxMux.start.
  • cmd/claude.go: --mux flag with completion, resolveMux, sessionRunning, useBoxMux; checkProject also returns the box's multiplexer; claudeSetupScript is a function that includes mux.setup(); help text.
  • cmd/clauderepo.go, cmd/claudels.go: use the multiplexer.

Tests

cmd/mux_test.go ports boxctl's suite against a fake herdr on PATH: first start brings the server up and types the command into a new workspace, second start only focuses, detached start doesn't attach, restart of the server closes restored workspaces first, running/list/parseList for both, muxNamed, ONCTL_MUX default, the project check reporting the marker, and the setup script installing herdr only under --mux herdr. Existing tests adjusted for the renamed field and claudeSetupScript(). go test ./cmd/ and golangci-lint run pass.

Verified on a real box (ac)

onctl -p ac claude --repo cdalar/onctl --box claude-muxtest --mux herdr -d on a fresh Ubuntu container: herdr was installed to /usr/local/bin, the box marked herdr, a herdr server started, Claude ran inside its claude workspace, and a second run reported Claude is running on claude-muxtest without starting another.

Not verified: how long the first detached start took to return. That run was killed by my own 9-minute timeout before printing, and the box lost its network attachment shortly after (the Apple container 0.1.0 network helper issues from #1231's thread), so I couldn't time a clean detached start in isolation. The start script is byte-for-byte boxctl's apart from the pane command, so I expect no hang, but it's worth one --detach run on a box with a healthy network.

🤖 Generated with Claude Code

https://claude.ai/code/session_01CQo63nquy9oDWspMWnWfxD

Ported from boxctl. A multiplexer keeps Claude running on the box
between attaches; tmux stays the default. --mux herdr (or ONCTL_MUX=
herdr) runs it in herdr (herdr.dev), installed on the box the first
time: one server per box, a workspace per session labeled with the
session's name, so an attached herdr shows every task with what its
Claude is doing, and claude ls reads the status (working, blocked,
idle) from one `herdr workspace list`. Ctrl-b q detaches.

The box records which multiplexer its sessions started in
(/root/.boxctl/mux, read by the project check), so later runs and
claude ls look there without being told; --mux given explicitly against
a session running in the other one is refused rather than starting a
second Claude beside it.

Unlike boxctl, a box here always outlives the run, so herdr's pane only
runs Claude: when it exits the server stays for the box's other
sessions, and the attached client shows a shell workspace to detach
from.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CQo63nquy9oDWspMWnWfxD
@codecov

codecov Bot commented Oct 23, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.00000% with 50 lines in your changes missing coverage. Please review.
✅ Project coverage is 47.67%. Comparing base (d10dd14) to head (1578e4c).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
cmd/claude.go 22.72% 34 Missing ⚠️
cmd/claudels.go 0.00% 5 Missing ⚠️
cmd/clauderepo.go 0.00% 5 Missing ⚠️
cmd/mux.go 92.53% 5 Missing ⚠️
cmd/claudesession.go 75.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1233      +/-   ##
==========================================
+ Coverage   47.22%   47.67%   +0.44%     
==========================================
  Files          77       78       +1     
  Lines        9044     9165     +121     
==========================================
+ Hits         4271     4369      +98     
- Misses       4773     4796      +23     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cdalar
cdalar merged commit 855dad9 into main Oct 23, 2026
13 checks passed
@cdalar
cdalar deleted the feat/claude-mux-herdr branch October 23, 2026 18:40
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.

1 participant

⌂ 换网址