IN THIS BREAKDOWN · 10 SECTIONS
You can read 18% of this breakdown.
The paper in one minute
OpenHands is an open-source platform for software agents. Its first architecture, which the authors call V0, assumed every tool call ran inside a sandboxed Docker container, separate from the process running the agent. That meant every conversation spanned two processes whose state could diverge. When the sandbox crashed and the agent kept going, or the reverse, the session was corrupted. Local execution, which the Model Context Protocol assumes, had to be bolted on with duplicate tool and MCP code. Configuration had grown to more than 140 fields across 15 classes and 2,800 lines, spread over separate hierarchies for the CLI, web UI, GitHub App and hosted service.
V1, the Software Agent SDK, rests on four rules. Isolation is optional: the agent runs in-process by default and moves into a container when you need one. Everything is immutable except one object: agents, tools and model settings are frozen Pydantic models, and a single ConversationState holds all mutable data. The agent core is a library that applications import rather than a codebase they share. Components are typed and replaceable, so a new tool or agent does not touch the core.
The state is event-sourced. Every message, tool call, observation, pause and condensation is an immutable event appended to a log, with each event persisted as its own JSON file and metadata in one base_state.json. Resuming a conversation means loading the metadata and replaying the events. The same Conversation(...) call runs locally against a folder, or, given a Docker or hosted workspace, serializes the agent to an agent server that runs it in a container and streams events back over WebSocket.
The paper backs this with production data. V0 and V1 served users side by side for 15 days, and failures attributable to the system rather than to model providers fell from 78.0 to 30.0 per 1,000 conversations.
Research notes: the problem, approach and results
system-attributable errors per 1,000 conversations, V0 against V1, in a 15-day parallel production rollout
median time to persist one event, on 39,870 events from 433 SWE-Bench Verified conversations
V0 failures from one cause alone: authentication errors between two pods, removed by co-locating them
OpenHands V0 grew from a research prototype into a product with a CLI, a web app, a GitHub integration and a hosted service. Every tool call ran in a separate sandbox process, configuration lived in four parallel hierarchies with 140+ fields, and benchmark code shared a repository with production. Sessions corrupted when one of the two processes crashed, and two runs with the same settings could behave differently.
Make every component except one immutable. Agents, tools and model settings are validated, serializable configuration; a single ConversationState holds all mutable data as metadata plus an append-only event log, persisted one event per file. Run the agent in-process by default and move it into a container by swapping the workspace object, with a REST and WebSocket agent server doing the remote half.
In a 15-day parallel rollout, system-attributable errors fell from 78.0 to 30.0 per 1,000 conversations. Persisting an event took a median 0.20 ms. With Claude Sonnet 4 on SWE-Bench Verified, V0 and V1 both scored 68.0%, so the redesign did not cost capability.
Why it matters to an FDE
If you have built an agent demo, you have built the V0 problems in small. A loop calls a model, a tool runs somewhere, and the only record of what happened is a list in memory. That works until the process dies halfway through a two-hour job, a customer asks why the agent deleted a file, or a second entry point (a Slack bot, a scheduled job) needs the same agent with slightly different settings.
The paper is a worked answer to three questions you will face when a pilot becomes a service.
Where does the truth live? One append-only log per conversation, written as it happens. It is your resume point, your audit trail and your debugging tool, and the paper measures its cost as negligible next to model calls.
What may change at runtime? Nothing except that log and a few status fields. Freezing configuration at construction is what made two runs with the same settings behave the same.
Where does the code run? Locally by default, in a container when a customer's security team or a multi-tenant service requires it, with the same agent code in both.
Read the production numbers carefully. Most of the 61% came from removing network calls between two Kubernetes pods. The authentication failures between those pods alone were 43.0 per 1,000 conversations. The lesson for your own deployment is to count the processes and network hops each agent step crosses. Each one is a failure mode that a better model cannot fix.
Understand the mechanism. Try it on a real problem.
Unlock this breakdown and 149 more papers.
Premium opens every paper in full, plus every answer, concept, course and guide on the site. One payment for six months of access.
6 months · One payment · No auto-renewal
- ◇1 architecture diagram
- </>1 runnable code experiment
- ▦3 results tables
- ?5 interview questions with answers
- 03Key takeaways
The design rules, the measured costs, what the numbers do and do not show, and three misreadings
Free account - 04How it works
The event hierarchy, one agent step, the tool contract, condensation, security and the remote path
Premium - 05The numbers that matter
The rollout, the persistence costs, the matched-model comparison and the benchmark table
Premium - 06Try it yourself
Check the paper's arithmetic, then crash an event-sourced agent 2,000 times and resume it
Premium - 07Where it breaks
What the rollout measures, the attribution gaps, the comparisons and the open security questions
Premium - 08Using it on a deployment
Adopting the pattern or the SDK: prerequisites, a worked example and what to measure
Premium - 09Interview angles
Five questions this paper prepares you for, with answer hints
Premium - 10Read next
Where to go from here on this site
Premium
