[FEATURE] Resume sessions in a different working directory: --cwd flag
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet (see Additional Context for related issues — filing this as a focused, scoped variant)
- [x] This is a single feature request (not multiple features)
Problem Statement
claude --resume <uuid>, claude --continue, and claude --resume <uuid> --fork-session are hard-filtered to the current working directory. Lookup is restricted to ~/.claude/projects/<encoded-$PWD>/. Resuming a session from any other directory fails with:
No conversation found with session ID: <uuid>
This blocks a workflow that comes up daily for me: forking an in-progress session into a new git worktree (different absolute path on disk, equivalent project context). It also blocks resuming a session after a worktree has been moved or renamed.
Repro:
$ cd /tmp/a && claude # start a session, say something, exit.
# claude prints "Resume this session with: claude --resume <uuid>"
$ cd /tmp/b && claude --resume <uuid>
No conversation found with session ID: <uuid>
The same lookup filter applies to --continue and --fork-session.
A minimal end-to-end reproducer (script + captured output from a real run) is included at the end of this issue.
Proposed Solution
Add --cwd <dir> to claude --resume, claude --continue, and claude --fork-session. Mirrors Codex's codex resume <uuid> -C <dir>, which is the smallest API addition that solves this.
claude --resume <uuid> --cwd /path/to/new/worktree
claude --continue --cwd /path/to/new/worktree
claude --resume <uuid> --fork-session --cwd /path/to/new/worktree
Behavior: lookup falls back to scanning project directories when the session id is not found under <encoded-$PWD>/. Once located, the session resumes against --cwd <dir> for all subsequent file operations and CLAUDE.md discovery.
Alternative Solutions
Agent SDK method. client.migrateSession({ sessionId, fromDir, toDir }) in @anthropic-ai/claude-agent-sdk. Pairs with the existing listSessions({ dir }) and getSessionMessages({ sessionId, dir }) (added in v0.1.51). Architecturally cleaner; would let third-party tooling migrate sessions without touching internal storage layouts.
Current workaround (in production use). Copy the session JSONL from ~/.claude/projects/<encoded-old-cwd>/<uuid>.jsonl to ~/.claude/projects/<encoded-new-cwd>/<uuid>.jsonl, then claude --resume <uuid> --fork-session from the new cwd. End-to-end validated: the resumed agent rebinds CLAUDE.md, file tools, and cwd-aware behavior to the new directory cleanly. Drawbacks: requires manually computing the encoded path (s,/,-,g, with symlink resolution), filesystem operations against an internal storage layout, per-session file copy + sidecar handling. See the reproducer below for a minimal demonstration.
Priority
High - Significant impact on productivity
Feature Category
CLI commands and flags
Use Case Example
Forking an active Claude Code session into a new git worktree to explore an alternative approach without losing the original thread.
- I'm in a Claude Code session in worktree
~/projects/foo/main, debugging an authentication issue. - I want to try a riskier fix in parallel without abandoning the current investigation.
- I create a new git worktree at
~/projects/foo/auth-experiment(same repo, same SHA, independent branch). - I want to fork the conversation into the new worktree: same history, same context, but the agent should now work in
~/projects/foo/auth-experimentgoing forward. The original session keeps running in~/projects/foo/main. - With
--cwd:claude --resume <uuid> --fork-session --cwd ~/projects/foo/auth-experiment— single command, done. - Without it: copy
~/.claude/projects/-Users-me-projects-foo-main/<uuid>.jsonlto~/.claude/projects/-Users-me-projects-foo-auth-experiment/<uuid>.jsonl, thencd ~/projects/foo/auth-experiment && claude --resume <uuid> --fork-session— three steps, requires knowing the path-encoding scheme, and breaks if the encoding changes.
This pattern repeats for: PR review in a fresh worktree, cross-worktree experiments, post-mv resume.
Additional Context
Cross-tool comparison. Codex, GitHub Copilot CLI, Cursor agent CLI, Goose, and Amp all support cross-directory resume natively:
| Tool | Cross-dir resume | How |
|---|---|---|
| Codex (OpenAI) | yes | -C/--cd <dir> + --all |
| GitHub Copilot CLI | yes | --resume <id\|name> not cwd-filtered |
| Cursor agent CLI | yes | chat-id keyed |
| Goose (Block) | yes | SQLite with working_dir column |
| Amp (Sourcegraph) | yes | Cloud-synced, server-side ID-keyed |
| Claude Code | no | Encoded-cwd dir lookup, no override |
Related open issues (filing this as a focused, scoped variant — happy to consolidate with any of these if maintainers prefer):
- #36937 —
/cdcommand and--cwdresume flag - #28745 — Allow resuming conversations from different directories
- #41021 — Global
/resumeacross projects - #5768 — Resume only works from launch directory (open since v1.0.80)
- #49954 — "Fork into worktree" affordance in Desktop
<details>
<summary><b>Reproducer (<code>repro.sh</code>)</b> — runnable script + sample output from a real run on Claude Code v2.1.140</summary>
#!/usr/bin/env bash
# Reproducer: Claude Code --resume is hard-filtered by current working directory.
# Usage: ./repro.sh
#
# What this proves:
# 1. A session created in dir A cannot be resumed from dir B (lookup fails).
# 2. After copying the session JSONL into dir B's encoded project dir,
# resume succeeds.
#
# Cleans up its own scratch state on exit.
set -euo pipefail
if ! command -v claude >/dev/null; then
echo "ERROR: 'claude' not on PATH. Install Claude Code first." >&2
exit 1
fi
if ! command -v uuidgen >/dev/null; then
echo "ERROR: 'uuidgen' not on PATH (macOS/Linux util)." >&2
exit 1
fi
SCRATCH=/tmp/claude-cwd-repro
DIR_A="$SCRATCH/a"
DIR_B="$SCRATCH/b"
SESSION_ID="$(uuidgen | tr 'A-Z' 'a-z')"
PROJECTS=~/.claude/projects
encode_path() {
# claude encodes cwd by replacing every / with - and resolving symlinks.
# macOS resolves /tmp -> /private/tmp; do the same.
local p
p=$(cd "$1" && pwd -P)
echo "${p//\//-}"
}
cleanup() {
rm -rf "$SCRATCH"
rm -rf "$PROJECTS/$(encode_path "$DIR_A" 2>/dev/null)" 2>/dev/null || true
rm -rf "$PROJECTS/$(encode_path "$DIR_B" 2>/dev/null)" 2>/dev/null || true
}
trap cleanup EXIT
mkdir -p "$DIR_A" "$DIR_B"
ENC_A=$(encode_path "$DIR_A")
ENC_B=$(encode_path "$DIR_B")
JSONL_A="$PROJECTS/$ENC_A/$SESSION_ID.jsonl"
JSONL_B="$PROJECTS/$ENC_B/$SESSION_ID.jsonl"
echo "=== Setup ==="
echo "claude version: $(claude --version 2>&1 | head -1)"
echo "session id: $SESSION_ID"
echo "dir A: $DIR_A (encoded: $ENC_A)"
echo "dir B: $DIR_B (encoded: $ENC_B)"
echo
echo "=== Step 1: create a session in dir A ==="
( cd "$DIR_A" && claude -p --session-id "$SESSION_ID" "hi" )
echo
echo "session jsonl present at A: $([[ -f "$JSONL_A" ]] && echo yes || echo NO)"
echo
echo "=== Step 2: resume from dir B without copying the jsonl (expect failure) ==="
set +e
( cd "$DIR_B" && claude -p --resume "$SESSION_ID" "still there?" 2>&1 )
RC=$?
set -e
echo
echo "exit code: $RC (nonzero / 'No conversation found' demonstrates the bug)"
echo
echo "=== Step 3: copy the jsonl into dir B's encoded project dir ==="
mkdir -p "$PROJECTS/$ENC_B"
cp "$JSONL_A" "$JSONL_B"
echo "copied $JSONL_A -> $JSONL_B"
echo
echo "=== Step 4: resume from dir B (expect success) ==="
( cd "$DIR_B" && claude -p --resume "$SESSION_ID" "still there?" )
echo
echo "=== Done. Cleaning up. ==="
Sample output from a real run (Claude Code v2.1.140 on macOS, 2026-05-13):
=== Setup ===
claude version: 2.1.140 (Claude Code)
session id: 2a11f963-e9ef-483c-86f1-3e896f7ff08f
dir A: /tmp/claude-cwd-repro/a (encoded: -private-tmp-claude-cwd-repro-a)
dir B: /tmp/claude-cwd-repro/b (encoded: -private-tmp-claude-cwd-repro-b)
=== Step 1: create a session in dir A ===
Hi Prateek — what are we working on?
session jsonl present at A: yes
=== Step 2: resume from dir B without copying the jsonl (expect failure) ===
No conversation found with session ID: 2a11f963-e9ef-483c-86f1-3e896f7ff08f
exit code: 1 (nonzero / 'No conversation found' demonstrates the bug)
=== Step 3: copy the jsonl into dir B's encoded project dir ===
copied /Users/prungta/.claude/projects/-private-tmp-claude-cwd-repro-a/2a11f963-e9ef-483c-86f1-3e896f7ff08f.jsonl -> /Users/prungta/.claude/projects/-private-tmp-claude-cwd-repro-b/2a11f963-e9ef-483c-86f1-3e896f7ff08f.jsonl
=== Step 4: resume from dir B (expect success) ===
Yep, still here. What do you need?
=== Done. Cleaning up. ===
</details>
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗