Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6c43376
fix(#4941): reap-orphans names .claude/worktrees residue git has forg…
behruznassre Oct 6, 2026
b97964a
chore(#4941): add changeset
behruznassre Oct 6, 2026
c87a758
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 6, 2026
0afab4c
test(#4941): pin the mtime-guard boundary and every residue scan status
behruznassre Oct 7, 2026
f7ba2a0
fix(#4941): an unresolvable default branch no longer skips the residu…
behruznassre Oct 7, 2026
629f9f7
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 7, 2026
b7a2ae6
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 8, 2026
c9d10d1
fix(#4941): surface reap-orphans residue to the workflow callers
behruznassre Oct 9, 2026
f6a761f
fix(#4941): quote residue paths, say a failed scan on stderr
behruznassre Oct 9, 2026
93cff1e
fix(#4941): ask git for the checkout instead of guessing from the git…
behruznassre Oct 9, 2026
7ba53cf
test(#4941): row 48 carve-out for the reap-orphans call-line sweep
behruznassre Oct 9, 2026
e11d158
fix(#4941): remove harness worktree residue behind guards, and keep t…
behruznassre Oct 10, 2026
903e1d6
fix(#4941): remove residue only on positive evidence, through a verif…
behruznassre Oct 10, 2026
2d60a4a
fix(#4941): read the checkout top through --show-cdup, walk node_modu…
behruznassre Oct 10, 2026
8b1d5b9
test(#4941): use an instruction-shaped fixture name the prompt-inject…
behruznassre Oct 10, 2026
4a4ae79
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 10, 2026
11cdce6
fix(#4941): rename residue to an unguessable name before removing it;…
behruznassre Oct 10, 2026
f0a3762
Merge remote-tracking branch 'origin/fix/4941-reap-unregistered-resid…
behruznassre Oct 10, 2026
74a8564
test(#4941): drop the colon from the instruction-shaped fixture name,…
behruznassre Oct 10, 2026
7c239b4
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 11, 2026
5085e70
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 12, 2026
587c15d
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 12, 2026
b379228
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 13, 2026
f0b5f93
Merge remote-tracking branch 'upstream/next' into fix/4941-reap-unreg…
behruznassre Oct 14, 2026
c0e3044
fix(#4941): pin the residue walk bound on both sides; require an id a…
behruznassre Oct 14, 2026
fcaf54e
fix(#4941): read tracked content from the checkout's own index, not a…
behruznassre Oct 14, 2026
3797af0
fix(#4941): sweep only when git's repository is this checkout's own (…
behruznassre Oct 14, 2026
086e68e
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 14, 2026
67d1800
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 14, 2026
997ba84
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 15, 2026
f9f3044
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 16, 2026
5afc194
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 16, 2026
a9fdd03
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 16, 2026
f956af3
Merge remote-tracking branch 'upstream/next' into fix/4941-reap-unreg…
behruznassre Oct 17, 2026
5c789d2
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 17, 2026
a491a39
fix(#4941): reclaim a .gsd-reap-* directory the sweep stranded mid-re…
behruznassre Oct 18, 2026
39b0a2a
fix(#4941): name the reserved .gsd-reap-* path when a rename back fails
behruznassre Oct 18, 2026
b23af8f
fix(#4941): a residue removal that finds its directory already gone i…
behruznassre Oct 18, 2026
d89d8d8
Merge remote-tracking branch 'upstream/next' into fix/4941-reap-unreg…
behruznassre Oct 18, 2026
6ed523c
fix(#4941): leave a reserved .gsd-reap name renamed inside the guard …
behruznassre Oct 19, 2026
570bc70
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 19, 2026
b5a548a
Merge branch 'next' into fix/4941-reap-unregistered-residue
behruznassre Oct 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/plucky-eagles-chatter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
type: Fixed
pr: 5233
---
**`worktree.reap-orphans` now removes a `.claude/worktrees/agent-*` directory left by an incomplete harness teardown, and only when every residue guard in `docs/CLI-TOOLS.md` passes** — the sweep used to miss such a directory and report `reaped: 0`; its three workflow callers now keep stderr, so a summary of what was removed or kept reaches the transcript, along with any runtime-build notice or Node warning, since `>/dev/null` discards only the JSON (#4941).
2 changes: 1 addition & 1 deletion CONTEXT.md

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions docs/CLI-TOOLS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,16 @@ Known limit: the kill terminates `git`, not the hook process it spawned. A hook

---

### Orphan sweep

```bash
# Reap orphaned agent worktrees; run at the start of /gsd-quick, /gsd-quick-batch and execute-phase.
# Returns JSON: { ok: true, reaped, entries: [{ path, status, reason }], scan: { admin_dir, residue_dir } }
gsd-tools query worktree.reap-orphans
```

It reaps locked worktrees in `.git/worktrees/` whose owner process is dead and whose branch is merged, and removes a `.claude/worktrees/agent-<id>` directory a harness teardown left behind only when it is a real, non-empty directory with no `.git` entry, not in `git worktree list`, older than five minutes, with a harness branch (`agent-<id>` or `worktree-agent-<id>`; `.gsd-reap-<16 hex>` is reserved for a directory the sweep stranded mid-removal, and one with that name needs neither the name nor a branch, but is left alone until five minutes after it was renamed, by its ctime, since until then it may be another sweep's removal in progress), no git-tracked file and no repository inside it, under a `.claude/worktrees` that is a real directory of the checkout (not a link). A candidate that fails a check is listed with `status: "skipped"` and the check's `reason` and left on disk; a child that is not a candidate (a link, one with a `.git` entry, one git still lists, a young or empty one) is left without a row. `scan` says which locations were read, so `reaped: 0` never stands for "did not look": `admin_dir` is `scanned`, `absent`, `unreadable`, `git_dir_unresolved` or `default_branch_unresolved`; `residue_dir` is `scanned`, `absent`, `unreadable`, `aliased` (`.claude` or `.claude/worktrees` is a link), `not_main_checkout` (run from a linked worktree — the sweep runs from the main checkout), `top_unresolved`, `git_mismatch` (git is pointed at another repository or work tree by `GIT_DIR`, `GIT_WORK_TREE` or `core.worktree`, so its answers are not about this checkout) or `not_scanned`. The workflow callers discard the JSON and keep stderr, which names removed directories (escaped, at most five), counts kept ones by reason, and says when `.claude/worktrees` was not swept. Wave cleanup blocks an entry whose directory exists with no `.git` entry as `reason: "worktree_unregistered"`.

## Graphify

Build, query, and inspect the project knowledge graph in `.planning/graphs/`. Requires `graphify.enabled: true` in `config.json` (see [Configuration Reference](CONFIGURATION.md#graphify-settings)).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ if [ "$ISOLATION" = "none" ] && [ "$USE_WORKTREES" != "false" ]; then
fi

# Sweep orphaned locked worktrees from prior crashed sessions (#3707).
[ "$ISOLATION" != "none" ] && gsd_run query worktree.reap-orphans 2>/dev/null || true
[ "$ISOLATION" != "none" ] && gsd_run query worktree.reap-orphans >/dev/null || true
# Auto-degrade if HEAD diverged from the fork base (#683) — both isolation models.
if [ "$ISOLATION" != "none" ]; then
_SHOULD_DEGRADE=$(gsd_run query worktree.base-check --mode "$ISOLATION" --pick shouldDegrade 2>/dev/null || true)
Expand Down
2 changes: 1 addition & 1 deletion gsd-core/workflows/quick-batch.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ when `ISOLATION = "harness-worktree"`, else empty.
If `USE_WORKTREES` is not `"false"`, sweep orphaned worktrees before dispatching anything (mirrors `/gsd:quick`'s own startup sweep):
```bash
if [ "$USE_WORKTREES" != "false" ]; then
gsd_run query worktree.reap-orphans 2>/dev/null || true
gsd_run query worktree.reap-orphans >/dev/null || true
fi
```

Expand Down
2 changes: 1 addition & 1 deletion gsd-core/workflows/quick.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ If `USE_WORKTREES` is not `"false"`, run a startup orphan sweep before spawning

```bash
if [ "$USE_WORKTREES" != "false" ]; then
gsd_run query worktree.reap-orphans 2>/dev/null || true
gsd_run query worktree.reap-orphans >/dev/null || true
fi
```

Expand Down
1 change: 1 addition & 0 deletions scripts/lib/macos-conformance-tier.generated.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ module.exports = {
"tests/workflow-shell-pinning.test.cjs",
"tests/workstream-inventory.test.cjs",
"tests/workstream.test.cjs",
"tests/worktree-safety-reap.test.cjs",
"tests/worktree-safety.test.cjs",
"tests/worktree.test.cjs",
],
Expand Down
1 change: 1 addition & 0 deletions scripts/lib/platform-conformance-tier.generated.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ module.exports = {
"tests/workstream-scoped-paths.test.cjs",
"tests/workstream.test.cjs",
"tests/worktree-cleanup.test.cjs",
"tests/worktree-safety-reap.test.cjs",
"tests/worktree-safety.test.cjs",
"tests/worktree.test.cjs",
"tests/xtrace-phase-timing.platform.test.cjs",
Expand Down
Loading
Loading