team-worktree
Prepare one or more isolated git worktrees — one per repository the topic touches. Router action — no agent. Trigger on "set up the worktree", "isolate this work", or "/team-worktree".
Install
npx skills add https://github.com/bostonaholic/team/tree/main/skills/team-worktree
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install bostonaholic-team@llmmart
git clone https://github.com/bostonaholic/team.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole bostonaholic/team collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Team Worktree — Isolate the Implementation
Before finalizing prose you author, read the writing standards.
Create a git worktree per involved repository so implementation happens on
isolated branches without affecting any main working tree. In single-repo
mode (the default) this is one worktree in the home repo. In multi-repo
mode (when docs/plans/<id>/4-repos.md is present) it is one worktree per
listed repo, all sharing the same <id> branch name.
Core contracts
- Detect a linked checkout with
git rev-parse --git-dirandgit rev-parse --git-common-dir. - Non-default branch in an existing linked checkout → skip worktree creation for this repo.
- Default branch → report and stop.
- In single-repo mode run
git worktree add .claude/worktrees/<branch>. - For every
4-repos.mdentry rungit -C <repo> worktree add .claude/worktrees/<branch>. - Record every created path under
## Worktreesin4-repos.md.
Procedure references
Read each reference completely when reaching that stage. Follow them in order; later stages depend on state and gates established earlier.
Files (team)
-
agents
-
openai.yaml 175 B
interface: display_name: "Team Worktree" short_description: "Prepare an isolated git worktree" default_prompt: "Use $team-worktree to prepare an isolated git worktree."
-
-
playbooks
-
worktree.md 12 KB
# Worktree Isolation Every `/team` run uses one isolated worktree per affected repo. The router owns isolation. Read this playbook before setup or teardown. Every `/team` pipeline run operates in **one or more** isolated git worktrees — one per repository the topic touches. The worktree boundary is at the **router level** — not per-agent. This means: 1. **Parallel pipelines.** Multiple `/team` runs can execute simultaneously without file conflicts. Each gets its own worktree(s). 2. **Clean main tree(s).** The user's working tree in every involved repo is never polluted by in-progress implementation, test scaffolding, or intermediate commits. 3. **Simple agents.** No agent needs to know about isolation. They operate in whatever directory the orchestrator hands them. 4. **Multi-repo features.** A single topic can span repos (e.g. frontend + backend + shared types) by listing them in `docs/plans/<id>/4-repos.md`. The router creates a worktree in each, branched off the same `<id>`. ## Single-repo (default) Without `docs/plans/<id>/4-repos.md`, the topic touches only the home repo (the repo the user invoked `/team` from). The router creates exactly one worktree on branch `<id>` off `origin/HEAD`, at `<repo>/.claude/worktrees/<id>`, using the host's native worktree support when it offers one and `git worktree add` otherwise. ## Multi-repo With `docs/plans/<id>/4-repos.md` present, the topic spans multiple repos. The router creates **one worktree per listed repo**, all sharing the same branch name `<id>`: - **Containment check first:** each `<repo-path>`'s `realpath` must resolve to a direct child of the home repo's parent directory (`dirname "$(realpath "<repo-path>")"` equals `dirname "$(realpath "<home-root>")"`). A repo that fails is refused and reported — `4-repos.md` content is not trusted blindly. - For each repo with absolute path `<repo-path>` in `4-repos.md` that passes the containment check: - Worktree path: `<repo-path>/.claude/worktrees/<id>` - Branch: `<id>`, branched from that repo's `origin/HEAD` - Created through `git -C <repo-path> worktree add .claude/worktrees/<id> -b <id> origin/HEAD` - The **home repo's worktree** holds the canonical `docs/plans/<id>/` artifact directory. The other repos' worktrees do not duplicate the artifacts. Agents that need them read from the home worktree's path, which the orchestrator passes in. After all worktrees are created, the orchestrator appends a `## Worktrees` section to `4-repos.md` recording the per-repo worktree paths. Any later `/team-*` invocation rediscovers them by reading that one file. ## Worktree creation For the home repo, use the host's native worktree support when it offers one (Claude Code's `--worktree <topic>` or dispatch into a worktree context). For more repos in multi-repo mode, the router uses plain `git worktree add` because a native flag only knows about the repo the session was launched from. Either mechanism produces a standard git worktree — there is no behavioral difference downstream. ## Lifecycle ### Setup (router responsibility) The home worktree is created at the **leading WORKTREE phase** — phase 1 of 8, before QUESTION (see [Why first](#why-first) below for the rationale). The router's responsibilities are: 1. Create the home repo's worktree on branch `<id>` off `origin/HEAD`. Author `docs/plans/<id>/` **inside** it. No copy is ever needed, because the artifact directory is born in the worktree. (Secondary repos in multi-repo mode get their worktrees after the design review, once `4-repos.md` confirms the repo set. Same `<id>` branch in each.) 2. After this phase, all downstream agent dispatches operate within the applicable worktree. That is the home worktree by default, or a per-repo worktree when a slice or step carries a `[repo: <name>]` annotation. The durable inter-agent protocol is the artifact files under the home worktree's `docs/plans/<id>/` directory. Live coordination uses TodoWrite (session-scoped). ### Reusing an existing worktree A **linked worktree** is any working tree other than the repository's main working tree. Detect it by the checkout's git dir differing from its common git dir. If the session already runs inside one on a **non-default branch**, the WORKTREE phase reuses it rather than create a new one. There is no new branch and no artifact copy, and work continues in place on the current branch. If that worktree is checked out on the default branch (main/master), the phase refuses and stops — implementing directly on the default branch is never acceptable, and nesting worktrees is not supported. Follow the team-worktree skill's "Detect existing worktree" procedure (`references/03-detect-existing-worktree.md`). ### Why first Worktree creation is the leading phase — it runs first, before QUESTION — for two load-bearing reasons. First, authoring `docs/plans/<id>/` inside the worktree from phase 1 keeps the home checkout's `git status` clean for the entire run. No intermediate artifacts, test scaffolding, or commits ever touch the main working tree. Second, a leading worktree gives the recovery hooks a genuine first state to detect: "a worktree exists for `<id>`, no `1-task.md` yet" ⇒ WORKTREE. The phase becomes inferable from the moment the run begins rather than only appearing midway through the pipeline. For artifact ergonomics, the orchestrator **reports the absolute worktree-rooted `docs/plans/<id>/` path**. That is where `6-design.md` and the `design-review-<n>.md` verdict records live. Anyone who audits the run then opens the artifacts cleanly, with no hunt for the worktree. ### During the pipeline All agents — researcher, planner, test-architect, implementer, reviewers — run inside whichever worktree the orchestrator hands them for the current slice or step. In single-repo mode that is always the home worktree. In multi-repo mode the implementer changes directory between repos as the plan steps require, committing each slice in the worktree where its files live. Main working trees are never touched. ### Ship (teardown) Opening a PR does **not** tear down the worktree — the user may need to iterate on the branch (push follow-up commits, address review feedback). Keep the worktree until the PR is merged or the user explicitly asks to remove it. The same holds when commits are kept locally without a PR. The user-invoked, PR-aware teardown — with a merged-PR gate, protected-branch refusals, and remote-branch deletion — is `/pr-cleanup` (`skills/pr-cleanup/SKILL.md`); the numbered steps below remain the orchestrator's in-pipeline teardown. Hard rules: preserve commits; never delete a primary clone; verify each removed path; `pull --rebase origin <base>`; `remote prune origin`; verify `docs/plans/<id>` is untracked before deleting only that topic; run `skills/pr-cleanup/playbooks/cleanup.md` last and skip its reviewer-only section. When teardown is warranted (post-merge or on explicit request): 1. For each worktree with commits ahead of its base branch, cherry-pick or rebase those commits onto the target branch in that repo. Then let the host remove the worktree, or run `git worktree remove`. 2. Empty worktrees clean up automatically. 3. If manual cleanup is needed: `git -C <repo-path> worktree remove <worktree-path>` and `git -C <repo-path> branch -D <id>`. 4. **Assert the path is actually gone.** `git worktree remove` exits 0 and does delete gitignored files, but a long-lived process still anchored to the old absolute path — an editor language server, a hook writing per-session state — can `mkdir -p` it straight back. Re-check the path, and delete a reappeared one only when it is `<repo-root>/.claude/worktrees/<name>`: never a path still listed by `git worktree list`, and never a primary clone. 5. After the worktree is gone, update the repo's local default branch with the merge: `git -C <repo-path> pull --rebase origin <base>`. Always rebase — never a merge commit — so history stays linear. When the merge also deleted the branch on origin, follow with `git -C <repo-path> remote prune origin`: that deletion is server-side, so the local `refs/remotes/origin/<id>` survives and keeps every commit on the branch reachable — `git branch -D` in step 3 frees nothing while it stands. `skills/pr-cleanup/SKILL.md` Mode A step 6 covers this and the space-reclaim sequence that follows it. 6. Remove the feature's local planning docs: `rm -rf docs/plans/<id>`. These are untracked QRSPI scratch that only existed to drive the work to a merged PR. Deleting them is part of teardown, alongside the branch and worktree. Verify the directory is untracked first (`git ls-files docs/plans/<id>` returns nothing) and remove only that feature's `<id>` directory — never sibling dirs for other in-flight work. 7. **Sweep residue as the final action.** Recreation lands *after* the removal command returns — seconds to hours later — so a check inside that same command cannot catch it, and the sweep is not redundant with step 4. It re-checks the removed path plus every sibling under `.claude/worktrees/` that `git worktree list` no longer knows about. A directory is deleted only when it is pure regenerable residue: no `.git` entry, and no files outside `tmp/`, `.omc/`, and `docs/plans/`. ```sh root="$(git -C <repo-path> rev-parse --show-toplevel)" live="$(git -C "$root" worktree list --porcelain | sed -n 's/^worktree //p')" for dir in "$root"/.claude/worktrees/*; do [ -d "$dir" ] || continue printf '%s\n' "$live" | grep -qxF "$dir" && continue if [ -e "$dir/.git" ]; then echo "kept (still a checkout): $dir"; continue fi extra="$(find "$dir" -type f \ -not -path "$dir/tmp/*" -not -path "$dir/.omc/*" -not -path "$dir/docs/plans/*")" if [ -n "$extra" ]; then printf 'kept (holds unexpected files): %s\n%s\n' "$dir" "$extra" else rm -rf "$dir" && echo "swept: $dir" fi done ``` Report the outcome either way: name each swept directory, or say no residue was found. A kept directory is surfaced to the user with the files it holds — never deleted silently, never left unreported. 8. **Tear down what the worktree provisioned**, not only the worktree. Steps 1-7 remove checkouts, refs, and directories; a database or container created for the branch survives all of them. Follow `skills/pr-cleanup/playbooks/cleanup.md` — all sections, full depth. Skip "Finishing a review rather than a merge". It runs the teardown commands the repo declares in `.teamteardown`, and runs nothing when the repo declares none. ## Gitignored Files Git worktrees are fresh checkouts — they do not include untracked files like `.env` or `.env.local`. To copy these automatically, add a `.worktreeinclude` file to the project root using `.gitignore` syntax: ``` .env .env.local ``` Only files matching a pattern that are also gitignored get copied. In multi-repo mode, each repo honors its own `.worktreeinclude` independently. ## Provisioned resources `.worktreeinclude` is the setup half of a pair. The teardown half is `.teamteardown`, also at the project root: one command per line, run when the work the worktree carried is finished, so a database or container created for the branch does not outlive it. Only the copy committed to the default branch ever runs. `skills/pr-cleanup/playbooks/cleanup.md` carries the format and the rules; teardown step 8 above is what runs it. ## Fallback If worktree creation fails in any repo (shallow clones, certain CI systems): 1. Report the failure for that repo: "Worktree creation failed in <name>. Falling back to main tree for that repo." 2. Continue the pipeline. Other repos still get worktrees. The failing repo's portion of the work runs in its main working tree. 3. If creation fails in the home repo, the orchestrator proceeds with in-place work for the entire pipeline — no isolation, but the pipeline still runs. Never block the pipeline because worktree creation failed — isolation is a best-practice enhancement, not a hard requirement.
-
-
references
-
01-input.md 1.1 KB
## Input `$ARGUMENTS` is the artifact directory: `docs/plans/<id>/`. If empty, the discovery command below resolves it. The directory's basename — `<id>` — is used as both the branch name and the worktree directory name in every involved repo. Resolve `<team-skill-dir>` to the absolute directory containing `skills/team/SKILL.md`. From the repository root, run: ```sh "<team-skill-dir>/discover-topic.sh" "${ARGUMENTS:-}" "8-plan.md" ``` - **If the command printed a path**, use it as `$ARGUMENTS` for the rest of this skill (tier 1 explicit arg, or tier 2 discovery). When the path came from tier 2 (no explicit arg), announce the resolved directory to the user before proceeding, so an auto-picked topic is never silent. - **If the command printed nothing** (tier 3 — no directory holds `8-plan.md`), do not hard-error. Fire `AskUserQuestion` with a `Setup` header and labeled options: - **Run the producer** — run `/team-plan docs/plans/<id>/` to produce the missing `8-plan.md`. - **Give a path** — the user supplies the `docs/plans/<id>/` directory directly (run `ls docs/plans/` to find your topic directory). -
02-detect-mode.md 471 B
## Detect mode 1. Use the directory resolved in `## Input`. 2. **Read `$ARGUMENTS/4-repos.md`** if present: - Parse the home repo path and the list of more repos (each with `path:` and `name:` fields). See the [feature playbook](../team/playbooks/feature.md) for the schema. - This puts you in **multi-repo mode**. 3. If `4-repos.md` is absent, you are in **single-repo mode**: only the home repo (the one this command is running in) gets a worktree. -
03-detect-existing-worktree.md 1.8 KB
## Detect existing worktree **Never create a nested worktree.** For each target repo, determine if the current checkout is a **linked worktree**. That is any working tree other than the repository's main working tree, wherever it lives on disk. In the main working tree the git dir and the common git dir are the same path. In a linked worktree they differ: ```sh [ "$(git -C <repo-path> rev-parse --path-format=absolute --git-dir)" != \ "$(git -C <repo-path> rev-parse --path-format=absolute --git-common-dir)" ] \ && echo "linked worktree" ``` If the checkout is a linked worktree, check which branch it is on: ```sh git -C <repo-path> rev-parse --abbrev-ref HEAD ``` Compare against the repo's default branch (`git -C <repo-path> symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@'`, falling back to `main`/`master` if unset): - **Non-default branch** → **skip worktree creation for this repo.** Announce once: "Already in worktree `<path>` on branch `<branch>` — skipping worktree creation, continuing in place." Then treat the current checkout as this repo's worktree for the rest of the pipeline. Work continues on the current branch — no `<id>` branch is created. - **Default branch** → report and stop. Implementing directly on the default branch inside a worktree is never acceptable, and nesting worktrees is not supported. The user should switch that worktree to a feature branch (or invoke `/team` from a non-worktree checkout) before retrying. If the checkout is **not** a linked worktree, this repo proceeds through the normal creation flow below. In multi-repo mode, this check applies to **every** listed repo, not just the home repo. Skipped repos reuse their current checkout. The remaining repos still get fresh `<id>`-branch worktrees. -
04-execution.md 5 KB
## Execution ### Derive identifiers - `<id>` = `basename "$ARGUMENTS"` - Branch name = `<id>` (in every involved repo) - Worktree path per repo = `<repo-path>/.claude/worktrees/<id>` (the `.claude/worktrees/` convention. See `skills/team-worktree/playbooks/worktree.md`) **Branch names must never contain a slash (`/`).** Use `-` as the only delimiter. A `/` in a branch name creates a nested ref path in `.git/refs/heads/`. That path collides with the `.claude/worktrees/` directory convention and breaks worktree cleanup. The `<id>` produced by the questioner is already slash-free, but if `basename "$ARGUMENTS"` ever yields a name containing `/` (e.g. a ticket prefix like `TEAM/123`), replace every `/` with `-` first and use that sanitized name as **both** the branch name and the worktree directory name so the two stay in sync for cleanup: `branch="$(printf '%s' "$id" | tr '/' '-')"`. Only the `docs/plans/<id>/` artifact directory keeps the original `<id>`. ### Confirm with the user (standalone invocation only) **Standalone invocation only — in a full `/team` run, skip this dialog entirely and proceed straight to "Create the worktree(s)".** The dialog fires only when a human invoked `/team-worktree` directly — a setup-time prompt on direct invocation. Within a full `/team` run the orchestrator creates the worktrees **without a confirmation prompt** (the phase loop never pauses mid-run). The resolved repo set is recorded loudly in `6-design.md` and echoed in the PR body's `## Review notes`. Create a worktree only for the repos that actually need one. If **no** repo needs creation (single-repo mode where the detect step skipped the home repo), skip this dialog entirely — the reuse announcement above is sufficient. Proceed to Completion. Single-repo: ``` Ready to create worktree: Worktree: <home-worktree-path> Branch: <id> Plan: $ARGUMENTS/8-plan.md Proceed? ``` Multi-repo: ``` Ready to create N worktrees (one per listed repo): <repo-1-name> @ <repo-1-path>/.claude/worktrees/<id> <repo-2-name> @ <repo-2-path>/.claude/worktrees/<id> ... Branch in each: <id> Plan: $ARGUMENTS/8-plan.md Proceed? ``` Use `AskUserQuestion` with a `Worktree` header and **Proceed** / **Cancel** options. ### Create the worktree(s) After the user confirms (standalone invocation) — or immediately, in pipeline mode — create a worktree in each repo the detect step did **not** skip: Use the slash-sanitized name (`<branch>`, derived above) for both the worktree directory and the `-b` flag in every repo. In the common case `<branch>` equals `<id>`. - **Single-repo:** create the home worktree on branch `<id>` off `origin/HEAD`, using the host's native worktree support when it offers one and `git worktree add` otherwise. - **Multi-repo:** for each listed repo, first assert **containment**: the repo path's real path must be a direct child of the home repo's parent directory — ``` [ "$(dirname "$(realpath "<repo-path>")")" = "$(dirname "$(realpath "<home-root>")")" ] ``` If the check fails, **refuse that repo and report it**. Never create a worktree outside the home repo's sibling set. Do not trust `4-repos.md` content blindly, because someone can author it with no Bash-side path check. For each repo that passes: ``` git -C <repo-path> fetch origin --quiet git -C <repo-path> worktree add .claude/worktrees/<branch> -b <branch> origin/HEAD ``` If a repo lacks an `origin` remote or `origin/HEAD`, fall back to its current default branch and warn the user once for that repo. ### Record the worktree paths (multi-repo only) After all worktrees are created, append a `## Worktrees` section to the home worktree's `docs/plans/<id>/4-repos.md` listing each repo's worktree path. For repos the detect step skipped, record the current checkout's path. This becomes the discoverable record any later `/team-*` invocation reads to relocate the worktrees. ```markdown ## Worktrees - home: <home-worktree-path> - <repo-name>: <repo-path>/.claude/worktrees/<id> - ... ``` For trivial single-file changes, in-place implementation is allowed — no worktree needed. Report the worktree paths and tell the user: - Single-repo: **"Next: cd <home-worktree> and run `/team-implement docs/plans/<id>/`"** - Home repo skipped (already in its worktree): **"Next: run `/team-implement docs/plans/<id>/`"** — no `cd` needed. Work continues in the current checkout on the current branch. - Multi-repo: **"Next: cd <home-worktree> and run `/team-implement docs/plans/<id>/`. The implementer will navigate between the per-repo worktrees as the plan steps require."** > The `/team-implement` handoff above is for **standalone, post-PLAN** > invocation (this skill's discovery command is gated on `8-plan.md`). In a full > `/team` pipeline run, WORKTREE is the **leading** phase: the orchestrator > creates the home worktree first, supplying `<id>` directly (it does not run > this skill's `8-plan.md`-gated discovery), and proceeds to QUESTION next — not > to `/team-implement`.
-
-
SKILL.md 1.6 KB
--- name: team-worktree description: 'Prepares isolated git worktrees. Trigger on "set up the worktree", "isolate this work", or "/team-worktree" only; never infer the phase from work needing isolation.' effort: low argument-hint: "[docs/plans/<id>/]" --- # Team Worktree — Isolate the Implementation Before finalizing prose you author, read the [writing standards](../team/references/writing.md). Create a git worktree per involved repository so implementation happens on isolated branches without affecting any main working tree. In single-repo mode (the default) this is one worktree in the home repo. In multi-repo mode (when `docs/plans/<id>/4-repos.md` is present) it is one worktree per listed repo, all sharing the same `<id>` branch name. ## Core contracts - Detect a linked checkout with `git rev-parse --git-dir` and `git rev-parse --git-common-dir`. - **Non-default branch** in an existing linked checkout → skip worktree creation for this repo. - **Default branch** → report and stop. - In single-repo mode run `git worktree add .claude/worktrees/<branch>`. - For every `4-repos.md` entry run `git -C <repo> worktree add .claude/worktrees/<branch>`. - Record every created path under `## Worktrees` in `4-repos.md`. ## Procedure references Read each reference completely when reaching that stage. Follow them in order; later stages depend on state and gates established earlier. 1. [Input](references/01-input.md) 2. [Detect mode](references/02-detect-mode.md) 3. [Detect existing worktree](references/03-detect-existing-worktree.md) 4. [Execution](references/04-execution.md)
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.