Pass design specs, handoff prompts, or any other shared artefact between two parallel Claude Code sessions that are working in different git worktrees on different branches — without merging the producing branch to main first. Use when: (1) session A produced design docs / a handoff prompt / a mockup file on branch X, (2) session B (different cwd / different worktree, on branch Y branched from main) reports "the file doesn't exist" or "I can't find the design spec you mentioned", (3) you want...
Scanned 6/5/2026
Install via CLI
openskills install wan-huiyan/agent-traffic-control---
name: cross-worktree-spec-handoff-via-checkout-paths
description: |
Pass design specs, handoff prompts, or any other shared artefact between
two parallel Claude Code sessions that are working in different git
worktrees on different branches — without merging the producing branch
to main first. Use when: (1) session A produced design docs / a handoff
prompt / a mockup file on branch X, (2) session B (different cwd /
different worktree, on branch Y branched from main) reports "the file
doesn't exist" or "I can't find the design spec you mentioned",
(3) you want B unblocked NOW without a PR review cycle, (4) both
worktrees are local checkouts of the same repo (share `.git`).
The unblock: `git checkout <producing-branch> -- <paths>` from inside
B's worktree pulls the files in as staged additions, no merge needed.
Also covers the related gitignore-exception trick when the artefact
files are blanket-ignored (e.g., `*.html` in a repo that produces HTML
deliverables but also keeps design mockups under `docs/`).
v1.1.0 (2026-05-26) adds the diagnostic-search variant: when the user
says "execute <path/to/file>" but the file isn't in your worktree, use
`git log --all --oneline --diff-filter=A -- "<path>"` + `git branch -a
--contains <sha>` to find which branch holds it, then `git show
<branch>:<path>` for read-only access without modifying your tree.
author: Claude Code
version: 1.1.0
date: 2026-05-26
---
# Cross-worktree spec handoff via `git checkout <branch> -- <paths>`
## Problem
You ran a brainstorming / design session in Claude Code session A. Output:
design spec doc, a handoff prompt, a vibe mockup HTML. You committed them
on branch `worktree-spec-A` in `.claude/worktrees/spec-A/`.
You then started Claude Code session B in a different worktree, on a fresh
branch `feat/something-B` branched from `main`. Session B is supposed to
consume the design spec — but the spec doc, handoff prompt, and mockup
files **don't exist** in B's working tree, because B's branch was cut from
main before A's commits landed and the commits never made it to main.
Session B reports: "the referenced design spec files don't exist in the
handover. Let me look at what's available." → it's blocked.
The naive fix is "merge A's branch into main, then B pulls main". That
needs a PR review cycle. Slow.
## Context / Trigger Conditions
All of:
- Two (or more) Claude Code sessions are running in parallel, in
**different worktrees** of the same repo. (`git worktree list` shows
multiple paths.)
- Session A (the producer) committed artefacts — design docs, plans, spec
files, mockups, fixtures, prompts — on a branch that is **not** the base
branch of session B.
- Session B (the consumer) is on a branch branched from `main` (or any
ancestor that predates A's commits) and cannot see A's files via
`ls` or Read.
- B reports a "file not found" / "doesn't exist" / "can't see the spec"
symptom referencing files that you (or session A) know exist on disk
*somewhere else*.
Smoking-gun signals:
- The missing file's path matches one you (or A) named in a recent message
("the spec is at `docs/plans/...`").
- `git log --all --oneline -- <path>` shows the file was committed on a
branch that isn't an ancestor of B's branch.
- `git worktree list` shows 2+ worktrees; the file exists in one but not
the other.
Note: this is distinct from
[[multi-worktree-file-url-stale-content]] (browser opens stale file://
URL), [[subagent-bash-cd-wrong-worktree]] (subagent operates in the wrong
cwd), and [[worktree-outer-ls-mistaken-for-main-state]] (parent dir
listing not reflecting worktree state). Those are all "wrong working
directory" issues; this one is "right working directory, file genuinely
isn't there yet because it lives on a different branch."
## Solution
### Variant — handoff prompt missing from current worktree (read-only diagnostic)
Added 2026-05-26 (v1.1.0). The original skill below assumes you already know
which branch holds the missing artefact. If you DON'T — the user told you to
execute a handoff prompt (e.g., `docs/handoffs/session_N_prompt.md`) and it
doesn't exist in your current worktree — start with this diagnostic search
BEFORE jumping to Step 1.
Trigger: user says "execute `docs/handoffs/session_NN_prompt.md`" (or any
specific file path) and `Read` / `ls` reports the file doesn't exist on disk.
```bash
# 1. Find which commits anywhere in the repo first introduced this file
git log --all --oneline --diff-filter=A -- "*session_NN_prompt*" 2>&1 | head -10
# Example output:
# 5307eb9 docs(s69): handoff + S70 prompt — 3 PRs shipped ...
# 79d27d3 docs(s69): handoff + S70 prompt — 3 PRs shipped ...
# 2. Find which branches contain those commits
git branch -a --contains 5307eb9 2>&1 | head -5
# Example output:
# remotes/origin/starbucks-uk
# 3. Read the file directly without modifying your working tree
git show origin/starbucks-uk:docs/handoffs/session_70_prompt.md | less
# or pipe to sed/grep for a section, or `gh` if it's already on GitHub
```
This is **read-only** — no checkout, no working-tree changes. Useful when
you just need to **read** the prompt to understand what to do; the full
Step 1→4 checkout flow below is for when subagents or downstream tooling
need the file to exist on disk in your worktree.
If `git log --all --diff-filter=A -- <path>` returns empty:
- The file was committed under a different filename (was renamed) — try
without the path filter: `git log --all --oneline --grep="session_NN"`
- The file was never committed (only exists on someone else's local
worktree, never pushed) — you can't recover it via git
- The path is wrong — double-check with `git ls-tree -r origin/<branch> --
| grep -i <keyword>`
After you confirm the branch holding the file, proceed to Step 1 below if
you need it on disk; or just `git show <branch>:<path>` repeatedly if
read-only access is sufficient.
### Step 1 — confirm the diagnosis
From inside session B's worktree:
```bash
# Is the file on disk here?
ls path/to/the/file 2>/dev/null && echo "present" || echo "missing"
# What branches contain commits touching this path?
git log --all --oneline -- path/to/the/file | head -5
# Does B's current branch include any of those commits?
git merge-base --is-ancestor <commit-from-log> HEAD && echo "in B" || echo "not in B"
```
If "missing" + commits exist on a branch + that branch is not an ancestor
of B → confirmed.
### Step 2 — pull the files into B's working tree
From inside B's worktree (cwd is B's checkout):
```bash
git checkout <producing-branch> -- \
path/to/file-1 \
path/to/file-2 \
path/to/directory/ # trailing slash works for whole dirs
```
This is `git checkout <tree-ish> -- <path>`. It:
- Brings the file contents from `<producing-branch>` into B's working tree.
- Stages the additions/modifications (visible in `git status` as "Changes
to be committed").
- Does **not** switch branches, does **not** create a merge commit, does
**not** affect any other file in B's tree.
- Works without a fetch when both branches are local (both worktrees share
`.git`).
- Works for both files and directories. For directories, every file under
the directory at that commit is pulled in.
### Step 3 — if the file is gitignored, add an exception
If the file you're pulling in is gitignored (common for HTML mockups in a
repo whose `.gitignore` has a blanket `*.html`), the checkout still works
(it brings the bytes into the working tree), but the file shows as
*staged-add despite being ignored* — slightly confusing. To track it
going forward:
```bash
# Find the ignore rule
git check-ignore -v <path>
# .gitignore:N:*.html docs/plans/.../foo.html
# Add an exception. Don't broaden too far — scope to the design directory.
echo "!docs/plans/**/*.html" >> .gitignore
```
Then commit `.gitignore` together with the checked-out files so future
edits stay tracked.
### Step 4 — commit on B's branch
```bash
git add .gitignore # if you added an exception
git commit -m "import spec + mockups from worktree-spec-A for design pass"
```
The spec now lives on B's branch too. When B's PR eventually opens, it
includes both the spec it consumed and the design it produced — single
self-contained PR. (If A's branch later also opens a PR with the same
files, GitHub's squash-merge will deduplicate cleanly.)
## Verification
- `ls <path>` from B's worktree now lists the file.
- `git status` shows the files as "Changes to be committed: new file: ..."
(or "modified" if they existed at older content).
- The consuming Claude Code session (B) can `Read` the files without
"file not found" errors.
## Example
This session:
```
.claude/worktrees/session13-resume/ ← session A (producer)
branch: worktree-session13-resume
HEAD: 303da93 docs(ui): vibe mockups + gitignore exception
files: docs/plans/2026-05-26-amc-brief-runner-ui-v2-{design,handoff-prompt}.md
docs/plans/2026-05-26-vibe-mockups/{index,option-a,option-b,option-c}.html
/Users/huiyanwan/Documents/AMC-handover/ ← session B (consumer)
branch: feat/amc-brief-runner-ui-mockup-v2 (branched from main = 755e042)
HEAD: 755e042 — does NOT include any of A's commits
Symptom: session B's frontend-design pass reported
"The referenced design spec and visual anchor files don't exist."
```
Unblock from B's worktree:
```bash
cd /Users/huiyanwan/Documents/AMC-handover
git checkout worktree-session13-resume -- \
docs/plans/2026-05-26-amc-brief-runner-ui-v2-design.md \
docs/plans/2026-05-26-amc-brief-runner-ui-v2-handoff-prompt.md \
docs/plans/2026-05-26-vibe-mockups/ \
.gitignore
git status # all five files staged
```
Session B's frontend-design pass now reads the files and proceeds.
## Notes
- **Local-only branches work too.** Because both worktrees share `.git`,
you don't need to push the producer branch to origin first. (Pushing is
still a good idea if anyone else needs the work, or if you'll open a PR
later — but it's not required for the cross-worktree handoff itself.)
- **Don't `git checkout <branch>` (no `--`)** — that switches branches in
B's worktree and loses B's in-progress work. The `--` is the critical
delimiter that makes it a path-restoration, not a branch-switch.
- **Order matters for big handoffs**: pull `.gitignore` first (so newly
imported HTML files aren't surfaced as "ignored" oddities in git
status), then the spec / mockup files.
- **Subagents spawned by B** also need the files visible in B's cwd — the
checkout has to happen before they're dispatched. If a subagent already
failed with "file not found", do the checkout in the parent session and
redispatch.
- **Alternative when you don't want it on B's branch yet**: use
`git show <branch>:<path>` to print a file's content without modifying
the working tree. Useful for one-off "let me see what A's spec says"
but doesn't help if B's subagents need to `Read` the file (they'd need
it on disk).
- **Distinct from `claude-design-handoff-bundle`**: that skill is for
fetching gzipped tar bundles from `claude.ai/design` URLs (a different
artefact-transfer mechanism, between Claude Design and Claude Code).
This skill is local: between two Claude Code sessions in different
worktrees of the same repo.
## References
- `git checkout <tree-ish> -- <paths>`: see
[git-checkout(1)](https://git-scm.com/docs/git-checkout) — "Checkout
paths out of the index or out of another commit." Modern git also
exposes this as `git restore --source=<branch> <paths>`; both work,
`checkout` is more widely understood.
- Related: [[multi-worktree-file-url-stale-content]],
[[subagent-bash-cd-wrong-worktree]],
[[worktree-outer-ls-mistaken-for-main-state]],
[[brainstorm-html-mockup-with-design-tokens]],
[[claude-design-handoff-bundle]].
No comments yet. Be the first to comment!