mintree
v0.4.1
Published
Issue-driven git worktrees + Claude Code sessions for repos with an opinionated SDD+TDD flow.
Maintainers
Readme
mintree
Issue-driven worktrees + Claude Code sessions for repos with an opinionated SDD+TDD flow.
mintree wraps the steps you do manually every time a feature begins:
- Pick an open issue or work item assigned to you (GitHub Issues or Plane).
- Create a git worktree on a branch named after that item, following the project's convention.
- Launch Claude Code inside the worktree with a session ID you can resume later.
- Live-track which Claude sessions are active, idle, or waiting.
It is a smaller, opinionated cousin of santree — built on the same TypeScript + Ink + Pastel stack but stripped to the <type>/<issue>-<desc> branch convention and the two issue trackers most likely to be used by a small team: GitHub Issues and Plane.
Install
npm install -g mintree
# Upgrade later:
# npm update -g mintree
# Verify
mintree --version # should match the latest published version
mintree doctor # checks toolchain (git, gh, claude, tmux, ...)
# Enable the shell wrapper so `mintree worktree create` and the
# dashboard can `cd` your shell into the new worktree.
#
# Use the cache-aware one-liner — it sources a cached copy on every
# subsequent shell instead of spawning node, which keeps shell
# startup fast. The cache regenerates itself when mintree is updated.
cat >> ~/.zshrc <<'EOF'
_MT=${XDG_CACHE_HOME:-$HOME/.cache}/mintree/init-zsh.zsh
[[ -f $_MT ]] && source $_MT || eval "$(mintree helpers shell-init zsh)"
EOF
exec zsh
# Bash users:
cat >> ~/.bashrc <<'EOF'
_MT=${XDG_CACHE_HOME:-$HOME/.cache}/mintree/init-bash.bash
[[ -f "$_MT" ]] && source "$_MT" || eval "$(mintree helpers shell-init bash)"
EOFWorking on mintree itself? Clone the repo, run
npm installandnpm linkinstead — that wiresmintreeto your local checkout so source edits show up afternpm run build.
mintree doctor should report all required checks pass before you continue. The most common gaps are:
ghnot authenticated →gh auth login(still needed when using Plane — mintree usesghfor PR status on worktree branches)- Claude Code not installed →
npm install -g @anthropic-ai/claude-code - Shell integration not loaded → re-run the
echo … >> ~/.zshrcstep and start a new shell
Per-repo setup
In every repository where you want to use mintree:
cd path/to/repo
# Default: GitHub Issues provider
mintree init
# Or: Plane provider
mintree init --provider plane --workspace <your-workspace-slug>
mintree helpers session-signal install # optional: live session state in the dashboardinit is idempotent — re-running it is a no-op when everything is already in place.
Picking the issue provider
mintree supports two issue providers, selected per repo via .mintree/metadata.json:
github(default): lists issues assigned to you on the current repo viagh. Transitions to "In Progress" on a Projects v2 board when present.plane: lists work items assigned to you across a configured set of Plane projects, via the Plane REST API. Transitions to the project's "started" state onw.
After mintree init --provider plane, edit .mintree/metadata.json to add at least one project:
{
"version": 1,
"provider": "plane",
"issues": {},
"plane": {
"apiUrl": "https://api.plane.so",
"workspaceSlug": "my-team",
"projects": [
{ "id": "<project-uuid>", "identifier": "BACK", "name": "Backend" },
{ "id": "<project-uuid>", "identifier": "WEB", "name": "Web" }
]
}
}You can find each project's UUID in the Plane URL (app.plane.so/<workspace>/projects/<uuid>/...). The identifier is the short prefix shown on work-item IDs (the BACK in BACK-100).
Authenticate by setting PLANE_API_KEY in your shell, or by writing the key to ~/.mintree/credentials.json:
export PLANE_API_KEY=plane_api_XXXXXXXXXXXXXX
# or
cat > ~/.mintree/credentials.json <<'EOF'
{ "plane": { "apiKey": "plane_api_XXXXXXXXXXXXXX" } }
EOF
chmod 600 ~/.mintree/credentials.jsonmintree doctor validates the key + each configured project's reachability when provider === "plane".
Daily flow
Interactive dashboard
mintree dashboardOpens a full-screen TUI listing your assigned open issues (or work items), each row marked with the live state of its Claude session (● active, ! waiting, ○ idle, — exited, · no session). Rows are grouped by project board and Status. The right pane shows the issue body, labels, worktree info, PR status, and live session message.
| Shortcut | Action |
|----------|-----------------------------------------------------------------------|
| ↑/↓ or j/k | Move between issues |
| ↵ | Resume Claude in the existing worktree, or open the create overlay if there's none |
| w | Always open the create overlay (type + kebab description) |
| d | Delete the selected worktree (confirmation overlay) |
| r | Manual refresh (auto-refreshes silently every 5 min) |
| o | Open the issue in your browser |
| q/Esc| Quit (or cancel an open overlay) |
The dashboard runs in the alternate screen buffer, so closing it leaves your shell exactly as it was.
CLI
Same building blocks, scriptable from any shell:
# Create a worktree, optionally launch Claude with an initial prompt
mintree worktree create feat/100-validar-patente
mintree worktree create feat/BACK-100-validar-patente --work --prompt "empezar BACK-100"
# Resume Claude in the worktree you're currently inside
cd .mintree/worktrees/BACK-100-validar-patente
mintree worktree work
# Inspect / clean up
mintree worktree list # tabular view, dirty + ahead/behind
mintree worktree list --pr # also fetch PR status per branch (slower)
mintree worktree remove fix/55-bug # drop worktree but keep branch + session_id
mintree worktree remove fix/55-bug --force # discard uncommitted changes too
mintree worktree clean # sweep worktrees whose PR is merged/closedmt, mtw, mtn are shell aliases the wrapper installs for mintree, mintree worktree, and an interactive "name a branch" shortcut.
Branch convention
mintree enforces:
<type>/<issue>-<kebab-desc><type> is one of:
feat,fix,docs,chore,refactor,test,build,ci,perf,style,revert
<issue> is one of:
- Bare digits for GitHub Issues (the issue number, no
#):42,100,1234 <PROJ>-<digits>for Plane work items (the human identifier):BACK-100,WEB-7,PROJ_X-12. The prefix is uppercase letters / digits / underscores, matching Plane's project-identifier constraints.
<desc> is lowercase kebab-case.
Examples: feat/42-validacion-patente, fix/55-selfie-upload-timeout, feat/BACK-100-readme-update, fix/WEB-7-modal.
When the dashboard's w overlay opens, it suggests a kebab description capped at 5 words. If your repo has a docs/conventions/git-workflow.md, CONTRIBUTING.md, or .claude/skills/ directory, mintree mentions it on the overlay so you can verify the suggestion against your project's rules — then edit the description to match.
What gets stored where
<repo>/
├── .gitignore # gets `.mintree/worktrees/` + session-states/ + metadata.json appended
└── .mintree/
├── metadata.json # gitignored. provider config + <issue-id> → { base_branch?, session_id? }
├── worktrees/ # gitignored
│ ├── 100-validar-patente/ # GH form: <digits>-<desc>
│ └── BACK-100-readme-update/ # Plane form: <PROJ-digits>-<desc>
├── session-states/ # gitignored
│ └── 100.json # live state written by Claude hooks (active/waiting/idle/exited)
└── init.sh # opt-in. Runs in the new worktree post-create (copy .env, install deps, …)metadata.json is gitignored because the session_id is local to your machine — sharing it would only generate noise. The provider and plane.* keys can be re-derived from a Plane workspace if needed; sharing them would just leak local config preference.
Plane authentication lives in ~/.mintree/credentials.json (user-scoped, not per-repo) or the PLANE_API_KEY env var.
Claude Code integrations
- Sessions persist by issue: each issue gets a UUID stored in
metadata.json. Subsequentworktree workcalls pass--resume <uuid>so Claude reopens the same conversation. - Live state (optional): the four hooks installed by
mintree helpers session-signal installwrite the current Claude state to.mintree/session-states/<issue>.jsonon every prompt / stop / notification / session-end. The dashboard reads those files to colour each row in real time. - Remote Control (optional):
mintree doctorchecks~/.claude.jsonforremoteControlAtStartup: true. Enabling it lets you continue a local session from a different device.
Troubleshooting
mintree doctoris the first stop. It surfaces missing tools, unauthenticated CLIs, missing hooks, and gitignore drift.- The shell wrapper exports
MINTREE_SHELL_INTEGRATION=1— if doctor says it's missing, the wrapper isn't being loaded by your shell init file. - If the dashboard ever opens with a stale session state, press
rto force a refetch (the auto-refresh runs every 5 minutes). - Plane-side issues (timeouts, rate limits, unexpected response shapes) can be logged to
~/.mintree/plane-debug.logby runningMINTREE_DEBUG=1 mintree dashboard. The log is file-only so it never corrupts the Ink-rendered TUI.
Why not santree
mintree was written for projects that have:
- A small set of trackers (GitHub Issues or Plane) — santree supports both Linear and GitHub but is heavier.
- An established branch convention without the
gh-prefix santree imposes. - Skills (
.claude/skills/) that own the SDD + TDD flow — mintree intentionally leaves the rich PR-create / PR-review prompts out of scope.
The implementation copies santree's stack (TypeScript + Ink + Pastel + Zod) and visual style (split pane, alt-screen, marker-based shell wrapper) so the two feel similar in use.
License
MIT
