# Run ClaudeAgent and CodexAgent in a sandbox that survives losing the host

> Agno's `ClaudeAgent` and `CodexAgent` take a `sandbox=` provider, such as `DockerSandbox`, and run the whole Claude Code or Codex process in an isolated computer that belongs to one session. Every turn starts from a checkpoint committed in the agent's Postgres.

- Published: 2026-10-16
- Author: Yash Pratap Solanky
- Categories: Changelog
- Canonical: https://www.agno.com/blog/run-claudeagent-and-codexagent-in-a-sandbox-that-survives-losing-the-host
- Markdown: https://www.agno.com/blog/run-claudeagent-and-codexagent-in-a-sandbox-that-survives-losing-the-host.md

Agno's `ClaudeAgent(sandbox=...)` and `CodexAgent(sandbox=...)` build their own coordinator from the agent's `PostgresDb` on first use, so a provider and a database are all the setup a sandboxed coding agent needs.

```python
from agno.agents.claude import ClaudeAgent
from agno.db.postgres import PostgresDb
from agno.sandbox.docker import DockerSandbox

agent = ClaudeAgent(
    id="coder",
    model="claude-sonnet-4-6",
    permission_mode="bypassPermissions",
    db=PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai"),
    sandbox=DockerSandbox("agno-sandbox:local", network="isolated"),
)

agent.run("Write hello.py that prints hello and run it.", session_id="sandbox-1")
agent.run("What file did you create in this session?", session_id="sandbox-1")
```

The sandbox is a computer that belongs to one session. Claude Code or Codex runs there as a whole process, with the workspace and its own conversation files next to it, and after every turn Agno saves both as a checkpoint. Docker and Amazon Bedrock AgentCore ship as providers in this release. A lost container, host or replica costs nothing past the last completed turn, because the next turn restores from that checkpoint wherever it runs.

## One turn, start to finish

Each turn claims the session through a lease row in `<session_table>_sandbox_bindings`, a table Agno creates in the agent's Postgres on first use. It starts a computer restored from the last committed checkpoint, runs the turn, captures and verifies a new checkpoint, and then publishes the run row and the recovery point in one transaction. A cancelled or failed turn publishes nothing, so the previous checkpoint stays the recovery point. When the previous turn left its computer warm, the next turn resumes it and skips the restore.

![The per-turn cycle of a sandboxed ClaudeAgent or CodexAgent. Lease claims the session through a lease row in the agent's Postgres. Restore starts a fresh computer from the last committed checkpoint, with the workspace and native conversation files. Run checks the committed native id first, then runs Claude Code or Codex inside. Capture and verify takes a new checkpoint and checks it in the checkpoint store. Publish writes the run row and the recovery point in one transaction. The next turn starts from that recovery point on any host or replica. A cancelled, failed or native_state_missing turn publishes nothing and the previous checkpoint stays the recovery point.](https://www.agno.com/images/v3-1-4-sandbox-turn-cycle.png)

## Refusing state it cannot verify

Every turn passes the runtime the native conversation id committed with the last checkpoint, the Claude session id or the Codex thread id. If the restored computer holds a different conversation or none, the runtime fails with `native_state_missing` before the model runs, and the coordinator treats that as a restore it can retry. A completed turn that reports no native conversation, or whose transcript could not be saved, publishes nothing either.

We drove the release's sandbox runtime directly, with a stand-in agent in place of Claude Code, once with the conversation restored and once with it gone.

```text
# real output, stand-in agent in place of the model
# restore holds the conversation: model calls=['model']
{"type": "execution_finished"}
# restore lost the conversation: model calls=[]
{"type": "execution_error", "reason": "native_state_missing", "error": "Sandbox native state does not match the session: expected the native conversation native-1, found none"}
```

## Settings that cross into the sandbox

Typed harness settings such as `model`, `permission_mode` or `allowed_tools` travel to the runtime as JSON. Settings that only mean something on the host fail when you build the agent, each one by name, and so does a database other than Postgres.

```text
# real output
ClaudeAgent(..., sandbox=box, cwd="/srv/repo", retries=2)
ValueError: Not supported with sandbox=: cwd, retries. The sandbox owns the workspace, process and local files; configure retries on QueueConfig.

CodexAgent(..., sandbox=box, env={"FOO": "1"})
ValueError: Not supported with sandbox=: env. The sandbox owns the workspace, process and local files; configure retries on QueueConfig.

ClaudeAgent(..., db=SqliteDb(...), sandbox=box)
ValueError: A sandboxed agent requires a PostgresDb or AsyncPostgresDb, on the agent or its AgentOS
```

`BaseExternalAgent` gains two options that the sandbox runtime turns on for every turn. `require_native_resume` fails the run when the recorded native conversation cannot be resumed, and `strict_persistence` fails it when its run row cannot be written. The new `agno[claude]` and `agno[codex]` extras install `claude-agent-sdk` and `openai-codex`.

This entry ran with no model key and no container. The release's 243 runtime, checkpoint and `sandbox=` unit tests pass, and so do its 120 Postgres store tests for leases, staging and the atomic commit, on an embedded Postgres.

See the [cookbook](https://github.com/agno-agi/agno/blob/main/cookbook/frameworks/sandbox/docker/sandbox_claude.py), and learn more about [running Claude and Codex as agent harnesses](https://docs.agno.com/agent-os/multi-framework/overview) in the documentation.
