Skip to content

Repository files navigation

Corral

Herd your Git worktrees in Herdr. Corral is a Herdr plugin plus a small hwt CLI that replaces a workmux-style workflow for people who moved from tmux to Herdr:

  • New worktree, ready to work. Creating a worktree copies your untracked .env / .env.* files, sets up dependencies (copy-on-write clone of the main checkout's node_modules when lockfiles match — near-instant on btrfs/XFS/APFS — otherwise an install via the lockfile-detected package manager), and opens exactly three tabs: agent (your coding agent, started automatically), shell, and server.
  • Stable dev ports. Every worktree leases a port from a configured range (default 4100–4199), so parallel dev servers never collide and URLs stay predictable.
  • Merge-safe cleanup. hwt cleanup deletes the worktree, the local branch, and the remote branch — without questions when the branch is provably merged into your base branch, and only with an explicit --abandon --confirm BRANCH when it is not.
  • Agent-first. Built for running one coding agent per worktree (Hermes, Claude Code, Codex, …) with isolated checkouts.

Install (the easy way)

On the machine that runs Herdr, open your agent harness (Hermes, Claude Code, Codex, OpenCode, …) and say:

Read https://raw.githubusercontent.com/bfreed/herdr-corral/main/AGENT_INSTRUCTIONS.md and follow it.

The agent will ask where your repositories live, install Corral, and verify the setup.

Install (by hand)

Requirements: Linux or macOS, Python 3.11+, Git, Herdr 0.8.0+.

git clone https://github.com/bfreed/herdr-corral ~/.local/share/herdr-corral
python3 ~/.local/share/herdr-corral/install.py --repos-root ~/repos
hwt doctor

The clone is the installation — hwt update later updates it in place. The installer discovers the Git repositories directly under --repos-root, writes a conservative config, links the plugin, and puts an hwt launcher in ~/.local/bin.

Corral is also listed in the Herdr plugin marketplace. herdr plugin install bfreed/herdr-corral registers the event hooks, but the full experience (CLI, config, updates) comes from the clone + install.py flow above.

Daily use

hwt new [feature/my-task]   # worktree + env files + deps + tabs, focused and ready
                            # omit the branch to pick repo, base, and name interactively;
                            # inside a worktree, offers to stack on its branch
hwt open [target]           # (re)open with the standard layout; omit to pick from a list
hwt dev                     # start the repo's dev server on the leased port
hwt list                    # configured repos and live worktrees
hwt status                  # port leases, lockfile drift, listening state
hwt init                    # (re)configure the current repo interactively

Finishing work:

hwt remove feature/my-task                    # remove worktree, KEEP the branch
hwt cleanup feature/my-task                   # merged? delete worktree + local + remote branch
hwt cleanup feature/my-task --abandon --confirm feature/my-task
                                              # not merged / dirty? affirmatively discard it

cleanup fetches first and proves the merge with git merge-base --is-ancestor before touching anything, refuses protected branches (main, master, develop, your configured base), and releases the port lease. The guard protects work that exists nowhere else, not branch names: an unmerged branch whose every commit is reachable from some other ref — a fresh worktree branch with no commits of its own, or one fully rebased/cherry-picked elsewhere — is also cleaned up without questions. (The branch's own remote copy doesn't count as "elsewhere", since cleanup deletes that too.)

No typing required, two ways:

  • hwt sweep — cleans every worktree that qualifies without questions in one shot, and reports the kept ones with the exact --abandon command for each.
  • The Corral palette — a popup (bind it to a key, below) listing every worktree with a safety annotation (merged — cleans instantly, nothing unique — cleans instantly, has unpublished commits, dirty). Pick a number to clean it, n to create a worktree, s to sweep, q to close.

Keybindings

Herdr's sidebar right-click menu is not extensible by plugins (as of 0.8.0 the plugin manifest's contexts field is parsed but not used by any UI — verified against the Herdr source), so Corral's interactive surface is the palette popup plus keybindings. Add to ~/.config/herdr/config.toml and run herdr server reload-config:

[[keys.command]]
key = "prefix+w"
type = "plugin_action"
command = "corral.palette"
description = "Corral: worktree palette"

# optional: merge-checked cleanup of the worktree you're focused on, no UI
[[keys.command]]
key = "prefix+backspace"
type = "plugin_action"
command = "corral.cleanup"
description = "Corral: clean up the focused worktree"

Pick any free keys; the install agent offers to set this up. To try it without a binding: herdr plugin action invoke corral.palette. For corral.cleanup, refusals (unmerged/dirty) delete nothing and are shown in the worktree's shell tab.

Configuration

  • ~/.config/herdr-corral/config.toml — global settings and discovered repositories.
  • ~/.config/herdr-corral/repos.d/<repo>.toml — per-repository overlays written by hwt init.

The first time you create a worktree for a repository, Corral offers to configure it (which env files to copy, whether to auto-install dependencies, the dev-server command). Repositories without explicit settings get safe defaults: copy untracked .env / .env.*, auto-detect the package manager, no dev server assumed, never a test tab, never an auto-started server.

Worktree placement — unified by default: Herdr's right-click "new worktree" and hwt new should create worktrees in the same place. Out of the box they do: worktree_placement = "shared-root" with worktree_root defaulting to ~/.herdr/worktrees — the same directory Herdr's own [worktrees].directory uses — so both entry points produce <root>/<repo>/<slug> checkouts, and either kind gets the full bootstrap and hwt cleanup support. Prefer a visible location? Set Herdr's [worktrees].directory (in ~/.config/herdr/config.toml, then herdr server reload-config) and Corral's worktree_root to the same folder. The workmux-style worktree_placement = "sibling" (<repo>__worktrees/ next to each repo) remains available for hwt new, but note Herdr's own dialog can't follow a per-repo layout; Corral recognizes and bootstraps all of these locations regardless.

Updating

hwt update      # git pull --ff-only + plugin relink
hwt doctor      # also tells you when an update is available

Uninstalling

python3 ~/.local/share/herdr-corral/install.py --uninstall --purge
rm -rf ~/.local/share/herdr-corral

Drop --purge to keep ~/.config/herdr-corral for a later reinstall.

Prior art

Corral overlaps with several fine single-purpose plugins — use them if you only need a slice: herdr-worktree-seed (env files + node_modules seeding), herdr-plugin-workspace-manager (declarative layouts), herdr-plugin-git-worktree-hooks and herdr-worktree-lifecycle (generic lifecycle hooks). Corral's reason to exist is the integrated workflow plus merge-safe cleanup.

Platform support

Linux and macOS. Windows is not supported yet (Herdr's own Windows support is beta); the Python code is written to be portable and contributions are welcome — see CONTRIBUTING.md.

License

MIT

About

Herd your Git worktrees in Herdr: env files, dependencies, agent/shell/server tabs, and merge-safe cleanup. A workmux replacement for Herdr.

Topics

Resources

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages