[BUG] ccd-cli --resume does not replay historical messages after bridge restart — sessions appear empty
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
After restarting the remote bridge (~/.claude/remote/server --bridge), Claude Desktop's sidebar continues to show existing session titles, but selecting any session displays "No messages yet". The .jsonl transcript files on disk are intact and valid, but the freshly spawned ccd-cli --resume <session-id> process never replays the historical messages to stdout, so the client renders an empty conversation.
ENVIRONMENT
- OS: Linux 5.15 (Ubuntu) — server side
- Client: Claude Desktop (entrypoint reported as
claude-desktopin session metadata), connected to the server via SSH (sshdis the parent of the bridge process) - Binary:
~/.claude/remote/ccd-cli/2.1.138 - Also reproduced with:
2.1.121and2.1.128(same behavior — not a regression) - Bridge / server:
~/.claude/remote/server(--serveand--bridgemodes)
What Should Happen?
When clicking an existing session, the freshly spawned ccd-cli --resume <id> --replay-user-messages should stream the historical type:"user" / type:"assistant" records from the on-disk .jsonl transcript to stdout, and the client should render the full conversation.
Either:
- The binary pushes the buffered transcript automatically on stdout after
control_request:initialize, OR - The client issues an explicit
control_request:replay_historyand the binary responds with the same stream.
Currently only the process.reattach path (to a long-lived process) renders the history; the cold process.spawn path leaves the UI empty despite the transcript being intact on disk.
Error Messages/Logs
## Evidence
### 1. Transcripts on disk are valid
Parsed the largest transcript:
Size: ~32 MB
Lines: 9,963 valid JSONL records (0 parse errors)
Types: assistant=4931, user=3139, last-prompt=734, attachment=406,
queue-operation=364, ai-title=260, system=129
All transcripts in the project's `.claude/projects/<cwd-slug>/` directory parse cleanly (totaling ~27,000 records across multiple sessions).
### 2. The `ccd-cli` binary does not replay
Direct test, bypassing the bridge entirely:
```bash
{ echo '{"request_id":"t","type":"control_request","request":{"subtype":"initialize","hooks":{}}}'; sleep 8; } \
| timeout 10 ~/.claude/remote/ccd-cli/2.1.138 \
--output-format stream-json --input-format stream-json --verbose \
--resume <SESSION_UUID> \
--replay-user-messages --include-partial-messages \
> /tmp/stdout.log 2> /tmp/stderr.log
Result:
STDOUT: ~7 KB, 1 line
→ 1 × control_response/success
→ 0 × user / assistant / replay events
STDERR: 0 bytes (no errors reported)
Same result on 2.1.121 and 2.1.128.
The binary contains the symbols (replayBufferedMessages, replayUserMessages, --replay-user-messages) — the feature is present in the source but produces no output during --resume.
3. Bridge log shows the client never receives history
Methods observed in remote-server.log after a fresh session selection:
process.spawn → spawns new ccd-cli with --resume
process.stdin (initialize) → sends control_request
process.stdin (mcp_set_servers)
process.stdin (get_context_usage)
No further inbound traffic from the new ccd-cli that contains transcript messages.
Process file descriptor inspection (/proc/<pid>/fd/) confirms the running ccd-cli has no .jsonl open during steady-state — it either never opens it, or opens it once at startup and closes it without emitting the parsed records.
Workarounds
- None for the UI. After this state, sessions cannot be re-rendered without the messages being replayed.
- The on-disk
.jsonlfiles remain authoritative and can be parsed manually for content recovery. - A full kill of
--serve+ Desktop restart was not attempted during debugging (would have destroyed the active session used to investigate), but is likely the only way to recover.
### Steps to Reproduce
1. Have Claude Desktop connected to a remote backend with several active sessions (each backed by a `ccd-cli --resume <id>` process held in memory by the `--serve` daemon).
2. Restart the bridge:
```bash
kill $(pgrep -f "remote/server --bridge")
```
The client auto-reconnects and the bridge respawns.
3. The previously held `ccd-cli --resume` processes become orphaned (their RPC `process.reattach` UUIDs are no longer mapped in the new bridge). Killing them or letting the client spawn new ones is equivalent for this bug.
4. Click an existing session in the sidebar.
5. The client issues `process.spawn` → `control_request:initialize` → `mcp_set_servers` → `get_context_usage` to the new `ccd-cli`.
6. **Expected**: historical messages from the session's `.jsonl` are streamed back and rendered.
7. **Actual**: only the `control_response:success` is returned; no `type:"user"` / `type:"assistant"` events from the transcript ever appear. UI shows "No messages yet."
### Claude Model
claude-opus-4-7
### Is this a regression?
I don't know
### Last Working Version
_No response_
### Claude Code Version
2.1.138 (Claude Code)
### Platform
Anthropic API
### Operating System
Ubuntu/Debian Linux
### Terminal/Shell
BASH
### Additional Information
## Hypothesis
`--replay-user-messages` appears to assume the historical replay happens within a process the user is interactively typing into, not on a fresh `--resume` cold-start triggered by `process.spawn`. The client expects the binary to push the transcript through stdout after `initialize`, but the binary does not — leaving the client and the binary in a deadlock where neither side knows to drive the replay.
The pre-bridge-restart state worked because the original `ccd-cli` processes had been alive since their first interactive launch, with messages already buffered in-process; the client reattached via `process.reattach` and rendered from the in-memory buffer rather than via a fresh replay. Restarting the bridge dropped the `process.reattach` UUID map, forcing a cold `process.spawn` path that exposes the missing replay.
## Severity
- **Data loss risk**: none — transcripts are on disk
- **Recovery cost**: high — every restart of `--bridge` (intentional or accidental) makes all sessions appear empty in the UI until the binary is fixed
- **User impact**: medium — sessions are present but unusable through the UI
## Suggested fix
Either:
1. Make `ccd-cli --resume X --replay-user-messages` emit the buffered `user` / `assistant` records on stdout immediately after the first `initialize` response, OR
2. Add an explicit RPC method (e.g. `control_request:replay_history`) the client can issue to trigger replay on demand, and have the client call it after spawning a `--resume`d process.
---This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗