[FEATURE] Resume sessions in a different working directory: --cwd flag

Resolved 💬 3 comments Opened May 13, 2026 by prateek Closed Jun 22, 2026

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.

  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:

| 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 — /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>

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗