tmux-style pane layouts and rotation for Herdr, scoped to the current tab. Reshaping and rotating both preserve every pane's running process and scrollback — nothing gets closed or restarted.
| Action | Behavior |
|---|---|
wrangler.columns |
N even side-by-side columns |
wrangler.rows |
N even top/bottom rows |
wrangler.main-left |
One large pane on the left, remaining panes stacked evenly on the right |
wrangler.main-top |
One large pane on top, remaining panes in an even row below |
wrangler.tiled |
Roughly-square grid |
wrangler.rotate-forward |
Shift pane contents forward by one slot (1,2,3 → 2,3,1) |
wrangler.rotate-backward |
Shift pane contents backward by one slot (inverse of rotate-forward) |
Every layout handles more panes than it was designed for by evenly
distributing the extras — main-left/main-top just add more rows/columns
to the stack, columns/rows add more columns/rows, and tiled grows the
grid.
The layout used by main-left/main-top always treats the same pane as
"main": whichever pane is first in the tab's current left-to-right,
top-to-bottom order — not whichever pane currently has focus, so repeated
presses are deterministic.
GitHub:
herdr plugin install jone/herdr-wrangler --yesLocal checkout:
herdr plugin link ~/projects/agent/herdr-wrangler
herdr server reload-configherdr's default config binds prefix+1..9 to switch_tab, so wrangler's
layout actions use prefix+alt+<n> instead to avoid shadowing that. Add to
~/.config/herdr/config.toml:
[[keys.command]]
key = "prefix+alt+1"
type = "plugin_action"
command = "wrangler.columns"
description = "wrangler: columns layout"
[[keys.command]]
key = "prefix+alt+2"
type = "plugin_action"
command = "wrangler.rows"
description = "wrangler: rows layout"
[[keys.command]]
key = "prefix+alt+3"
type = "plugin_action"
command = "wrangler.main-left"
description = "wrangler: main-left layout"
[[keys.command]]
key = "prefix+alt+4"
type = "plugin_action"
command = "wrangler.main-top"
description = "wrangler: main-top layout"
[[keys.command]]
key = "prefix+alt+5"
type = "plugin_action"
command = "wrangler.tiled"
description = "wrangler: tiled layout"
[[keys.command]]
key = "prefix+alt+o"
type = "plugin_action"
command = "wrangler.rotate-forward"
description = "wrangler: rotate panes forward"
[[keys.command]]
key = "prefix+alt+shift+o"
type = "plugin_action"
command = "wrangler.rotate-backward"
description = "wrangler: rotate panes backward"Reshaping an arbitrary live tab into a new split tree isn't a single herdr
call — there's no "set layout" API. columns/rows/main-left/main-top/
tiled build the desired layout as a binary split tree, then move every pane
except a fixed anchor pane through a disposable staging tab and back into the
original tab in the target shape, via herdr's pane.move. If anything fails
partway through, whatever's left in the staging tab is moved back into the
original tab rather than stranded. Rotation is much simpler: it's just a
chain of pane.swap calls over the tab's panes in their current
left-to-right, top-to-bottom order.
- Herdr 0.7.0+
- Python 3.10+ (standard library only — nothing to
pip install) - macOS or Linux
Dev tooling (ruff, pytest) is managed with uv and never touches the plugin's own runtime requirements above.
bin/setup # uv sync -- creates .venv with ruff + pytest
bin/test # ruff check . && pytestTests never need a live herdr session: layout_tree.py is pure functions,
wrangler.py's reshape()/rotate() are exercised against an in-memory
FakeHerdr (test/fakes.py), and herdr_client.py's socket wire format is
checked against a throwaway local Unix-socket server (test/socket_server.py).
CI (.github/workflows/test.yml) runs the same checks on Python 3.10
through 3.14.
AI disclosure: This project — design, implementation, and test suite — was generated with AI assistance (Claude Code, Claude Sonnet 5).