Skip to content
Changelog

Serve sandboxed Claude and Codex agents from AgentOS with no new endpoints

October 16, 20262 min read

Agno AgentOS accepts a sandboxed ClaudeAgent or CodexAgent only on a durable queue with Redis coordination, because any replica may run the next turn. Register the agent the way you register any other and the run route does the rest.

from agno.agents.claude import ClaudeAgent
from agno.db.postgres import PostgresDb
from agno.job_queue.config import QueueConfig, RedisCoordination
from agno.os import AgentOS
from agno.sandbox.checkpoint import FileCheckpointStore
from agno.sandbox.docker import DockerSandbox
 
db = PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai")
agent = ClaudeAgent(
    id="coder",
    permission_mode="bypassPermissions",
    sandbox=DockerSandbox(
        "agno-sandbox:local",
        network="isolated",
        checkpoints=FileCheckpointStore("/shared/checkpoints"),
    ),
)
agent_os = AgentOS(
    agents=[agent],
    db=db,
    queue=QueueConfig(durable=True, db=db, redis=RedisCoordination(url="redis://localhost:6379/0")),
)

A foreground request waits on the queued run and returns it, stream=true tails its events, and background=true answers 202 with a run_id. A client that drops reconnects with /runs/{run_id}/resume and its last_event_index, and /runs/{run_id}/cancel works from any replica. When the cancel settles on another replica, the run row records the run as cancelled and keeps the user's message.

Retries with an Idempotency-Key

A client that retries with the same Idempotency-Key gets the run it already started. If the key comes back with another session, user or agent, AgentOS answers 409, and the same goes for changed input, run options or attachment bytes. Changing only stream or background still returns the original run.

We ran the release's AgentOS through FastAPI's TestClient on an embedded Postgres, with fakeredis for Redis and a stand-in sandbox that has no compute, since every check here happens before a computer starts.

Real output from four POSTs to /agents/coder/runs with Idempotency-Key ticket-42 on a sandboxed ClaudeAgent, using a stand-in sandbox. The first request returns 202 with run_id df2b2787 and status PENDING. A retry with the same body returns 202 with the same run_id df2b2787, PENDING. The same key with a new message returns 409 Idempotency-Key already has different input or options. The same key with a new session_id returns 409 Idempotency-Key belongs to a different submission scope. Below, building AgentOS with the sandboxed agent and a SqliteDb raises ValueError: A sandboxed agent requires a PostgresDb or AsyncPostgresDb, on the agent or its AgentOS.

Mistakes caught before a turn runs

A sandboxed agent coordinates every turn through Postgres, so AgentOS(...) raises at construction when neither the agent nor AgentOS has a PostgresDb or AsyncPostgresDb. Once a queue worker is active, AgentOS also refuses a sandbox left on the default ~/.agno/sandbox/checkpoints folder, which other replicas can't read. That submission came back as a 500 in the test run, and AgentOS cancelled the ticket before it could execute.

AgentOS validates each sandboxed agent's <session_table>_sandbox_bindings table at startup and again before a submission creates its ticket. A table left by an earlier build fails with its remedy, telling you to drop or rename that table or pass PostgresDb(sandbox_table=...) to create a new one. A user_id that doesn't match the session's owner gets a 404 before any ticket exists, and a foreground job that failed before its run row was written returns that job's error as a 500.

See the cookbook, and learn more about the durable queue and idempotency keys in the documentation.

Frequently asked questions

The usual POST /agents/{agent_id}/runs. AgentOS puts the request on its durable queue whether you ask for a foreground answer, a stream or a background run, and /runs/{run_id}/resume and /runs/{run_id}/cancel work from any replica.

A PostgresDb or AsyncPostgresDb, on the agent or on AgentOS, and QueueConfig(durable=True) with Redis coordination. Without Postgres, building AgentOS raises a ValueError; without the durable queue and Redis, the run route answers 400.

When the key was already used for a different session, user or agent, or for different input, run options or attachment bytes. The same submission sent again returns the original run, even with another stream or background value.

Once a queue worker is active, any replica may run the next attempt, and the default ~/.agno/sandbox/checkpoints lives on one host. AgentOS cancels the submission before it executes, so pass checkpoints= storage that every replica can read.

Shipped around the same time