Skip to main content
A ready-to-run example is available here!

How to use Persistence

Save conversation state to disk and restore it later for long-running or multi-session workflows.

Saving State

Create a conversation with a unique ID to enable persistence:

Restoring State

Restore a conversation using the same ID and persistence directory:

What Gets Persisted

The conversation state includes information that allows seamless restoration:
  • Message History: Complete event log including user messages, agent responses, and system events
  • Agent Configuration: LLM settings, tools, MCP servers, and agent parameters
  • Execution State: Current agent status (idle, running, paused, etc.), iteration count, and stuck detection settings
  • Tool Outputs: Results from bash commands, file operations, and other tool executions
  • Statistics: LLM usage metrics like token counts and API calls
  • Workspace Context: Working directory and file system state
  • Activated Skills: Skills that have been enabled during the conversation
  • Secrets: Managed credentials and API keys
  • Agent State: Custom runtime state stored by agents (see Agent State below)
For the complete implementation details, see the ConversationState class in the source code.

Persistence Directory Structure

When you set a persistence_dir, your conversation will be persisted to a directory structure where each conversation has its own subdirectory. By default, the persistence directory is workspace/conversations/ (unless you specify a custom path). Directory structure:
workspace/conversations
<conversation-id-1>
base_state.json
events
event-00000-<event-id>.json
event-00001-<event-id>.json
...
...
Each conversation directory contains:
  • base_state.json: The core conversation state including agent configuration, execution status, statistics, and metadata
  • events/: A subdirectory containing individual event files, each named with a sequential index and event ID (e.g., event-00000-abc123.json)
The collection of event files in the events/ directory represents the same trajectory data you would find in the trajectory.json file from OpenHands V0, but split into individual files for better performance and granular access.

Ready-to-run Example

This example is available on GitHub: examples/01_standalone_sdk/10_persistence.py
examples/01_standalone_sdk/10_persistence.py
You can run the example code as-is.
The model name should follow the LiteLLM convention: provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o). The LLM_API_KEY should be the API key for your chosen provider.
ChatGPT Plus/Pro subscribers: You can use LLM.subscription_login() to authenticate with your ChatGPT account and access Codex models without consuming API credits. See the LLM Subscriptions guide for details.

Reading serialized events

Convert persisted events into LLM-ready messages for reuse or analysis.
examples/01_standalone_sdk/36_event_json_to_openai_messages.py
You can run the example code as-is.
The model name should follow the LiteLLM convention: provider/model_name (e.g., anthropic/claude-sonnet-4-5-20250929, openai/gpt-4o). The LLM_API_KEY should be the API key for your chosen provider.
ChatGPT Plus/Pro subscribers: You can use LLM.subscription_login() to authenticate with your ChatGPT account and access Codex models without consuming API credits. See the LLM Subscriptions guide for details.

How State Persistence Works

The SDK uses an automatic persistence system that saves state changes immediately when they occur. This ensures that conversation state is always recoverable, even if the process crashes unexpectedly.

Auto-Save Mechanism

When you modify any public field on ConversationState, the SDK automatically:
  1. Detects the field change via a custom __setattr__ implementation
  2. Serializes the entire base state to base_state.json
  3. Triggers any registered state change callbacks
This happens transparently—you don’t need to call any save methods manually.

Events vs Base State

The persistence system separates data into two categories: Events are appended incrementally (one file per event), while base state is overwritten on each change. This design optimizes for:
  • Fast event appends: No need to rewrite the entire history
  • Atomic state updates: Base state is always consistent
  • Efficient restoration: Events can be loaded lazily

Next Steps