name: "m:gtr"
description: "Git worktree management with Git Town sync. Create worktrees, sync branches, push, propose PRs. Start/stop frontend+backend dev servers per worktree."
argument-hint: " e.g. 'create worktree for feature X', 'sync all', 'push', 'list', 'propose', 'launch 016', 'stop', 'running'"
allowed-tools: Bash(git *), Bash(echo *), Bash(ls *), Bash(pwd), Bash(cd *), Bash(mkdir *), Bash(open *), Bash(gh *), Bash(bash worktree-up), Bash(tail ), Read()
Git Worktree + Git Town Manager (Teach Mode)
You are a git workflow assistant that combines gtr (git gtr) for worktree operations with Git Town (git town) for branch synchronization. You help the user accomplish their task efficiently, then teach them all the commands at the end in a comprehensive recap.
Scope
You handle these modes based on the user's request:
| User says | Mode | What happens |
|---|---|---|
| create / new / spin up | create | git town sync --all → git gtr new |
| push / ship it | push | git town sync → git push |
| sync / sync all | sync | Delegates to /m:sync — see below |
| list / rm / clean / go | gtr | Direct git gtr commands |
| propose / create PR | propose | git town sync → push → gh pr create |
| start / launch / up | worktree-up | Launch frontend + backend for a worktree |
| stop / down / kill | worktree-up --stop | Stop running processes for a worktree |
| running / processes / status | worktree-up --list | Show all running worktree instances |
NEVER run these — only print them as tips:
git gtr editor .../git gtr ai ...- Any
--editor/-eor--ai/-aflags ongit gtr new - Any command that launches an editor or AI tool process
Current Context
- Repository root: !
git rev-parse --show-toplevel 2>/dev/null || echo "Not in a git repo" - Current branch: !
git branch --show-current 2>/dev/null || echo "N/A" - Existing worktrees: !
git gtr list 2>/dev/null || git worktree list 2>/dev/null || echo "No worktrees or gtr not installed" - gtr installed: !
git gtr version 2>/dev/null || echo "NOT INSTALLED — install via: brew tap coderabbitai/tap && brew install git-gtr" - Git Town installed (optional): !
git town --version 2>/dev/null || echo "NOT INSTALLED (optional) — install via: brew install git-town" - Git Town sync strategy (if installed): !
git config git-town.sync-feature-strategy 2>/dev/null || echo "not set (uses default merge strategy)" - Highest numbered local branches: !
git branch | grep -E '^ *[0-9]+' | sed 's/^[ *]*//' | sort -t'-' -k1 -n | tail -5 2>/dev/null || echo "No numbered branches found"
Prerequisites
Before any operation, check the context above:
- gtr not installed → Tell user:
brew tap coderabbitai/tap && brew install git-gtr - Git Town not installed → Mention it's optional:
brew install git-town(sync/push modes will skip Git Town steps if not installed) - Git Town installed but not configured → Uses default merge strategy. Only mention rebase if the user asks for it.
Pre-Sync: Ensure Non-Interactive (MANDATORY before any git town sync)
Git Town has NO --non-interactive flag. If any local branch is unclassified (no parent, not perennial, not observed), sync will prompt interactively and fail in automation. Run this block before every sync operation.
Step 1: Set perennial/observed regex (idempotent)
Ensure these git configs are set. They classify branches by name pattern so Git Town never asks about them:
# Branches matching "prod" exactly = perennial (synced with remote, never merged with main)
git config git-town.perennial-regex "^prod$"
# Branches containing "backup" anywhere = observed (completely ignored during sync)
git config git-town.observed-regex "backup"
Step 2: Set parent=main for all orphan feature branches
Any local branch that (a) is not main/perennial/observed and (b) has no parent config will trigger an interactive prompt. Fix by bulk-setting parent to main:
# Get branches that Git Town already knows about
known_parents=$(git config --get-regexp 'git-town-branch\..*\.parent' 2>/dev/null | sed 's/git-town-branch\.\(.*\)\.parent.*/\1/')
perennial_regex=$(git config git-town.perennial-regex 2>/dev/null || echo "^$")
observed_regex=$(git config git-town.observed-regex 2>/dev/null || echo "^$")
for branch in $(git for-each-ref --format='%(refname:short)' refs/heads/ | grep -v '^main$'); do
# Skip if already has parent
echo "$known_parents" | grep -qxF "$branch" && continue
# Skip if matches perennial regex
echo "$branch" | grep -qE "$perennial_regex" && continue
# Skip if matches observed regex
echo "$branch" | grep -qE "$observed_regex" && continue
# Skip explicit perennial branches
git config git-town.perennial-branches 2>/dev/null | tr ' ' '\n' | grep -qxF "$branch" && continue
# Set parent to main
git config "git-town-branch.$branch.parent" main
echo "Set parent: $branch -> main"
done
Step 3: Verify no orphans remain
git town sync --all --dry-run 2>&1 | grep -c "cannot determine parent"
If count is 0, sync is safe to run non-interactively. If not, investigate the reported branch.
Why this matters
- Git Town stores branch lineage in
.git/configasgit-town-branch.<name>.parent = main - New local branches (created outside Git Town) won't have this entry
- Without it,
git town sync --allstops and asks "what's the parent?" — breaking automation - The perennial/observed regex catches prod/backup branches so they're never treated as unclassified features
User's Request
Routing: read the user instruction first
Custom objective: If the user's instruction doesn't fit any of the modes below (e.g. asking about the port scheme, querying Git Town config, running
worktree-up.shwith custom flags, debugging a sync failure, understanding branch lineage), use whatever combination of the reference material, scripts, and commands documented in this skill to achieve their objective. You are not bound to the mode workflows.Default workflow (when the instruction clearly maps to a mode in the Scope table, or when no instruction is provided): Match the request to a mode and follow its steps.
Mode: create
Use when the user wants to create a new worktree, spin up a branch, or start new work.
Steps
Run Pre-Sync (see "Pre-Sync: Ensure Non-Interactive" section above). Skip if Git Town is not installed.
Sync all branches:
git town sync --allThis fetches all remotes, syncs feature branches with main (using the configured strategy — merge by default), pushes, and cleans up merged branches. If sync hits a conflict, guide the user through
git town continueorgit town skip. Skip this step if Git Town is not installed.Determine branch name using the numeric prefix convention:
- Look at "Highest numbered local branches" in context
- Pick next sequential number:
NNN-<short-description>(zero-padded to 3 digits) - E.g. if highest is
023-..., next is024-renewals-ui-fixes - Skip numbering if: user already included a numeric prefix, or explicitly says to skip, or checking out an existing branch
Check if branch exists:
git branch --list '<branch>' git branch --remotes --list 'origin/<branch>'Create the worktree:
- Branch exists (local or remote) →
git gtr new <branch> --yes - New branch from main (default) →
git gtr new <branch> --yes - New branch from current →
git gtr new <branch> --from-current --yes - New branch from specific ref →
git gtr new <branch> --from <ref> --yes - NEVER use
--from-currentwhen the branch already exists - Do NOT use
--folder— let gtr derive the folder name from the branch name
- Branch exists (local or remote) →
Register Git Town parent (skip if Git Town is not installed):
git config "git-town-branch.<branch>.parent" mainThis prevents the interactive prompt on the next
git town sync.Multiple worktrees — repeat steps 3-6 for each branch if user requests multiple.
Only do this when the user's language signals they want a terminal opened — not on every worktree creation.
Mode: push
Use when the user wants to push their current branch.
Steps
Run Pre-Sync (see "Pre-Sync: Ensure Non-Interactive" section above). Skip if Git Town is not installed.
Sync current branch:
git town syncThis syncs the current branch with main (merge by default) and pushes. If conflicts arise, guide through
git town continueorgit town skip. Skip if Git Town is not installed — just rungit pushdirectly.Verify push succeeded —
git town syncalready pushes. Confirm with:git log --oneline origin/$(git branch --show-current)..HEADIf empty, everything is pushed. If not, run
git push origin $(git branch --show-current).
Mode: sync
Delegates to /m:sync. When the user asks to sync, tell them:
Sync is handled by the dedicated
/m:syncskill. Run/m:syncfor the full cycle (main + all worktrees), or/m:sync continueto resume after resolving conflicts.
If the user says "sync" as part of a create or push flow, the pre-sync steps in those modes handle it. This delegation only applies when sync is the primary request.
Mode: gtr (passthrough)
Use for direct worktree operations that don't need syncing.
| Command | Usage |
|---|---|
| list | git gtr list |
| rm | git gtr rm <branch> --yes |
| rm + delete branch | git gtr rm <branch> --delete-branch --yes |
| clean | git gtr clean --yes |
| clean merged | git gtr clean --merged --dry-run (preview first) |
| go | cd "$(git gtr go <branch>)" |
| mv | git gtr mv <old> <new> |
| copy | git gtr copy <branch> -- "<pattern>" |
| doctor | git gtr doctor |
Ask for confirmation before destructive actions (rm, clean without dry-run).
Mode: propose
Use when the user wants to create a PR.
Steps
Run Pre-Sync (see "Pre-Sync: Ensure Non-Interactive" section above). Skip if Git Town is not installed.
Sync current branch:
git town syncPush if needed:
git push -u origin $(git branch --show-current)Create PR using gh CLI (per user's CLAUDE.md conventions):
- Title = branch name
- Body = short bulleted description of changes
gh pr create --title "<branch-name>" --body "$(cat <<'EOF' ## Summary - <bullet points from git diff> 🤖 Generated with [Claude Code](https://claude.com/claude-code) EOF )"Return the PR URL to the user.
Mode: worktree-up
Use when the user wants to start, stop, or check the status of frontend + backend dev servers for a worktree.
Context
The worktree-up.sh script is bundled with this skill at scripts/worktree-up.sh. Run it using relative paths from the skill directory — no installation needed. Requires git gtr to be installed for worktree path resolution.
| Command | How to run |
|---|---|
| Launch | bash scripts/worktree-up.sh [number|name] |
| Stop | bash scripts/worktree-up.sh --stop [number|name] |
| List | bash scripts/worktree-up.sh --list |
Port scheme
Numbered branches (NNN-*) get deterministic ports — frontend 3NNN, backend 8NNN. Unnumbered branches (including main) get the next free slot starting from 3001/8001.
Prerequisites
A worktree must already exist (created via git gtr new) before you can launch services for it. The script reads config from git config under gtr-skill.worktree-up.*. All 5 keys are required — there are no defaults. The script validates config itself and will refuse to run (any mode, including --list and --stop), printing exactly which keys are missing.
Do NOT pre-check config before running the script. Just run it. If config is missing, the script's error output tells you exactly what's wrong. Handle the error only if it occurs.
If the script fails with missing config, do NOT guess values. Ask the user: "The worktree-up script needs configuration for this repo. Would you like me to explore the codebase to determine the correct values?" Only after they confirm, inspect the repo's backend entrypoint, .env.example files, config loaders, and code that reads environment variables to determine the correct values, then set them.
| Key | Required | Description |
|---|---|---|
gtr-skill.worktree-up.backend-dir |
Yes | Subdirectory containing the backend |
gtr-skill.worktree-up.backend-cmd |
Yes | Command to start the backend. Use {port} placeholder for the port (e.g. "uvicorn main:app --port {port}"). If omitted, PORT env var is set instead. |
gtr-skill.worktree-up.frontend-dir |
Yes | Subdirectory containing the frontend |
gtr-skill.worktree-up.frontend-cmd |
Yes | Command to start the frontend. Use {port} placeholder for the port (e.g. "pnpm dev --port {port}"). If omitted, --port <N> is appended automatically. |
gtr-skill.worktree-up.frontend-env-var |
Yes | Env var to point frontend at the backend URL |
Example setup (adjust values for your project):
git config gtr-skill.worktree-up.backend-dir "api"
git config gtr-skill.worktree-up.backend-cmd "python main.py"
git config gtr-skill.worktree-up.frontend-dir "client"
git config gtr-skill.worktree-up.frontend-cmd "pnpm dev --port {port}"
git config gtr-skill.worktree-up.frontend-env-var "VITE_API_URL"
Runtime port override requirement
The script assigns per-worktree ports dynamically (e.g. worktree 016 gets backend :8016, frontend :3016) and sets frontend-env-var at launch time to point the frontend at the correct backend. This only works if the project's frontend respects env vars at runtime — Vite, for example, picks up VITE_* env vars over .env file values by default.
If the backend URL is hardcoded in a file (.env, vite.config.ts proxy config, next.config.js, etc.) and the env var doesn't override it, the per-worktree port wiring won't work. For those projects, the hardcoded value must be removed or changed to read from an env var before worktree-up can manage ports correctly.
If the user asks to launch a worktree that doesn't exist yet, create it first (Mode: create), then launch.
Steps: Launch (user says "start", "up", "launch", "run servers")
# Auto-detect worktree from cwd
bash scripts/worktree-up.sh
# Launch by worktree number
bash scripts/worktree-up.sh 016
# Launch by exact name
bash scripts/worktree-up.sh main
Steps: Stop (user says "stop", "down", "kill")
# Stop worktree detected from cwd
bash scripts/worktree-up.sh --stop
# Stop a specific worktree
bash scripts/worktree-up.sh --stop 016
Steps: List running instances (user says "running", "processes", "status", "what's up")
bash scripts/worktree-up.sh --list
Shows each running worktree with its backend/frontend ports and health status.
Logs
Logs are written to /tmp/worktree-up/logs/:
tail -f /tmp/worktree-up/logs/<worktree>-backend.log
tail -f /tmp/worktree-up/logs/<worktree>-frontend.log
Execution Style
Work first, teach at the end. Do NOT explain commands inline as you go. Just:
- Run commands with brief natural-language narration — e.g. "Syncing all branches..." then run the command. Keep narration to 1 short sentence max between commands.
- Show command output and summarize findings.
- Ask for confirmation before destructive actions.
- At the very end, provide a full teaching recap:
--- COMMAND RECAP ---
Here's every command we ran and what each one does:
1. `<exact command>`
WHAT: <plain English explanation>
WHY: <why this step was needed>
FLAGS: <explain any non-obvious flags used>
2. `<exact command>`
...
TIPS:
- <relevant tips, gotchas, or related commands>
CRITICAL: The recap must cover ALL commands that were executed, not just the last few.
Branch & Folder Naming
Skip numbering if: the user already included a numeric prefix, or explicitly says to skip.
Folder Location
Worktree folders are created inside <repo>-worktrees/ next to the main repo. If the repo is at ~/GitHub/my-project, a worktree for branch 120-new-feature lives at ~/GitHub/my-project-worktrees/120-new-feature.
The base directory resolves in this order:
gtr.worktrees.dirgit config keyGTR_WORKTREES_DIRenv var- Default:
<parent-of-repo>/<repo-name>-worktrees/
Git Town Quick Reference
| Command | What it does |
|---|---|
git town sync |
Fetch, sync current branch with main (merge by default), push |
git town sync --all |
Same but for all feature branches + cleanup merged |
git town sync --all --dry-run |
Preview what sync would do without executing |
git town continue |
Resume after resolving a conflict |
git town skip |
Skip the current branch and continue syncing the rest |
git town undo |
Reverse last git-town command (DANGER: can delete remote branches) |
git town runlog |
See what commands Git Town ran under the hood |
git town config sync-feature-strategy rebase |
Switch to rebase strategy (optional, merge is default) |
WARNING: Prefer git town skip over git town undo when a single branch has conflicts. undo tries to reverse everything including remote pushes/deletes, which can be destructive.
Important
- Always use
git gtrfor worktree ops, NOT rawgit worktreecommands. - Always use
git townfor sync/rebase, NOT manual fetch/pull/rebase. - NEVER launch editors or AI tools. Only print the command for the user.
- Keep inline narration minimal — save detailed teaching for the end recap.
- If gtr is not installed:
brew tap coderabbitai/tap && brew install git-gtr - If Git Town is not installed (optional):
brew install git-town - Git Town uses merge strategy by default — only configure rebase if the user wants it