`claude --resume <id>` fails from a different cwd than the session origin; agents daemon respawns the failed worker indefinitely
Summary
When a conversation is resumed from a working directory that differs from the one the session was originally created in, claude --resume <session-id> reports "No conversation found with session ID: …" even though the transcript file still exists on disk under a different project folder.
When the resume is driven by the "claude agents" / FleetView background daemon, the worker exits 1 on every attempt and the daemon respawns it indefinitely, producing an unbreakable loop that makes the conversation impossible to open from the UI:
[worker crashed (exit 1) — respawning…]
No conversation found with session ID: <resume-session-id>
[worker crashed (exit 1) — respawning…]
Environment
- Claude Code CLI: daemon running
2.1.186; affected agent job created under2.1.185 - Platform: macOS (Darwin), zsh
- Feature: the "claude agents" / FleetView window (local
claude daemon runsupervising per-agent workers)
Three distinct issues (ranked)
1. Infinite respawn on a deterministic startup failure (highest severity).
The worker fails immediately and identically on every attempt — the cause (missing transcript in the resolved folder) can never become true at runtime. The daemon keeps respawning instead of detecting an unrecoverable startup error and surfacing it once. A permanent exit-1-on-startup should stop and report, not loop forever.
2. --resume <id> resolves the id only against the current directory's project folder, with no fallback.
Session-id → transcript lookup appears scoped to ~/.claude/projects/<cwd-with-every-slash-as-dash>/<id>.jsonl. If resumed from a different directory, the lookup misses and errors out, even though <id>.jsonl exists under a different project folder on disk. A fallback (search other project folders for the id, or at least error with the actual file location) would let this self-heal.
3. The daemon resumed by bare session-id when it already had the absolute transcript path.
The agent's persisted job record (~/.claude/jobs/<short>/state.json) stores the full path to the transcript (a linkScanPath-style field), and other agents in the same roster resume by absolute path (--resume /abs/path/to/<id>.jsonl). This worker instead used the bare id resolved against cwd. Resuming by the path it already knows would avoid the entire failure class.
Minor / latent: project-folder name mangling replaces every / with -, so proj/results and proj-results collapse to the same folder name. In our case this only produced a harmless orphan side-folder, not the failure — noted for completeness.
Minimal repro (issue #2, the core)
# 1. Create a session in a subdirectory
mkdir -p ~/work/proj/sub && cd ~/work/proj
claude # send one message so a transcript is written, then exit
# note the session id <SID>; transcript is written at:
# ~/.claude/projects/-Users-<user>-work-proj/<SID>.jsonl
# 2. Resume from a DIFFERENT directory (the parent)
cd ~/work
claude --resume <SID>
Expected: resumes <SID> (the transcript exists on disk), or fails with a message pointing to where the transcript actually lives.
Actual: No conversation found with session ID: <SID>.
How it manifests via the agents window
An agent whose recorded cwd does not match the project folder of the conversation it resumes (resumeSessionId) will have its worker exit 1 on every spawn → the daemon respawns forever → the conversation can no longer be opened from the UI. The agent's state lives in ~/.claude/jobs/<short>/state.json (relevant fields: cwd, originCwd, resumeSessionId, and an absolute-path linkScanPath that already identifies the correct transcript location).
Suggested fixes
- Cap/backoff respawns and surface a terminal error when a worker exits non-zero before reaching a ready state (issue #1).
- Make
--resume <id>fall back to a cross-project lookup, or at minimum emit the resolved/expected path on failure (issue #2). - In the daemon, prefer resuming by the absolute transcript path it already records over the bare id (issue #3).
Notes
Behavior and file locations were observed externally (CLI output + on-disk ~/.claude layout), not from source — so repro and paths are reliable, but internal field names are descriptive rather than verbatim. Paths and identifiers above are genericized placeholders.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗