Skip to content
Back to skills

Rig Worktree

ASecurity

Manage isolated git worktrees: create one wired up for dev (fetch, branch from base, symlink env, install deps), list them with PR state, or safely remove merged ones. A shared bootstrap that implement-style flows can call, also usable directly. Triggers on: 'worktree', 'set up a worktree', 'new worktree', 'list worktrees', 'remove worktree', 'isolate this in a worktree', 'symlink env into worktree'.

  • 3 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 19, 2026
ai-agentsbashgit

Works with

  • claude code
  • cursor
  • cli

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 19, 2026

npx -y skills add agent-rig/rig --skill rig-worktree --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Rig Worktree?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Rig Worktree
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/agent-rig-rig-worktree/badge)](https://www.skillsdirectory.com/skills/agent-rig-rig-worktree)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: rig-worktree
description: "Manage isolated git worktrees: create one wired up for dev (fetch, branch from base, symlink env, install deps), list them with PR state, or safely remove merged ones. A shared bootstrap that implement-style flows can call, also usable directly. Triggers on: 'worktree', 'set up a worktree', 'new worktree', 'list worktrees', 'remove worktree', 'isolate this in a worktree', 'symlink env into worktree'."
argument-hint: "<branch> [--base <ref>] [--reuse] [--no-install] [--name <s>] | list | rm <branch|path> [--force-dirty]"
allowed-tools: [Bash, Read]
---

# Worktree — isolated dev checkout lifecycle

Create / list / remove isolated git worktrees under `.claude/worktrees/`.
Creation produces a worktree that's actually ready to run: fetched from
origin, branched from the right base, env files symlinked, dependencies
installed. This is a shared bootstrap you can call directly (spikes,
ad-hoc branches, parallel experiments) and that implement-style flows and
prune/rig-tidy steps can delegate to.

The logic lives in two scripts so the invariants live in one place:
`<SCRIPTS>/setup-worktree.sh` (create) and
`<SCRIPTS>/remove-worktree.sh` (teardown), where `<SCRIPTS>` is resolved
per install (see *Configuration*). **Creation encodes
three invariants that bite if skipped** — fetch-before-branch (stale
local refs silently start you on a pre-merge tip), env symlinks (missing
secrets read as flaky/timeout test failures, not "config not found"),
and a per-worktree dependency install (installed deps don't carry across
worktrees → `Cannot find package '...'`). Don't reimplement these
inline; call the scripts.

## Configuration

**Script location (`<SCRIPTS>`).** Where the helper scripts live depends on
which target installed them, so resolve — don't assume — from the repo root
(`git rev-parse --show-toplevel`), first hit wins:

1. `.claude/scripts/` — the `claude-code` target (on a dual-target install this
   is a symlink at `.rig/scripts/`, so either entry finds the same file).
2. `.rig/scripts/` — the `agents-md` target (Codex, Cursor, Gemini CLI, …),
   where there is no `.claude/` at all.

If neither holds `setup-worktree.sh`, say so and stop rather than
reimplementing the script inline — its invariants are the whole point.

Reads `.rig/config.json` (missing keys → defaults):

| Key | Default | Used for |
|---|---|---|
| `vcs.baseRef` | `origin/main` | Default `--base` the worktree branches from. |
| `vcs.branchConvention` | `{user}/{ticket}-{slug}` | Template when inferring a branch name from a ticket ID. |
| `vcs.defaultBranch` | `main` | The trunk (informational; the main worktree). |
| `runtime.installCommand` | derived from `packageManager` | Passed to the setup script as `--install-cmd`. |
| `runtime.packageManager` | `npm` | Derives the install command when `installCommand` is unset (`bun`→`bun install`, `pnpm`→`pnpm install`, `yarn`→`yarn`, `npm`→`npm install`, `none`→skip install). |
| `tracker.ticketPrefix` | — | Recognizing a ticket ID (e.g. `ABC-521`) to slot into the branch template. |

If `.rig/config.json` is absent, run unconfigured: base `origin/main`,
install `npm install`, branch template `{user}/{ticket}-{slug}`, and say so.

## Subcommands

`$ARGUMENTS` routes to one of:

- **(default — a branch name)** create/reuse a worktree. See *Create* below.
- **`list`** — show all worktrees with their branch + PR state. Read-only.
- **`rm <branch|path>`** — safely tear a worktree down (skip if dirty).

## Create — arguments

`$ARGUMENTS` is the branch name plus optional flags. The branch is the
only required argument.

- `<branch>` — branch to create/check out, e.g. `alice/feat-521-rename`
  or `feat-679-observability`. The naming convention for ticket work is
  `vcs.branchConvention` (default `{user}/{ticket}-{slug}`).
- `--base <ref>` — base to branch from. Default `vcs.baseRef`. For a
  stacked/integration child, pass `origin/<integration-branch>`.
- `--path <path>` — worktree location. Default
  `.claude/worktrees/<last segment of branch>` (so `alice/feat-521-foo`
  → `.claude/worktrees/feat-521-foo`). This is the directory the Claude Code
  harness manages, so a worktree created here can be adopted natively via
  `EnterWorktree`/`ExitWorktree`. The default is unchanged on non-Claude
  agents — it's then just a path with no special meaning, so pass `--path` if
  you'd rather not have a `.claude/` dir in the repo.
- `--reuse` — if the worktree/branch already exists, fetch and
  hard-reset it to `<base>` instead of failing. Use this for a
  "reuse a child worktree" path.
- `--no-install` — skip the dependency install (rarely wanted; only for
  a read-only checkout).
- `--name <session-name>` — background-job/session display name. Delegates to
  `set-session-name.sh` (ships with the kit). **Claude-Code-only** — it renames
  the FleetView background-job entry so the job list reads as the work (the
  ticket/epic) instead of the raw prompt; a clean no-op on any other agent.
- `--skip-if-prefix <p>` — passed through to `set-session-name.sh`; leave an
  existing name in place if it starts with `<p>` (so an `EPIC:` label set by
  `rig-epic` wins over a per-child `FEAT:`/`CHORE:` label).

## Create — procedure

1. **Read `.rig/config.json`** for `vcs.baseRef`,
   `vcs.branchConvention`, and the install command. Derive the install
   command from `runtime.installCommand`, else from
   `runtime.packageManager`.

2. **Infer the branch if not given.** If `$ARGUMENTS` is empty:
   - If the current branch matches the ticket-work convention, offer to
     reuse / recreate it. Otherwise ask the user for a branch name or
     ticket ID. Don't guess a branch out of thin air.
   - If given a ticket ID (e.g. `<ticketPrefix>521`) with no slug, build
     the branch from `vcs.branchConvention`, substituting `{user}` (git
     user), `{ticket}` (the lowercased ID), and `{slug}` (a short kebab
     from the ticket title — fetch it if you have a tracker, else ask).

3. **Run the script** from the repo root, passing the resolved base and
   install command. Resolve `<SCRIPTS>` first (see *Configuration*):

   ```bash
   ROOT="$(git rev-parse --show-toplevel)"
   for d in "$ROOT/.claude/scripts" "$ROOT/.rig/scripts"; do
     [ -x "$d/setup-worktree.sh" ] && SCRIPTS="$d" && break
   done
   [ -n "$SCRIPTS" ] || { echo "rig scripts not found under .claude/ or .rig/" >&2; exit 1; }

   "$SCRIPTS/setup-worktree.sh" \
     <branch> [--base <baseRef>] [--install-cmd "<install cmd>"] [--reuse]
   ```

   The script prints progress to stderr and the **absolute worktree
   path as the last line of stdout**, so capture it:

   ```bash
   WT=$("$SCRIPTS/setup-worktree.sh" \
     alice/feat-521-rename --base origin/main --install-cmd "bun install" | tail -1)
   ```

   (The script also honors `WORKTREE_BASE_REF` and `WORKTREE_INSTALL_CMD`
   env vars, so you can export those from config instead of passing flags.)

4. **Report back** the worktree path, the branch, and the base it was
   cut from. If the caller is a human running this directly, remind them
   they can `cd "$WT"` to work there. If the script failed (e.g. path
   exists without `--reuse`), surface the error verbatim and suggest
   `--reuse`.

## `list`

Show every worktree with the branch it has checked out and, where one
exists, the state of its PR. Read-only — never removes anything.

```bash
git worktree list --porcelain
```

For each non-main worktree, resolve its branch and look up the PR
state so the user can see what's safe to prune:

```bash
gh pr list --head <branch> --state all --json number,state,title -q '.[0] // empty'
```

Report a table: worktree path · branch · PR # · PR state (OPEN /
MERGED / CLOSED / none) · dirty? (`git -C <path> status --porcelain`).
End with a one-line hint, e.g. *"2 worktrees on MERGED branches —
`/rig-worktree rm <branch>` to reclaim them."*

## `rm <branch|path>`

Safely tear a worktree down via the shared script. Dirty worktrees are
**skipped, not removed** (a skip is a normal outcome, not an error) —
pass `--force-dirty` to override. Resolve `<SCRIPTS>` as in *Create* step 3:

```bash
"$SCRIPTS/remove-worktree.sh" \
  <branch|path> [--force-dirty] [--keep-branch]
```

The first stdout token is the outcome: `removed <path>`,
`skipped <path>` (dirty), or `absent <arg>` (no such worktree). The
script deletes the branch too (force `-D`, since a squash/rebase-merged
PR leaves the local branch unmerged); pass `--keep-branch` to retain it.

Report what was removed, skipped (with the dirty reason), or absent.

## Notes

- The scripts resolve the **main** worktree (first entry of `git
  worktree list`) as the source for env files / ignores and as the
  place to run `git worktree` commands, so they're safe to invoke from
  inside another worktree. `remove-worktree.sh` refuses to remove the
  main worktree.
- Symlinks (not copies) — editing an env file in the main repo
  propagates to every worktree. `ln -sfn` is idempotent, so re-running
  create with `--reuse` re-links cleanly.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.