Chapter 9: Sessions — The Durable Work Unit
By the end of this chapter, you will understand what a session is, how it differs from a chat conversation, how to create and manage sessions, and how to attach files and memory stores at session creation.
The Big Idea
A conversation ends when the window closes. A session is different.
A session is a persistent work unit — it maintains complete conversation history, file system state, and event logs across multiple interactions. You can come back to a session hours later and pick up exactly where you left off. The session remembers every message, every tool call, every result.
This is the architectural foundation for the kind of work that takes time. A coding agent that spends 45 minutes refactoring a codebase can't rely on a conversation that expires. A research agent that runs through 200 web pages needs durable state to track what it has and hasn't read. Sessions provide that durability.
The sessions documentation describes a session as "a running agent instance within an environment. Each session references an agent and an environment (both created separately), and maintains conversation history across multiple interactions."
The key phrase: "multiple interactions." A session isn't a single prompt-and-response. It's the container for an ongoing working relationship with your agent.
The Analogy
Think of a session like a shared document workspace, not a phone call.
A phone call is stateless. Once it ends, there's no persistent record unless you made notes. If you call back, you start from scratch unless you remember the context yourself.
A shared document workspace is different. Every edit is tracked. Every comment is timestamped. You can leave and come back a week later and see exactly what happened, in what order, and who did what. You can pick up from the last edit, not from the beginning.
Sessions work like the shared workspace. Every event — every message you sent, every tool Claude used, every result it got back — is logged in order. When you reconnect to a session, the full history is available. The agent picks up from the last event in the log, not from a blank slate.
How It Actually Works
Creating a Session
A session requires two things: an agent ID and an environment_id. Both must be created beforehand.
session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
)
(Sessions)
The returned session object includes:
id— e.g.,"sesn_01..."— your reference for all subsequent operationsstatus— starts atidle
Creating a session provisions the environment and agent but does not start any work. To delegate a task, you send events.
Session Statuses
Sessions operate as a state machine with four statuses:
| Status | Description |
|---|---|
idle |
Agent is waiting for input. Sessions start in idle. |
running |
Agent is actively executing. |
rescheduling |
Transient error occurred; retrying automatically. |
terminated |
Session ended due to an unrecoverable error. |
(Sessions)
The most important operational distinction: when a session is idle, it's either waiting for your first task, finished with a task, or paused waiting for tool confirmation. The stop_reason field on the accompanying session.status_idle event tells you which one.
Pinning Agent Versions
By default, creating a session uses the latest agent version. To run a specific version:
pinned_session = client.beta.sessions.create(
agent={"type": "agent", "id": agent.id, "version": 1},
environment_id=environment.id,
)
"This lets you control exactly which version runs and stage rollouts of new versions independently." (Sessions)
Use version pinning for production deployments where you're rolling out a new system prompt. Test the new version on a small percentage of sessions before making it the default.
Attaching Resources: Files, Memory Stores, Repositories
The most powerful aspect of session creation is the resources array — it lets you pre-load the session with files, memory stores, and repositories before the agent starts any work.
Attaching a file:
session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
resources=[
{
"type": "file",
"file_id": file.id,
"mount_path": "/workspace/data.csv",
},
],
)
Attaching a memory store:
session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
resources=[
{
"type": "memory_store",
"memory_store_id": store.id,
"access": "read_write",
"prompt": "User preferences and project context.",
},
],
)
Attaching a GitHub repository:
session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
resources=[
{
"type": "github_repository",
"url": "https://github.com/org/repo",
"mount_path": "/workspace/repo",
"authorization_token": "ghp_your_github_token",
},
],
)
(Sessions)
All three resource types can be combined in a single resources array. A session can have up to 100 files, 8 memory stores, and multiple repositories attached.
MCP Authentication at Session Creation
If your agent uses MCP tools that require authentication, pass vault_ids at session creation:
vault_session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
vault_ids=[vault.id],
)
"If your agent uses MCP tools that require authentication, pass vault_ids at session creation to reference a vault containing stored OAuth credentials. Anthropic manages token refresh on your behalf." (Sessions)
Session Operations
# Retrieve a session
retrieved = client.beta.sessions.retrieve(session.id)
print(f"Status: {retrieved.status}")
# List all sessions
for session in client.beta.sessions.list():
print(f"{session.id}: {session.status}")
# Archive a session (prevents new events, preserves history)
client.beta.sessions.archive(session.id)
# Delete a session (permanent; cannot delete a running session)
client.beta.sessions.delete(session.id)
(Sessions)
Important notes on deletion: "Delete a session to permanently remove its record, events, and associated container. A running session cannot be deleted; send an interrupt event if you need to delete it immediately." Also: "Files, memory stores, environments, and agents are independent resources and are not affected by session deletion."
Tracking Token Usage
The session object includes cumulative token statistics. Fetch the session after it goes idle to read the latest totals:
{
"id": "sesn_01...",
"status": "idle",
"usage": {
"input_tokens": 5000,
"output_tokens": 3200,
"cache_creation_input_tokens": 2000,
"cache_read_input_tokens": 20000
}
}
"input_tokens reports uncached input tokens and output_tokens reports total output tokens across all model calls in the session. Cache entries use a 5-minute TTL." (Session event stream)
This is your cost tracking tool. Compare input_tokens to cache_read_input_tokens to see how much caching is saving you. High cache_read_input_tokens relative to input_tokens means your prompt structure is cache-friendly.
Sessions vs. Chat Conversations — The Key Differences
| Chat Conversation | Session |
|---|---|
| Stateless (history in client only) | Stateful (history stored server-side) |
| Ends when the window closes | Persists until archived or deleted |
| No tools available | Full tool access |
| Single context window | Supports context compaction for long tasks |
| Synchronous request-response | Asynchronous event stream |
| No resource attachments | Files, memory stores, repositories |
Try It Yourself
Create a session with a file attachment. First, upload a sample file:
from pathlib import Path import anthropic client = anthropic.Anthropic() file = client.beta.files.upload(file=Path("sample_data.csv")) print(f"File ID: {file.id}")Create a session with the file mounted:
session = client.beta.sessions.create( agent=agent.id, environment_id=environment.id, resources=[ { "type": "file", "file_id": file.id, "mount_path": "/workspace/data.csv", }, ], ) print(f"Session ID: {session.id}, Status: {session.status}")Send a task asking the agent to analyze the file. Use the streaming pattern from Chapter 5. Send: "Read the data.csv file at /workspace/data.csv and give me a summary of what's in it."
After the session finishes, check usage:
retrieved = client.beta.sessions.retrieve(session.id) print(retrieved.usage)Note the token counts. How does the input token count compare to what you'd expect?
Send a follow-up message in the same session. Don't create a new session — send another
user.messageevent to the existing session. Confirm the agent remembers the file analysis from the previous turn.Archive the session when done:
client.beta.sessions.archive(session.id)This prevents new events but preserves the history for auditing.
Common Pitfalls
Creating a new session for every follow-up message. Sessions persist history. If you want the agent to remember what it did in a previous turn, use the same session — send a new
user.messageto the existing session ID. Creating a new session every time is like starting a fresh chat with no memory of what was discussed.Deleting a running session. You can't delete a session in
runningstatus. Send an interrupt event first, wait for the status to change toidleorterminated, then delete.Assuming files survive between sessions. Each session gets its own isolated container instance. Files written during Session A are not available in Session B unless you explicitly save them to outputs and re-mount them. For cross-session persistence, use memory stores or the Files API.
Not reading the
usagefield. Token costs accumulate per session and theusagefield gives you the breakdown. Ignoring it means you won't notice when sessions are unexpectedly token-heavy.Forgetting that session creation doesn't start work. After
client.beta.sessions.create(), the agent is waiting. Nothing happens until you send events. This surprises developers who expect creation to immediately trigger action.
Toolkit
Session Lifecycle Cheat Sheet — Visual lifecycle diagram plus all four status descriptions and the operations available in each status. Includes the archiving vs. deletion decision tree.
Resource Attachment Quick Reference — Code snippets for attaching each resource type (file, memory store, GitHub repository) with annotation on required vs. optional fields.
Chapter Recap
- A session is a durable work unit that maintains the complete event log, file system state, and conversation history across multiple interactions. It's not a chat conversation — it persists until you archive or delete it.
- Creating a session provisions the infrastructure but doesn't start work. Work begins when you send events. Sessions move through four statuses:
idle,running,rescheduling,terminated. - Attach resources at session creation — files, memory stores, and GitHub repositories all go in the
resourcesarray. Track token usage viasession.usageafter each idle period.