claude-code - 💡(How to fix) Fix [FEATURE] Resume sessions in a different working directory: --cwd flag [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#58591Fetched 2026-05-14 03:44:20
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Author
Participants
Timeline (top)
labeled ×2cross-referenced ×1referenced ×1

Error Message

#!/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. ==="

Fix Action

Fix / Workaround

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.

Code Example

No conversation found with session ID: <uuid>

---

$ 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>

---

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

---

#!/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. ==="

---

=== 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. ===
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • 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)
  • 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.

  1. I'm in a Claude Code session in worktree ~/projects/foo/main, debugging an authentication issue.
  2. I want to try a riskier fix in parallel without abandoning the current investigation.
  3. I create a new git worktree at ~/projects/foo/auth-experiment (same repo, same SHA, independent branch).
  4. I want to fork the conversation into the new worktree: same history, same context, but the agent should now work in ~/projects/foo/auth-experiment going forward. The original session keeps running in ~/projects/foo/main.
  5. With --cwd: claude --resume <uuid> --fork-session --cwd ~/projects/foo/auth-experiment — single command, done.
  6. Without it: copy ~/.claude/projects/-Users-me-projects-foo-main/<uuid>.jsonl to ~/.claude/projects/-Users-me-projects-foo-auth-experiment/<uuid>.jsonl, then cd ~/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:

ToolCross-dir resumeHow
Codex (OpenAI)yes-C/--cd <dir> + --all
GitHub Copilot CLIyes--resume <id|name> not cwd-filtered
Cursor agent CLIyeschat-id keyed
Goose (Block)yesSQLite with working_dir column
Amp (Sourcegraph)yesCloud-synced, server-side ID-keyed
Claude CodenoEncoded-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 — /cd command and --cwd resume flag
  • #28745 — Allow resuming conversations from different directories
  • #41021 — Global /resume across 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>

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING