Dungeon steward for worktree-heavy projects. It keeps the halls swept: base branches fast-forwarded, merged feature branches buried, and new worktrees created in the right chamber.
The expected project layout is an organization directory with mirrored git worktrees:
main/ -> main
feature/<name>/ -> feature/<name>
Projects can add more workstreams, for example:
webpage/main/ -> webpage/main
webpage/<name>/ -> webpage/<name>
specification/main/ -> specification/main
specification/<name>/ -> specification/<name>
uv tool install git+https://github.com/nueces/steward.git@v0.1.0
steward --helpFor local development, install from a checkout instead:
git clone https://github.com/nueces/steward.git
uv tool install --editable ./stewardDev tasks use Poe the Poet through uv. To avoid a broken or stale local .venv, point uv at a disposable environment:
export UV_PROJECT_ENVIRONMENT=/tmp/steward-venv
uv run poe test # pytest
uv run poe coverage # pytest with coverage
uv run poe lint # ruff
uv run poe check # lint + test
uv run poe pre-commit # run all pre-commit hooks- Use
pytestwith pure function tests; no test classes. - Mock git/subprocess output for fast unit coverage of parsing, planning, and command intent.
- Use temporary git repositories for integration behavior; use mocks for unit tests. Temp repo integration tests are planned, but not used yet.
Run steward from anywhere inside one of the project's git worktrees. With no
command it opens an arrow-key menu:
Steward
update base branches
clean merged branches
exit
Use --json with a command for agent-friendly output and no prompts:
steward --json cleanup-branchesTool upkeep lives under self:
steward self update # upgrade steward with uv
steward self config # infer and write .steward.toml
steward self config --overwrite # overwrite existing .steward.toml without asking
steward --install-completionSee docs/self-config.md for how config discovery works.
By default, the steward knows the smallest dungeon map:
[[workstream]]
prefix = "feature"
base = "main"
create = true
cleanup = truePut a .steward.toml at the project organization root to change the map, or run:
steward self configself config inspects git worktrees plus local/origin branches, prints the
inferred config, and writes it. Existing config files are overwritten only after
confirmation, or immediately with --overwrite.
A workstream is a lane of related work identified by a branch prefix and,
when mirrored locally, a matching directory prefix. For example, the feature
workstream covers branches like feature/login and worktrees like
feature/login/.
A workstream config tells steward which base branch that lane starts from,
whether steward may create new branches in it, and whether steward may clean up
merged branches from it. Base branches are derived from base and protected.
Example for a larger project:
[[workstream]]
prefix = "feature"
base = "main"
create = true
cleanup = true
[[workstream]]
prefix = "webpage"
base = "webpage/main"
create = true
cleanup = true
[[workstream]]
prefix = "specification"
base = "specification/main"
create = true
cleanup = true
[[workstream]]
prefix = "release"
base = "main"
cleanup = true
[[workstream]]
prefix = "post-release"
base = "main"
cleanup = trueFetches origin --prune, shows the configured base branches, then safely
fast-forwards local base worktrees. For the default config this means:
main/fromorigin/main
Larger configs may also include bases such as:
webpage/main/fromorigin/webpage/mainspecification/main/fromorigin/specification/main
It skips dirty or diverged worktrees. If a base branch exists locally but the mirrored worktree is missing, it offers to recreate it.
steward update-basesExample creation when specification/main/ is missing:
created specification/main -> /home/nueces/code/sbx/specification/main
JSON example:
steward --json update-bases{
"base_branches": [
{
"branch": "main",
"worktree": "/home/nueces/code/sbx/main",
"remote": true
},
{
"branch": "webpage/main",
"worktree": "/home/nueces/code/sbx/webpage/main",
"remote": true
},
{
"branch": "specification/main",
"worktree": "/home/nueces/code/sbx/specification/main",
"remote": true
}
],
"updates": [
{
"branch": "specification/main",
"worktree": "/home/nueces/code/sbx/specification/main",
"behind": -1
}
],
"skips": []
}behind: -1 means the worktree needs to be created.
Finds local and remote branches matching configured cleanup workstreams:
feature/*merged intomainby defaultrelease/*merged intomainwhen configuredpost-release/*merged intomainwhen configuredwebpage/*merged intowebpage/mainwhen configuredspecification/*merged intospecification/mainwhen configured
It never removes protected base branches. Base branches are all configured
base values, for example main, webpage/main, or specification/main.
It skips dirty worktrees and branches not fully merged. It asks before deleting anything.
steward cleanup-branchesExample removable remote-only branch:
Branch Local Origin Merged into Worktree
feature/smolvm-upgrade - available origin/main -
Menu options adapt to what exists:
Remove branches
local only
origin only
local + origin
no changes
JSON example:
steward --json cleanup-branches{
"plans": [
{
"branch": "feature/smolvm-upgrade",
"target": "origin/main",
"worktree": null,
"local": false,
"remote": true
}
],
"skips": []
}Creates a new branch and mirrored worktree using the project organization rules.
steward new feature vm-mount-syncCreates:
branch: feature/vm-mount-sync
base: main
worktree: feature/vm-mount-sync/
steward new webpage release-bannerCreates:
branch: webpage/release-banner
base: webpage/main
worktree: webpage/release-banner/
steward new specification docker-installCreates:
branch: specification/docker-install
base: specification/main
worktree: specification/docker-install/
JSON example:
steward --json new feature config-wizard{
"branch": "feature/config-wizard",
"base": "main",
"worktree": "/home/nueces/code/sbx/feature/config-wizard"
}