--- title: "Sessions — Persisting and Resuming Conversation History" aliases: [session-management, continue-resume-fork] tags: [agent-sdk, sessions, python, typescript, conversation-history] sources: [raw/Work with sessions.md] created: 2026-04-17 updated: 2026-04-17 --- # Sessions — Persisting and Resuming Conversation History A **session** is the full conversation history the SDK accumulates during a `query()` run: your prompt, every tool call, every tool result, every response. The SDK writes it to disk automatically under `~/.claude/projects//.jsonl`. Sessions persist the **conversation**, not the filesystem. To snapshot/revert file changes use [[wiki/agent-sdk/file-checkpointing|file-checkpointing]]. --- ## Choosing an Approach | Scenario | What to use | |---|---| | One-shot task, no follow-up | Nothing extra. One `query()` call. | | Multi-turn chat in one process | `ClaudeSDKClient` (Python) or `continue: true` (TypeScript) | | Pick up after a process restart | `continue_conversation=True` / `continue: true` — resumes most recent session, no ID needed | | Resume a specific past session | Capture session ID → pass to `resume` | | Try an alternative without losing original | Fork the session | | Stateless, no disk writes (TypeScript only) | `persistSession: false` | --- ## Automatic Session Management ### Python — `ClaudeSDKClient` `ClaudeSDKClient` tracks the session ID internally. Every `client.query()` call automatically continues the same session. Use it as an async context manager. ```python async with ClaudeSDKClient(options=options) as client: await client.query("Analyze the auth module") async for message in client.receive_response(): print_response(message) # automatically continues same session await client.query("Now refactor it to use JWT") async for message in client.receive_response(): print_response(message) ``` ### TypeScript — `continue: true` The stable V1 `query()` has no session-holding client object. Pass `continue: true` on each subsequent call — SDK finds and resumes the most recent session on disk. ```typescript // First query — creates a new session for await (const message of query({ prompt: "Analyze the auth module", ... })) { ... } // Second query — resumes most recent session for await (const message of query({ prompt: "Now refactor it to use JWT", options: { continue: true, allowedTools: [...] } })) { ... } ``` > V2 preview (`createSession()` / `send` / `stream`) is closer to Python's client feel but is unstable — stick to V1 for production. See [[wiki/agent-sdk/typescript-v2-interface|typescript-v2-interface]]. --- ## Manual Session Options with `query()` ### Capture the Session ID Read `session_id` from the `ResultMessage` — present on every result, success or error. ```python async for message in query(prompt="...", options=ClaudeAgentOptions(...)): if isinstance(message, ResultMessage): session_id = message.session_id ``` In TypeScript the ID is also on the init `SystemMessage` (earlier than `ResultMessage`). ### Resume by ID ```python async for message in query( prompt="Now implement the refactoring you suggested", options=ClaudeAgentOptions( resume=session_id, allowed_tools=["Read", "Edit", "Write", "Glob", "Grep"], ), ): ... ``` **Common resume use cases:** - Follow up on a completed task without re-reading files - Recover from `error_max_turns` or `error_max_budget_usd` with higher limits - Restore a conversation after process restart **Gotcha — mismatched `cwd`:** Sessions are stored under `~/.claude/projects//`. If the resume call runs from a different directory, the SDK looks in the wrong folder and returns a fresh session. The `cwd` must match exactly. ### Fork to Explore Alternatives Fork creates a new session starting with a copy of the original's history. The original stays unchanged. Both sessions get their own IDs and can be resumed independently. ```python # Fork: branch from session_id, try OAuth2 forked_id = None async for message in query( prompt="Instead of JWT, implement OAuth2 for the auth module", options=ClaudeAgentOptions(resume=session_id, fork_session=True), ): if isinstance(message, ResultMessage): forked_id = message.session_id # Original session untouched — continue JWT thread async for message in query( prompt="Continue with the JWT approach", options=ClaudeAgentOptions(resume=session_id), ): ... ``` > Fork branches conversation history only. File changes from a forked agent are real and visible to all sessions in the directory. To branch files too, combine with [[wiki/agent-sdk/file-checkpointing|file-checkpointing]]. --- ## Resume Across Hosts Session files are **local** to the machine that created them. | Option | How | |---|---| | Move the file | Persist `~/.claude/projects//.jsonl`, restore it to the same path on the new host, ensure `cwd` matches | | Skip session resume | Capture the output you need (analysis, decisions, diffs) and pass it into a fresh session's prompt — often more robust | --- ## Session Utility Functions Both SDKs expose helpers for working with sessions on disk: | Purpose | Python | TypeScript | |---|---|---| | List sessions | `list_sessions()` | `listSessions()` | | Read messages | `get_session_messages()` | `getSessionMessages()` | | Get session info | `get_session_info()` | `getSessionInfo()` | | Rename session | `rename_session()` | `renameSession()` | | Tag session | `tag_session()` | `tagSession()` | Use these to build custom session pickers, cleanup logic, or transcript viewers. --- ## Key Takeaways - Sessions = serialized conversation history (prompts + tool calls + results), written as `.jsonl` files - **Continue** = resume most recent session by directory; no ID needed - **Resume** = return to a specific session by ID; required for multi-user or non-latest sessions - **Fork** = copy history into a new session; original untouched; both independently resumable - Mismatched `cwd` is the #1 cause of resume returning a blank session - For cross-host resuming, moving the `.jsonl` file is possible but passing output as a fresh prompt is more robust - `persistSession: false` (TypeScript only) keeps the session in memory only — nothing written to disk --- ## Related - [[wiki/agent-sdk/agent-loop|agent-loop]] — how turns, messages, and context accumulate within a session - [[wiki/agent-sdk/file-checkpointing|file-checkpointing]] — track and revert file changes across sessions - [[wiki/agent-sdk/python-api-reference|python-api-reference]] — `ClaudeAgentOptions` session fields reference - [[wiki/agent-sdk/typescript-api-reference|typescript-api-reference]] — `Options` session fields reference - [[wiki/agent-sdk/typescript-v2-interface|typescript-v2-interface]] — V2 `createSession()` / `resumeSession()` preview - [[wiki/agent-sdk/streaming-input|streaming-input]] — notes on session resuming with streaming input ## Sources - `raw/Work with sessions.md` — official Agent SDK sessions documentation