AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Worktree

skill-ghostlygawd-recursive-harness-worktree · by GhostlyGawd

Create + manage git worktrees in this harness — when to isolate vs when one is overhead, how to EnterWorktree/ExitWorktree (they live at .claude/worktrees/<name>), and the gotchas that bite here: results don't auto-merge to main; state/ is gitignored so `harness` writes in a worktree miss the main ledger; committed memory/ rides in; shared DB/ports aren't isolated; the guard protects the trunk, n…

No reviews yet
0 installs
39 views
0.0% view→install

Install

$ agentstack add skill-ghostlygawd-recursive-harness-worktree

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-ghostlygawd-recursive-harness-worktree)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Worktree? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Worktree — isolate parallel work without clobbering

A worktree is a second checkout sharing the same .git/ history but with its own HEAD, branch, and working files. Edits in one never touch another — that isolation is the whole point, and the source of every gotcha below. The description above is the always-loaded when; this body is the how. The user should never have to instruct either.

> Re-verified against the live Claude Code worktree docs + empirical repo tests > on 2026-06-14. Docs change under us — see §5; treat the live docs as truth > over this file.

0. Is a worktree actually warranted?

Make one when work could collide on shared files — a second concurrent session, parallel independent tasks, or file-mutating agents running beside other work. Do not wrap a solo single-task session: a worktree you don't need just buys untracked noise and a merge-back tax. When unsure whether two efforts can collide, make it.

1. Create / enter

  • This session into its own worktree: call EnterWorktree with a short

name. It creates .claude/worktrees// at the repo root, on a new branch worktree-, and switches the session's working dir into it. From inside a worktree you cannot nest another — only switch into an existing one via path, and that path must be under .claude/worktrees/.

  • EnterWorktree is UNAVAILABLE under a pinned cwd / from a subagent — you can't move yourself in; spawn an isolation:worktree Agent for file-mutating steps instead (full mechanics in §6, When EnterWorktree is blocked).
  • A separate parallel session: the user runs claude --worktree in

another terminal, or git worktree add ../ -b then claude there.

  • Base ref: new worktrees branch from origin/HEAD by default — a clean

tree matching the remote, NOT your local uncommitted work. To carry unpushed local commits instead, set worktree.baseRef: "head" (project-level .claude/settings.json, or your account config). This repo's account config sets worktree.baseRef: "fresh" (the default — branch from origin/).

2. The gotchas (this is why the skill exists)

  • Results do NOT auto-merge. Changes live on worktree-, isolated.

Reaching main is deliberate: review the diff, open a PR (ONE TRUNK, kernel prime directive 6). Never assume worktree work has reached main.

  • **state/ is gitignored and per-checkout, but the harness CLI resolves to the

MAIN ledger.** state/* is not copied into a worktree. As of follow-up 1d30be, bin/harness resolves state/ to the MAIN checkout via _resolve_state_dir() (git --git-common-dir), so ./bin/harness predict|outcome|corrections|followup|gc run inside a worktree write to the ONE canonical ledger — no longer the worktree's throwaway state/. Caveat (residual): the enforcement HOOKS (log_skill_use, session_start/session_end) still root state at their OWN tree, so skill-usage and similar logged during a worktree session write tree-local and vanish on cleanup until that locked half is fixed (tracked with 3939d8/d72eec). The ledger is the kernel's self-knowledge; a split is silent prediction/correction debt.

  • memory/ is committed → it rides in automatically. It's part of the

checkout, so every worktree has the team memory natively. No junction needed.

  • Shared runtime is NOT isolated. Same DB, ports, services across worktrees.

Worktrees isolate files, not runtime — use separate schemas/containers/ports when running migrations or binding a port.

  • The enforcement guard protects the TRUNK, not your worktree's own copies.

The active guard hook is wired by absolute path to the trunk copy (silo settings.json), so it blocks edits to the trunk's hooks/lint/evals/autonomy.json no matter which worktree you're in — but it does NOT fire on a worktree's OWN copies of those files (verified: editing /hooks/… exits 0). What keeps enforcement safe is ONE TRUNK: a worktree edit can't reach main without a PR + human review. Route enforcement/config changes via /harness-pr; never treat the guard as a backstop for a worktree-local edit.

  • node_modules, build artifacts, gitignored config (.env,

settings.local.json) are NOT copied into a fresh worktree. Plugin enablement is a case of this: /plugin writes a plugin's code to the machine-global account cache (present everywhere), but records its enable flag in .claude/settings.local.json — gitignored, so a Claude-created worktree starts with installed plugins OFF. This repo ships a root .worktreeinclude (gitignore-syntax; only files that are also gitignored get copied) listing .claude/settings.local.json, so plugin enablement and the project permission allowlist ride into every new worktree. (That propagates already-granted permissions.allow entries without re-prompting — intentional here, since worktrees are same-user/same-machine on one repo; drop the include line if you'd rather re-consent per worktree.) Add lines there as a product grows gitignored config it needs. Caveat: a custom WorktreeCreate hook replaces git creation and skips .worktreeinclude (this repo configures none). (Verified 2026-06-18 — live docs + an empirical subagent-worktree test: the copied settings.local.json arrived with its enabledPlugins block intact.) worktree.symlinkDirectories exists for heavy dirs but has known bugs (cleanup can silently fail; a write can replace the symlink with a regular file) — prefer .worktreeinclude, use symlinks only knowingly.

  • Untracked files in a worktree are not automatically THIS repo's work. A

harness worktree can accumulate strays from a different project — you ran a sibling project's task here, or a trial dropped its output in. Before git add/committing an untracked dir, resolve its home first: is the same dir tracked, and newer, in a sibling repo (ls the projects dir; git -C log -- )? If so, the copy here is a stray — remove it, don't commit it into the trunk. (2026-06-17: a 162-file skills/yc-venture-foundry/ was committed into the harness before we caught it lived, newer, as yc-venture-foundry/ in the sibling yc-foundry-experiment; had to git reset + rm.)

3. Cleanup — and where it bites

Two paths with two different bars — don't conflate them:

  • ExitWorktree (interactive): auto-removes the worktree and its branch

only when pristine — no uncommitted changes, no untracked files, and no new commits (any commit counts, pushed or not). Otherwise it prompts keep or remove. A named session also prompts (so you can resume the worktree later) rather than auto-removing.

  • Background sweep (cleanupPeriodDays): a looser bar — auto-removes aged

subagent- and background-session worktrees with no uncommitted changes, no untracked files, and no unpushed commits. --worktree user sessions are never swept.

  • claude --worktree and -p non-interactive runs are NOT auto-cleaned.

Manual: git worktree remove (--force to discard changes), then git worktree prune.

  • **Return to trunk from a worktree with git switch --detach origin/main, never a

bare git switch main.** Inside a LINKED worktree git switch main checks main OUT into that worktree and leaves the PRIMARY checkout detached on an old commit, so main migrates between worktrees and the next session's git switch main fails ("already used by worktree X"). --detach origin/main lands on trunk's commit without moving the main ref. The post_merge_return_to_trunk hook now emits the --detach form when it detects a linked worktree (follow-up 1c9cea); do the same by hand. Detail in references/cleanup.md.

  • Before removing, reconcile this worktree's gitignored state/ (see §2) —

cleanup discards it.

  • Pruning a BATCH is rule-driven, not list-driven. State is non-stationary

while a peer session is live (it can swap a branch, push, or open a PR mid-pass), so: re-read the git worktree list / git branch -vv SNAPSHOT before each destructive batch; drive each delete off a RULE ("merged into main AND not pinned by a worktree AND no open PR"), never a memorized name list; and lean on git's own refusals (git worktree remove without --force refuses a dirty tree; git branch -d not -D refuses an unmerged branch). Run each git worktree remove "" as its OWN command — a for … do git worktree remove … loop is BLOCKED (Guard A's exemption matches the segment START, and the loop body leads with do). Spot live peers by .jsonl mtimes under projects/**.

  • **A locked worktree may be held by THIS session's own long-lived host, not a

dead peer** — locks leak from isolation:worktree agents and outlive them. Before reaping one or killing the holder pid, walk the current shell's process-ancestry (PowerShell: Win32_Process.ParentProcessId from $PID up): if the holder is an ANCESTOR it's your own session, and killing it ends the conversation. Reclaim self-held locks losslessly with git worktree unlock ""git worktree remove "" (never --force/kill), or let them free on the next CLI restart.

  • Full batch-GC empirics — the snapshot/rule/refusal discipline, the Guard-A loop

trap, git branch -d's merged-into-HEAD pitfall, and lock self-vs-peer diagnostics (with provenance) — live in references/cleanup.md.

4. Windows / this repo's housekeeping

  • Paths with spaces (D:\GitHub Projects\...) must be quoted in shell commands.
  • Keep .claude/worktrees/ in .gitignore. The docs recommend it, and it's

confirmed here: a worktree created under .claude/worktrees/ otherwise shows up as ?? .claude/ in the main checkout's git status. (Added to this repo's .gitignore alongside this skill.)

  • Windows symlink behavior is finicky — see the worktree.symlinkDirectories

caveat in §2; prefer .worktreeinclude.

5. Verify against live docs — don't trust this file blindly

Claude Code changes under us, and stale worktree knowledge is dangerous. So:

  • Before anything non-trivial, or the moment behavior surprises you, WebFetch

the canonical page: https://code.claude.com/docs/en/worktrees (and /sub-agents, /settings, /tools-reference). Treat the live docs as truth over this file.

  • If the live docs contradict a step here, follow the docs and **update this

skill in the same motion** (branch + PR) so the next session inherits the correction. A skill that silently drifts is worse than no skill.

6. Sessions: launch, resume, and the guard hatches

Terse rules below; recipes, exact error strings, and provenance live in references/sessions.md (re-verify against live docs if behavior surprises you).

  • Launching the harness against a foreign repo needs

CLAUDE_CONFIG_DIR=/.claude-private/accounts/ claude from inside that repo — a plain claude loads the global config, not the harness, and /cd cannot relocate a live session (ADR 0004). Recipe in references/sessions.md.

  • A session "missing" from /resume is almost never data loss — it is either

still open in a live process (withheld from the picker) or just re-titled. claude --resume opens it regardless; prove integrity with the .jsonl byte-count, not prose. Detail in references/sessions.md.

  • Guard A allows cross-worktree READS; only writes are gated. Read/Glob/Grep a

sibling worktree directly; for a cross-worktree WRITE the env hatch can't be set mid-session, so lead the command with HARNESS_ALLOW_CROSS_WORKTREE=1 (powershell form + Guard B's launch-only hatch in references/sessions.md).

  • **Before reimplementing a trunk fix, reconcile against ALL in-flight work, not

just merged history.** git fetch, then scan merged AND open PRs (gh pr list --state all) AND live sibling worktrees (git worktree list) — a near-complete rebuild can already sit in an OPEN PR or peer worktree, not yet on main. (retro-backlog 2026-06-19 b7488db6+dc1c3470; extended 2026-06-23 d1917edc — re-derived an SDD phase open PR #99 already carried.)

  • Two sessions sharing one checkout race on .git/HEAD. Prevent with separate

worktrees (Guard C's lease blocks a stale-HEAD mutate on main); to commit mid-race, build from git objects (write-treecommit-treepush :refs/heads/…) off a TEMP GIT_INDEX_FILE, never checkout/reset a HEAD a peer holds. (sessions b7488db6 + dc1c3470.)

  • **A finished isolation:worktree agent can leave the session's cwd inside its

now-empty worktree.** Confirm pwd is the PRIMARY checkout before any bin/harness op: the CLI resolves state/ to the main ledger regardless of cwd (§2), but the enforcement HOOKS still log tree-local, so a drifted cwd silently drops skill-usage/session logs. (session b3314a63, 2026-06-23.)

  • When EnterWorktree is blocked (subagent / pinned cwd — see §1), don't fight

the guards inline: spawn an isolation:worktree Agent to do the Write + commit in its own clean worktree, then git push its branch from the primary checkout. Full create-time and amend-time recipes in references/sessions.md.

Rules

  • The user never asks for a worktree and never recites the gotchas — that's this

skill's job.

  • A worktree is single-agent, single-branch, temporary. Integration happens via

PR to main, never a merge inside it.

  • Worktree changes are not on main until a PR merges them. Say so plainly;

never imply otherwise.

  • Enforcement-layer / config changes (settings keys, .worktreeinclude, hooks)

go via /harness-pr — and the trunk guard won't catch a worktree-local edit, so don't rely on it as a backstop.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.