Skip to content

fix: wait for graceful CLI exit on close to persist session transcript#561

Open
n0isy wants to merge 1 commit intoanthropics:mainfrom
n0isy:fix/graceful-close-for-session-persistence
Open

fix: wait for graceful CLI exit on close to persist session transcript#561
n0isy wants to merge 1 commit intoanthropics:mainfrom
n0isy:fix/graceful-close-for-session-persistence

Conversation

@n0isy
Copy link

@n0isy n0isy commented Feb 10, 2026

Summary

  • close() now waits up to 5 seconds for the CLI process to exit gracefully after closing stdin, instead of immediately sending SIGTERM
  • Falls back to SIGTERM only if the process doesn't exit within the timeout
  • This ensures the CLI's async write queue has time to flush the session transcript to disk

Root Cause

The CLI uses enqueueWrite() + setTimeout() to batch-write session transcript entries to the JSONL file. When close() sends SIGTERM immediately after closing stdin, the write queue hasn't drained yet. The session file ends up containing only a queue-operation entry — no user/assistant messages. When --resume is later used with that session ID, the CLI can't find the conversation history and silently creates a new session instead.

How the Fix Works

The CLI already detects stdin EOF and initiates a clean shutdown, flushing its write queue before exiting (typically under 1 second). This change simply gives it time to do so:

# Before: immediate SIGTERM after closing stdin
self._process.terminate()

# After: wait for graceful exit, SIGTERM only as fallback
try:
    with anyio.fail_after(5):
        await self._process.wait()
except TimeoutError:
    self._process.terminate()

Verification

Tested with a script that:

  1. Creates a session via ClaudeSDKClient, sends a query, disconnects
  2. Resumes the session with resume=session_id, sends a follow-up query

Before fix: Resume fails silently — new session ID returned, error_during_execution, 0 turns.
After fix: Resume works — same session ID, conversation context preserved.

Also verified via direct subprocess test that the CLI exits naturally in ~0.5s after stdin EOF with the transcript fully flushed to disk.

Fixes #555

🤖 Generated with Claude Code

The `close()` method previously sent SIGTERM to the CLI process
immediately after closing stdin. The CLI uses an async write queue
(`enqueueWrite` + `setTimeout`) to batch-write session transcript
entries to disk. Terminating the process before this queue drains
causes the session JSONL to be incomplete (only a `queue-operation`
entry), which makes `--resume` silently create a new session instead
of resuming the existing one.

After closing stdin, the CLI detects EOF and shuts down on its own,
flushing the write queue before exiting (typically under 1 second).
This change waits up to 5 seconds for the process to exit gracefully
after stdin EOF, falling back to SIGTERM only on timeout.

Fixes anthropics#555

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Session resume silently creates new session despite valid session file and correct parameters

1 participant