This commit is contained in:
Jayesh Betala 2026-07-14 17:01:33 -07:00 committed by GitHub
commit 0f89264099
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 195 additions and 44 deletions

View File

@ -23,8 +23,8 @@ triggers:
## When to invoke this skill
Loads the most recent
saved state (across all branches by default) so you can pick up where you
left off — even across Conductor workspace handoffs.
saved state (preferring the current branch, falling back across branches) so
you can pick up where you left off — even across Conductor workspace handoffs.
Use when asked to "resume", "restore context", "where was I", or
"pick up where I left off". Pair with /context-save.
Formerly /checkpoint resume — renamed because Claude Code treats /checkpoint
@ -791,13 +791,19 @@ context and present it clearly so the user can resume work without losing a beat
**HARD GATE:** Do NOT implement code changes. This skill only reads saved
context files and presents the summary.
**Default: load the most recent saved context across ALL branches.** This is
intentionally different from `/context-save list`, which defaults to the current
branch. `/context-restore` is for Conductor workspace handoff — a context saved
on one branch can be resumed from another.
**Default: prefer the most recent checkpoint saved on the CURRENT branch; if
this branch has none, fall back to the most recent across ALL branches.** The
fallback is for Conductor workspace handoff — a context saved on one branch can
be resumed from another. The current-branch preference exists because every
worktree of a repo shares one checkpoints directory (same origin-derived slug),
so without it `/context-restore` in one worktree could silently load a sibling
worktree's newer checkpoint.
**Do NOT filter the candidate set by current branch.** The `list` flow does
that; `/context-restore` does not.
**Do NOT hard-filter the candidate set to the current branch** — other-branch
checkpoints stay in the set as a fallback. They are just ordered *after* the
current branch's own, so a current-branch save is never shadowed by a newer
sibling-worktree save. (`/context-save list` is the flow that hard-scopes to one
branch.)
---
@ -828,27 +834,53 @@ else
# copies/rsync). Filesystem mtime drifts and is not authoritative.
# 2. On macOS, `find ... | xargs ls -1t` with zero results falls back to
# listing cwd. `sort -r` on empty input cleanly returns nothing.
# Cap at 20 most recent: a user with 10k saved files shouldn't blow the
# context window just listing them. /context-save list handles pagination.
FILES=$(find "$CHECKPOINT_DIR" -maxdepth 1 -name "*.md" -type f 2>/dev/null | sort -r | head -20)
if [ -z "$FILES" ]; then
# Scan the 200 newest so a current-branch checkpoint sitting below a burst of
# sibling-worktree saves can still be found; the result is capped at 20 below.
ALL=$(find "$CHECKPOINT_DIR" -maxdepth 1 -name "*.md" -type f 2>/dev/null | sort -r | head -200)
if [ -z "$ALL" ]; then
echo "NO_CHECKPOINTS"
else
# Order current-branch checkpoints first, other branches after. A git branch
# is checked out in at most one worktree, and all worktrees of a repo share
# one checkpoints dir (same origin-derived slug), so without this preference
# `/context-restore` in worktree A could load worktree B's newer checkpoint.
# Cross-branch resume (Conductor handoff) is preserved as the fallback: when
# the current branch has no checkpoint, the full newest-first set is used.
# CURRENT_BRANCH may be pre-set (tests); otherwise resolve it from git.
: "${CURRENT_BRANCH:=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)}"
SAME=""; OTHER=""
while IFS= read -r f; do
[ -n "$f" ] || continue
b=$(grep -m1 '^branch:' "$f" 2>/dev/null | sed 's/^branch:[[:space:]]*//')
if [ -n "$CURRENT_BRANCH" ] && [ "$b" = "$CURRENT_BRANCH" ]; then
SAME="${SAME}${f}
"
else
OTHER="${OTHER}${f}
"
fi
done <<EOF
$ALL
EOF
# Cap at 20: a user with 10k saved files shouldn't blow the context window.
FILES=$(printf '%s%s' "$SAME" "$OTHER" | grep -v '^[[:space:]]*$' | head -20)
echo "$FILES"
fi
fi
```
**Candidates include every `.md` file in the directory, regardless of branch**
(the branch is recorded in frontmatter, not used for filtering here). This
enables Conductor workspace handoff.
**Candidates include every `.md` file in the directory**, but they are ordered
**current-branch-first** (the branch is read from each file's `branch:`
frontmatter). Other-branch files stay in the set as a fallback, which preserves
Conductor workspace handoff when the current branch has no checkpoint of its own.
### Step 2: Load the right file
- If the user specified a title fragment or number: find the matching file among
the candidates.
- Otherwise: load the **first file returned by the `sort -r` above** — that is
the newest `YYYYMMDD-HHMMSS` prefix, which is the canonical "most recent."
- Otherwise: load the **first file returned by Step 1 above** — that is the
newest `YYYYMMDD-HHMMSS` checkpoint for the current branch, or, if the current
branch has none, the newest across all branches.
Read the chosen file and present a summary:
@ -900,9 +932,10 @@ state, then `/context-restore` will find it."
## Important Rules
- **Never modify code.** This skill only reads saved files and presents them.
- **Always search across all branches by default.** Cross-branch resume is the
whole point. Only filter by branch if the user explicitly asks via a
title-fragment match that happens to be branch-specific.
- **Prefer the current branch's own checkpoint, but keep all branches in the
fallback set.** Cross-branch resume (Conductor handoff) still works when the
current branch has no checkpoint; it just no longer lets a sibling worktree's
newer save shadow this branch's own.
- **"Most recent" means the filename `YYYYMMDD-HHMMSS` prefix**, not
`ls -1t` (filesystem mtime). Filenames are stable across file-system
operations; mtime is not.

View File

@ -4,8 +4,8 @@ preamble-tier: 2
version: 1.0.0
description: |
Restore working context saved earlier by /context-save. Loads the most recent
saved state (across all branches by default) so you can pick up where you
left off — even across Conductor workspace handoffs.
saved state (preferring the current branch, falling back across branches) so
you can pick up where you left off — even across Conductor workspace handoffs.
Use when asked to "resume", "restore context", "where was I", or
"pick up where I left off". Pair with /context-save.
Formerly /checkpoint resume — renamed because Claude Code treats /checkpoint
@ -35,13 +35,19 @@ context and present it clearly so the user can resume work without losing a beat
**HARD GATE:** Do NOT implement code changes. This skill only reads saved
context files and presents the summary.
**Default: load the most recent saved context across ALL branches.** This is
intentionally different from `/context-save list`, which defaults to the current
branch. `/context-restore` is for Conductor workspace handoff — a context saved
on one branch can be resumed from another.
**Default: prefer the most recent checkpoint saved on the CURRENT branch; if
this branch has none, fall back to the most recent across ALL branches.** The
fallback is for Conductor workspace handoff — a context saved on one branch can
be resumed from another. The current-branch preference exists because every
worktree of a repo shares one checkpoints directory (same origin-derived slug),
so without it `/context-restore` in one worktree could silently load a sibling
worktree's newer checkpoint.
**Do NOT filter the candidate set by current branch.** The `list` flow does
that; `/context-restore` does not.
**Do NOT hard-filter the candidate set to the current branch** — other-branch
checkpoints stay in the set as a fallback. They are just ordered *after* the
current branch's own, so a current-branch save is never shadowed by a newer
sibling-worktree save. (`/context-save list` is the flow that hard-scopes to one
branch.)
---
@ -72,27 +78,53 @@ else
# copies/rsync). Filesystem mtime drifts and is not authoritative.
# 2. On macOS, `find ... | xargs ls -1t` with zero results falls back to
# listing cwd. `sort -r` on empty input cleanly returns nothing.
# Cap at 20 most recent: a user with 10k saved files shouldn't blow the
# context window just listing them. /context-save list handles pagination.
FILES=$(find "$CHECKPOINT_DIR" -maxdepth 1 -name "*.md" -type f 2>/dev/null | sort -r | head -20)
if [ -z "$FILES" ]; then
# Scan the 200 newest so a current-branch checkpoint sitting below a burst of
# sibling-worktree saves can still be found; the result is capped at 20 below.
ALL=$(find "$CHECKPOINT_DIR" -maxdepth 1 -name "*.md" -type f 2>/dev/null | sort -r | head -200)
if [ -z "$ALL" ]; then
echo "NO_CHECKPOINTS"
else
# Order current-branch checkpoints first, other branches after. A git branch
# is checked out in at most one worktree, and all worktrees of a repo share
# one checkpoints dir (same origin-derived slug), so without this preference
# `/context-restore` in worktree A could load worktree B's newer checkpoint.
# Cross-branch resume (Conductor handoff) is preserved as the fallback: when
# the current branch has no checkpoint, the full newest-first set is used.
# CURRENT_BRANCH may be pre-set (tests); otherwise resolve it from git.
: "${CURRENT_BRANCH:=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)}"
SAME=""; OTHER=""
while IFS= read -r f; do
[ -n "$f" ] || continue
b=$(grep -m1 '^branch:' "$f" 2>/dev/null | sed 's/^branch:[[:space:]]*//')
if [ -n "$CURRENT_BRANCH" ] && [ "$b" = "$CURRENT_BRANCH" ]; then
SAME="${SAME}${f}
"
else
OTHER="${OTHER}${f}
"
fi
done <<EOF
$ALL
EOF
# Cap at 20: a user with 10k saved files shouldn't blow the context window.
FILES=$(printf '%s%s' "$SAME" "$OTHER" | grep -v '^[[:space:]]*$' | head -20)
echo "$FILES"
fi
fi
```
**Candidates include every `.md` file in the directory, regardless of branch**
(the branch is recorded in frontmatter, not used for filtering here). This
enables Conductor workspace handoff.
**Candidates include every `.md` file in the directory**, but they are ordered
**current-branch-first** (the branch is read from each file's `branch:`
frontmatter). Other-branch files stay in the set as a fallback, which preserves
Conductor workspace handoff when the current branch has no checkpoint of its own.
### Step 2: Load the right file
- If the user specified a title fragment or number: find the matching file among
the candidates.
- Otherwise: load the **first file returned by the `sort -r` above** — that is
the newest `YYYYMMDD-HHMMSS` prefix, which is the canonical "most recent."
- Otherwise: load the **first file returned by Step 1 above** — that is the
newest `YYYYMMDD-HHMMSS` checkpoint for the current branch, or, if the current
branch has none, the newest across all branches.
Read the chosen file and present a summary:
@ -144,9 +176,10 @@ state, then `/context-restore` will find it."
## Important Rules
- **Never modify code.** This skill only reads saved files and presents them.
- **Always search across all branches by default.** Cross-branch resume is the
whole point. Only filter by branch if the user explicitly asks via a
title-fragment match that happens to be branch-specific.
- **Prefer the current branch's own checkpoint, but keep all branches in the
fallback set.** Cross-branch resume (Conductor handoff) still works when the
current branch has no checkpoint; it just no longer lets a sibling worktree's
newer save shadow this branch's own.
- **"Most recent" means the filename `YYYYMMDD-HHMMSS` prefix**, not
`ls -1t` (filesystem mtime). Filenames are stable across file-system
operations; mtime is not.

View File

@ -40,7 +40,7 @@
},
"context-restore": {
"lead": "Restore working context saved earlier by /context-save.",
"routing": "Loads the most recent\nsaved state (across all branches by default) so you can pick up where you\nleft off — even across Conductor workspace handoffs.\nUse when asked to \"resume\", \"restore context\", \"where was I\", or\n\"pick up where I left off\". Pair with /context-save.\nFormerly /checkpoint resume — renamed because Claude Code treats /checkpoint\nas a native rewind alias in current environments.",
"routing": "Loads the most recent\nsaved state (preferring the current branch, falling back across branches) so\nyou can pick up where you left off — even across Conductor workspace handoffs.\nUse when asked to \"resume\", \"restore context\", \"where was I\", or\n\"pick up where I left off\". Pair with /context-save.\nFormerly /checkpoint resume — renamed because Claude Code treats /checkpoint\nas a native rewind alias in current environments.",
"voice_line": null
},
"context-save": {

View File

@ -36,15 +36,33 @@ echo "TITLE_SLUG=$TITLE_SLUG"
echo "FILE=$FILE"
`;
// The exact find + sort + head used by context-restore/SKILL.md Step 1.
// The exact selection used by context-restore/SKILL.md Step 1: scan newest 200,
// order current-branch checkpoints first (fallback: all branches), cap at 20.
// CURRENT_BRANCH is injected via env in tests; the skill resolves it from git.
const RESTORE_FIND_BASH = `
if [ ! -d "$CHECKPOINT_DIR" ]; then
echo "NO_CHECKPOINTS"
else
FILES=$(find "$CHECKPOINT_DIR" -maxdepth 1 -name "*.md" -type f 2>/dev/null | sort -r | head -20)
if [ -z "$FILES" ]; then
ALL=$(find "$CHECKPOINT_DIR" -maxdepth 1 -name "*.md" -type f 2>/dev/null | sort -r | head -200)
if [ -z "$ALL" ]; then
echo "NO_CHECKPOINTS"
else
: "\${CURRENT_BRANCH:=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)}"
SAME=""; OTHER=""
while IFS= read -r f; do
[ -n "$f" ] || continue
b=$(grep -m1 '^branch:' "$f" 2>/dev/null | sed 's/^branch:[[:space:]]*//')
if [ -n "$CURRENT_BRANCH" ] && [ "$b" = "$CURRENT_BRANCH" ]; then
SAME="\${SAME}\${f}
"
else
OTHER="\${OTHER}\${f}
"
fi
done <<EOF
$ALL
EOF
FILES=$(printf '%s%s' "$SAME" "$OTHER" | grep -v '^[[:space:]]*$' | head -20)
echo "$FILES"
fi
fi
@ -312,6 +330,73 @@ describe('context-restore: find + sort + head cap', () => {
});
});
// ─── Current-branch preference (#2052) ──────────────────────────────────────
//
// All worktrees of a repo share one origin-derived slug → one checkpoints dir.
// Restore must prefer the CURRENT branch's own checkpoint so a sibling
// worktree's newer save can't shadow it, while still falling back across
// branches (Conductor handoff) when the current branch has none.
describe('context-restore: current-branch preference (#2052)', () => {
let tmp: string;
beforeEach(() => { tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'ctx-branch-')); });
afterEach(() => { try { fs.rmSync(tmp, { recursive: true, force: true }); } catch {} });
function writeCheckpoint(ts: string, branch: string | null): string {
const file = `${tmp}/${ts}-work.md`;
const fm = branch === null
? `---\nstatus: in-progress\n---\n`
: `---\nstatus: in-progress\nbranch: ${branch}\n---\n`;
fs.writeFileSync(file, fm);
return file;
}
function firstCandidate(currentBranch?: string): string {
const env: Record<string, string> = { CHECKPOINT_DIR: tmp };
if (currentBranch !== undefined) env.CURRENT_BRANCH = currentBranch;
const out = runBash(RESTORE_FIND_BASH, env).stdout;
return out.trim().split('\n').filter(Boolean)[0] ?? '';
}
test('the bug: current-branch save is NOT shadowed by a newer sibling-worktree save', () => {
const mine = writeCheckpoint('20260101-120000', 'feature-a'); // older, my branch
writeCheckpoint('20260619-120000', 'feature-b'); // newer, sibling worktree
// On feature-a, restore must load feature-a's own (older) checkpoint.
expect(firstCandidate('feature-a')).toBe(mine);
});
test('fallback: current branch has no checkpoint → newest across all branches (Conductor handoff)', () => {
writeCheckpoint('20260101-120000', 'feature-a');
const newest = writeCheckpoint('20260619-120000', 'feature-b');
// On feature-c (no own checkpoint), cross-branch resume still works.
expect(firstCandidate('feature-c')).toBe(newest);
});
test('back-compat: empty current branch (non-git) → newest across all', () => {
writeCheckpoint('20260101-120000', 'feature-a');
const newest = writeCheckpoint('20260619-120000', 'feature-b');
expect(firstCandidate('')).toBe(newest);
});
test('checkpoints without a branch frontmatter still rank as fallback, never lost', () => {
const mine = writeCheckpoint('20260101-120000', 'feature-a');
writeCheckpoint('20260301-120000', null); // legacy save, no branch field
const out = runBash(RESTORE_FIND_BASH, { CHECKPOINT_DIR: tmp, CURRENT_BRANCH: 'feature-a' }).stdout;
const lines = out.trim().split('\n').filter(Boolean);
expect(lines[0]).toBe(mine); // current branch first
expect(lines.length).toBe(2); // legacy file is still present
});
test('within the current branch, ordering stays newest-first', () => {
const older = writeCheckpoint('20260101-120000', 'feature-a');
const newer = writeCheckpoint('20260619-120000', 'feature-a');
const out = runBash(RESTORE_FIND_BASH, { CHECKPOINT_DIR: tmp, CURRENT_BRANCH: 'feature-a' }).stdout;
const lines = out.trim().split('\n').filter(Boolean);
expect(lines[0]).toBe(newer);
expect(lines[1]).toBe(older);
});
});
// ─── Migration HOME guard ──────────────────────────────────────────────────
describe('migration v1.1.3.0: HOME guard', () => {