---
ai_assisted: true
title: "Model Providers Are Taking Over the Agent Runtime: Managed Agents and the OpenAI Agents API"
description: "What Anthropic Managed Agents and the OpenAI Agents API add to each provider's lineup, how the two runtime APIs converged on the same abstractions, a run of the same task on both, and a comparison with local harnesses and cloud coding products"
pubDate: 2026-10-23
category: "AI"
subcategory: "Agent"
serial: 41
tags: ["Claude", "Managed Agents", "Agent SDK", "OpenAI", "Agents API", "Codex"]
heroImage: ""
draft: false
published: true
---

Anthropic's documentation describes two ways to build with Claude. One is the Messages API, which calls the model directly. The other is Claude Managed Agents, which the documentation calls a "pre-built, configurable agent harness that runs in managed infrastructure." OpenAI's documentation lays out a similar split in a table: the Responses API for working with model responses directly, the Agents SDK for running an agent loop inside your application, and the Agents API, which runs "a managed Codex harness."

Both providers have added the same kind of layer to their lineups. Until now, a model provider sold tokens, and developers built the agent loop, tool execution, sandboxing, and state storage themselves. Run locally, tools such as Claude Code and Codex executed that loop on your own machine, and the Agent SDK opened the same loop up as a library. Managed Agents and the Agents API go one step further. They move the loop, the execution environment, and the session state onto the provider's servers, and expose them as API resources a program can work with.

This post looks at that shift from three angles. First, it maps how far the provider's share of the work now reaches, layer by layer. Second, it looks at how the two providers' runtime APIs converged on the same abstractions, using a run of the same Fibonacci task on both APIs as evidence. Third, it weighs what a developer gains from this layer and what they hand over.

I called Claude Managed Agents, the Claude Agent SDK, the OpenAI Responses API, and the OpenAI Agents API with the `none` and `openai_hosted` environments. The OpenAI Agents SDK, both providers' self-hosted environments, Claude Code cloud sessions, and Codex Cloud are covered only from their official documentation. This reflects the state as of 2026-10-23, and both APIs are in beta.

## 1. The provider's share keeps growing

Running an agent takes five things:

1. Model inference.
2. A loop that picks tools and feeds their results back to the model. This is the harness.
3. An execution environment where commands and file operations actually happen.
4. Session state that holds the conversation and the results.
5. A trigger that starts the work, and a screen where a person sees the result.

The two providers' product lines now split into four layers, depending on who handles each of these five things.

| Responsibility | Model API (Messages, Responses) | Local harness (`claude -p`, Claude Agent SDK, Codex local runs, OpenAI Agents SDK) | Hosted runtime API (Managed Agents, Agents API) | Cloud coding product (Claude Code cloud, Codex Cloud) |
| --- | --- | --- | --- | --- |
| Model inference | Provider | Provider | Provider | Provider |
| Tool loop | You | Provider-written code running on your machine or in your app | Provider | Provider |
| Execution environment | You | Your machine, or a sandbox you choose | Provider sandbox, or your infrastructure | Provider VM |
| Session state | You (OpenAI also offers Conversations and similar options) | Your machine or your storage | Provider servers | Provider servers |
| Trigger and screen | You | Terminal or your app | Your code (the provider supports webhooks and scheduled runs) | The provider's web, mobile, and desktop apps |

Moving right across the table, the provider fills more of the cells. What is new about the hosted runtime API is that the provider takes over the harness, the execution environment, and the session state, yet stops short of the screen. Instead it hands those three pieces to you as resources that a program can combine. One way to read it: a cloud coding product bundles these layers behind a screen for people, and a hosted runtime API unbundles them into parts for programs.

OpenAI's documentation states this relationship outright. It says the Agents API runs "a managed Codex harness," and lists automatic context compaction, multi-agent orchestration, programmatic tool calling, and MCP server support among its features. Anthropic's documentation says the Managed Agents harness supports built-in prompt caching and compaction, but it does not call that harness Claude Code. I did not confirm whether either provider's hosted harness is the same code as its coding product. The reading above rests on how the documentation names and groups these products.

## 2. The two runtime APIs converged on the same abstractions

Side by side, the two APIs share a skeleton even where names and paths differ. Both separate configuration (the agent) from execution (the session), put an execution environment between them, keep the conversation on the provider's servers, and expose output files from a fixed directory through an API. The endpoints and response shapes below come from my own calls. The default tools and the budget row come from the documentation.

| Concept | Claude Managed Agents | OpenAI Agents API |
| --- | --- | --- |
| Beta marker | `anthropic-beta: managed-agents-2026-04-01` | `OpenAI-Beta: agents=v1` |
| Agent definition | Separate resource `POST /v1/agents`, referenced by ID from a session | Inline `agent` in the session request, or a saved agent ID |
| Execution environment | Separate resource `POST /v1/environments` (`cloud`, `self_hosted`) | Inline `environment` in the session request (`none`, `openai_hosted`, `self_hosted`) |
| Unit of execution | Session `POST /v1/sessions`; messages are sent separately | Session `POST /v1/agents/sessions`; creation and first input in one call |
| Conversation record | Events at `/v1/sessions/{id}/events` | Items at `/v1/agents/sessions/{id}/items` |
| Completion signal | `session.status_idle` event | Session `status` plus turn events (`agent.session.turn.completed` and others) |
| Output files | Write to `/mnt/session/outputs/`, list with the Files API `scope_id` filter | Write to `/workspace/outputs`, list with the artifacts API |
| Cost information | `usage` plus `list_cost` (a string of cents) | `usage` (documented as best-effort, may be `null`) |
| Server-side budget | `max_list_cost` at session creation | Not found in the documentation pages I checked |
| Default tools | `agent_toolset_20260401` (bash, read, write, edit, glob, grep, web_fetch, web_search) | Codex harness tools |
| Cleanup | Sessions and environments with `DELETE`; agents can only be archived | Session `DELETE`; artifacts are no longer downloadable afterward |

The differences are in the details. Claude makes you create an environment as a reusable resource and separates session creation from sending a message. OpenAI lets you put the agent and the environment inline in the session request and accepts the first input in the same call. To start the same task, I made four calls to Claude, including agent creation, and one call to OpenAI. With a reused agent, the Claude side takes three. Cost information differs too. Claude gives you the session's cost directly as `list_cost`, while OpenAI gives usage only as a best-effort value.

Why they converged is a matter of interpretation, and what follows is mine. Any team that wanted to run agents kept rebuilding the same parts, whatever the provider: a tool loop, an isolated execution environment, a way to move files in and out, and state that lets an interrupted task resume. As the two providers absorbed those common parts, their API surfaces took on the shape of those parts. That both providers left a self-hosted exit fits the same pattern. For customers who cannot hand over the execution environment, the provider keeps the harness and the state while the compute stays on the customer's side.

## 3. A first session on Claude Managed Agents

Managed Agents has four resources. An agent is a configuration that bundles a model, system prompt, tools, MCP servers, and skills. You create it once and reference its ID from many sessions. An environment defines what the sandbox looks like and holds no files. A session is one run that pairs an agent with an environment, and each session gets its own sandbox. Events are the messages, tool calls and results, and status changes that pass through a session.

![Relationships among agent, environment, session, and events, with the paths for mounted uploads and output files](https://media.jaesolshin.com/media/df41cc4ace13270b9fb3442efa8eea182bac2adf86a11ae428abd7840d0f04d4.png)

If you use the Python SDK, you need an `anthropic` version that includes `client.beta.agents`. I confirmed that `beta.agents`, `beta.sessions`, and `beta.environments` exist in 0.116.0 and in 2.1.0. According to the documentation, Managed Agents is also available on Claude Platform on AWS, with some differences in features and session behavior. Below are the six curl steps I ran. I sent the task instructions in Korean; the prompts in this post's code are English translations, and everything else in the requests is unchanged.

**Step 1: Define the headers.** Put the authentication header and the beta header in an array named `H`. The shell expands the array's values at the moment you define it, so defining it before the key is loaded freezes an empty key into the array and authentication fails. If authentication fails, check this order first.

```bash
# Define this after loading the key. The array expands its values at definition time
H=(-H "x-api-key: $ANTHROPIC_API_KEY" -H "anthropic-version: 2023-06-01" \
   -H "anthropic-beta: managed-agents-2026-04-01" -H "content-type: application/json")
```

The `anthropic-beta` header is the beta marker that enables Managed Agents. Without it, the agent API paths are not available.

**Step 2: Get an agent.** Create an agent named `probe` and store its ID in `AGENT_ID`. Because the command extracts only the `id` field from the response, you never copy the ID by hand. Agents cannot be deleted, so run this command only once.

```bash
# Agent: create it only once. Running this again creates another agent
AGENT_ID=$(curl -sS "${H[@]}" https://api.anthropic.com/v1/agents \
  -d '{"name":"probe","model":"claude-haiku-5-5","tools":[{"type":"agent_toolset_20260401"}]}' | jq -r .id)
```

`agent_toolset_20260401` turns on the shell, file read and write, search, and web tools at once. This setting is why the agent in this experiment could write and run a script with `bash`. Each tool can take a `permission_policy`, and the default for this toolset is `always_allow`, which runs tools without approval.

Opening this experiment's `probe` agent in the Console shows the eight tools in the toolset and the permission of each. All eight are set to always allow. The Console screenshots in this post show the Korean UI.

![Tool settings of the probe agent in the Console, Korean UI. Under the built-in toolset agent_toolset_20260401, bash, read, write, edit, glob, grep, web_fetch and web_search are all set to always allow](https://media.jaesolshin.com/media/771a2dd25b5fe59dc3ec280425b29be1964a33f95a390d3e9492e80b6971824f.png)

**Step 3: Create an environment.** Create the environment that defines the sandbox and store its ID in `ENV_ID`. `cloud` is a sandbox that Anthropic runs, and `limited` networking restricts outside access to an allowlist. Setting `allow_package_managers` opens access to package managers.

```bash
# Environment
ENV_ID=$(curl -sS "${H[@]}" https://api.anthropic.com/v1/environments \
  -d '{"name":"probe-env","config":{"type":"cloud","networking":{"type":"limited","allow_package_managers":true}}}' | jq -r .id)
```

An environment is configuration, not storage. Sessions that use the same environment do not share a filesystem.

**Step 4: Create a session with a budget.** Combine the agent and the environment into a session. `budget` caps what the session can spend. The value is a string of cents, so `"50"` means $0.50. Building the JSON with `jq -n --arg` saves you from escaping quotes by hand.

```bash
# Session: the budget is a string of cents. "50" means $0.50
SESSION_ID=$(jq -n --arg a "$AGENT_ID" --arg e "$ENV_ID" \
  '{agent: $a, environment_id: $e, budget: {type: "limit", max_list_cost: {amount: "50", currency: "USD"}}}' \
  | curl -sS "${H[@]}" https://api.anthropic.com/v1/sessions -d @- | jq -r .id)
```

A budget can be set only when the session is created. The documentation says new model requests stop once the cap is reached, but this experiment never reached the cap.

**Step 5: Send the message.** Post a `user.message` to the session's events. This message is the task instruction.

```bash
# Send the message
curl -sS "${H[@]}" https://api.anthropic.com/v1/sessions/$SESSION_ID/events \
  -d '{"events":[{"type":"user.message","content":[{"type":"text","text":"Write a script that saves the first 20 Fibonacci numbers to fibonacci.txt, then run it."}]}]}' | jq .
```

The response echoes the message you just sent as an event. Whether the task has finished is checked in the next step, not here.

**Step 6: Wait for completion.** Poll the event list every 5 seconds, up to 60 times (five minutes), until a `session.status_idle` event appears. `jq -e` exits with status 0 when its condition holds, which is why `&& break` ends the loop.

```bash
# Wait for a session.status_idle event, for up to five minutes
for i in $(seq 1 60); do
  curl -sS "${H[@]}" https://api.anthropic.com/v1/sessions/$SESSION_ID/events \
    | jq -e '.data[] | select(.type=="session.status_idle")' > /dev/null && break
  sleep 5
done
```

The agent wrote `save_fibonacci.py` with its `bash` tool and ran it. The session ended in `idle`, and the result file `fibonacci.txt` (134 bytes) appeared in the session. Each line held an index and a value, such as `0: 0` and `1: 1`. Section 7 covers how to download the result.

Sessions are also tallied on the Console's agents overview page. The screenshot below is from 2026-10-27. It shows the session count and error rate for the last 30 days, daily sessions per agent, and the median active time per session. `probe` is the agent from this post. The two whose names start with `sre-blogp3-` come from [Part 3](/posts/managed-agents-brain-hands-session/).

![The Console agents overview, Korean UI: 16 sessions and a 0% error rate in the last 30 days, 3 agents with sessions, a bar chart of daily sessions per agent, and the median active time per session (sre-blogp3-commander 2 min 5 s, probe 5 s, sre-blogp3-probe 4 s)](https://media.jaesolshin.com/media/8ae7a24eac61bc2d84313f716fd6e0bf2662378012ee71aed468f3b54f365f57.png)

## 4. The same task on the OpenAI Agents API

I ran the same Fibonacci task on the OpenAI Agents API, with the `gpt-6-luna` model and an OpenAI-run `openai_hosted` sandbox of size `small`.

**Step 1: Define the headers.** OpenAI uses Bearer authentication and the `OpenAI-Beta: agents=v1` header.

```bash
OH=(-H "Authorization: Bearer $OPENAI_API_KEY" -H "OpenAI-Beta: agents=v1" -H "content-type: application/json")
```

Without the beta header, the API replies with `To access the Agents API, set the 'OpenAI-Beta' header to 'agents=v1'.` The error names the header and value it expects.

**Step 2: Create the session with the first input.** Put the agent configuration, the environment, and the first input in a single request. This one call covers what steps 2 through 5 did on the Claude side.

```bash
OSID=$(curl -sS "${OH[@]}" https://api.openai.com/v1/agents/sessions -d '{
  "agent": {"model": "gpt-6-luna", "instructions": "You are a helpful coding assistant. Write clean, well-documented code."},
  "environment": {"type": "openai_hosted", "container_size": "small"},
  "input": [{"role": "user", "content": [{"type": "input_text",
    "text": "Write a script that saves the first 20 Fibonacci numbers to fibonacci.txt, then run it. Save the result to /workspace/outputs/fibonacci.txt."}]}]
}' | jq -r .id)
```

The response's `environment` came back with the defaults filled in. Network access was `enabled` with an empty list of allowed domains, the desktop was disabled, and skill directories for documents, presentations, and spreadsheets were attached as `capability_directories`. In other words, a session starts with the network open unless you say otherwise, so set restrictions explicitly when you create it.

**Step 3: Wait for completion.** Wait until the session `status` leaves `in_progress` and an item other than the user message appears. Section 5 explains why the status alone is not enough.

```bash
for i in $(seq 1 50); do
  ST=$(curl -sS "${OH[@]}" https://api.openai.com/v1/agents/sessions/$OSID | jq -r .status)
  if [ "$ST" != in_progress ]; then
    N=$(curl -sS "${OH[@]}" https://api.openai.com/v1/agents/sessions/$OSID/items \
      | jq '[.data[] | select(.type!="message" or .role=="assistant")] | length')
    [ "$N" -gt 0 ] && break
  fi
  sleep 6
done
```

**Step 4: Read the items.** A session's items record reasoning (`reasoning`) and command runs (`command_execution`) alongside messages. They correspond to Claude's event list.

```bash
curl -sS "${OH[@]}" https://api.openai.com/v1/agents/sessions/$OSID/items | jq -c '.data[] | {type, role}'
```

In this run, user messages, assistant messages, reasoning, and command execution items were interleaved. The agent first described its plan, ran commands twice, and finished with a message pointing to the result file and the script.

**Step 5: List and download the artifacts.** When a turn completes, files in `/workspace/outputs` are published as artifacts. Get the IDs and paths from the list, then download each file separately. The documentation says there is no endpoint for downloading several files at once.

```bash
# List artifacts
curl -sS "${OH[@]}" https://api.openai.com/v1/agents/sessions/$OSID/artifacts \
  | jq -c '.data[] | {id, path, turn_id, size_bytes}'

# Download all of them
OUT=~/Downloads/openai-$OSID
mkdir -p $OUT
curl -sS "${OH[@]}" https://api.openai.com/v1/agents/sessions/$OSID/artifacts \
  | jq -r '.data[] | "\(.id) \(.path | split("/") | last)"' \
  | while read aid name; do
      curl -sS "${OH[@]}" https://api.openai.com/v1/agents/sessions/$OSID/artifacts/$aid/content -o "$OUT/$name"
    done
ls -l $OUT
```

There were two artifacts, `fibonacci.txt` (64 bytes) and `generate_fibonacci.py` (572 bytes), both with the same `turn_id`. The downloaded `fibonacci.txt` held the 20 values from 0 to 4181, one per line.

**Step 6: Delete the session.** The delete response was `agent.session.deleted` with `deleted: true`, and fetching the session afterward returned `not_found_error`.

```bash
curl -sS -X DELETE "${OH[@]}" https://api.openai.com/v1/agents/sessions/$OSID | jq -c '{object, deleted}'
```

When I tried to download the same artifact after the deletion, I got a `404`. The documentation says artifacts survive sandbox expiration and tells you to download anything you need before deleting the session. In practice, deleting the session also cut off access to its artifacts.

**Same task, different output.** Both results had the correct 20 values, but the formats differed. Claude's file prefixed each value with an index and came to 134 bytes. OpenAI's file held only the values and came to 64 bytes. When the instruction does not specify a format, the output depends on the model and the harness. If another program has to read the result, state the format in the instruction.

## 5. Turns and deciding when work is done

The two APIs decide "the work is finished" in different ways, and this difference is the first thing to break automation code.

In the Claude experiment, the `session.status_idle` event matched task completion well. By the time the event appeared, the result file already existed.

On the OpenAI side, a run showed that the session status alone cannot be trusted. The first time I fetched the session right after creating it, it already showed `idle`, yet the item list held only the user message. On the next fetch the status had changed to `in_progress`, and the work finished only after assistant messages and command execution items appeared. That is why the wait loop above checks both the status and the items.

OpenAI's documentation warns about this as well. An idle session does not mean the turn succeeded, so it tells you to check whether `agent.session.turn.completed`, `agent.session.turn.failed`, or `agent.session.turn.cancelled` arrived. It also notes that a completed turn does not guarantee that every individual tool call succeeded.

Both providers document ways to intervene during a run. Anthropic's documentation says you can send additional user events to steer a running agent or interrupt it. OpenAI's documentation distinguishes two cases: a message sent during an active turn steers that turn, while a message sent to an idle session starts a new turn. OpenAI also documents an `Idempotency-Key` header so that a retried submission is processed only once, and notes that a dropped stream does not replay missed events, so after reconnecting you fetch the stored items to recover the state. I did not run any of these intervention features in this experiment.

## 6. Usage and cost: the harness has a fixed cost

A hosted runtime adds costs beyond tokens, and it also increases the token count itself, because the harness adds instructions and tool definitions to the input of every turn.

The runs confirmed this fixed cost. I sent short requests to the same OpenAI `gpt-6-luna` model in two ways. A Responses API request that asked, in Korean, for a one-word reply of "hello" used 16 input tokens. An Agents API session with the `none` environment, a one-line instruction, and the Korean input "hello" used 7,734 input tokens. The two requests were worded slightly differently, but a gap of thousands of tokens most likely comes from the context the harness adds. The Claude side has the same structure. When I sent one short question to Sonnet 5.5 through the Claude Agent SDK, it recorded 29,209 cache-read tokens and 12,310 cache-write tokens.

### Claude: `list_cost` gives the session cost

Fetching a Claude Managed Agents session returns `usage` along with `list_cost`.

```bash
curl -sS "${H[@]}" https://api.anthropic.com/v1/sessions/$SESSION_ID | jq '{id, status, usage}'
```

```json
{
  "status": "idle",
  "usage": {
    "active_seconds": 7.121,
    "cache_creation": { "ephemeral_5m_input_tokens": 7377 },
    "cache_read_input_tokens": 6147,
    "input_tokens": 6,
    "output_tokens": 1159,
    "list_cost": { "amount": "1", "currency": "USD" },
    "server_tool_use": { "web_fetch_requests": 0, "web_search_requests": 0 }
  }
}
```

`input_tokens` counts only the input after the last cache breakpoint. Total input is the sum of cache reads, cache writes, and that remaining input: 6 + 6,147 + 7,377 = 13,530 tokens in this run. Long system prompts and tool definitions mostly go through the cache, and only the new message counts as remaining input.

![Total input of 13,530 tokens made up of cache reads, cache writes, and remaining input](https://media.jaesolshin.com/media/58837ddc7bf2e6863c05d7b8758d25fa94ec0d29b13aeda9a0df5da6c8978575.png)

`list_cost` was one cent. The same usage priced at Haiku rates comes to about 0.16 cents, so the reported value is larger than the token cost. I could not find in the official documentation whether this is rounding up to a whole cent or a separate charge based on session active time. I leave that difference unresolved.

### OpenAI: usage is best-effort

OpenAI's documentation states that Agents API `usage` is best-effort. It may be `null`, it may change later, and it is not a final bill. The runs matched that description. The `none`-environment session reported input and output tokens, but the Fibonacci session still showed `usage` as `null` after its turn had finished. The documentation says cache-write tokens are not reported separately in Agents API usage. A Responses API response, by contrast, did include a `cache_write_tokens` field, with a value of 0.

The cost components differ as well. According to OpenAI's pricing page, hosted shell and code interpreter containers are billed per 20-minute session: $0.03 for 1 GB, $0.12 for 4 GB, $0.48 for 16 GB, and $1.92 for 64 GB. Web search costs $10 per 1,000 calls, plus the search content tokens at model rates. On the Claude side, one web search measured at about $0.01, but that is an observed value, not a documented price. I also could not find a documented price for Claude session active time.

### Hidden calls and streamed values

When the Claude Agent SDK ran a web search, the CLI made an extra internal call to Haiku for each search. That call's input was about 14K tokens, and it never appeared in the message stream; it showed up only in the per-model totals (`model_usage`). Adding up message-level usage alone badly undercounts the cost.

Streamed values need care too. In the Agent SDK's message stream, each chunk with the same `message_id` carries a `usage` object, but the chunk's values stayed at their start-of-message level. One message's chunks reported 4 output tokens, while its final value was 4,579. The more of the harness the provider runs, the more the provider decides the units of measurement. Until you confirm that the totals reconcile, do not use any single measurement as the basis for cost.

## 7. Files and sandboxes

In both APIs, files move in and out through fixed directories.

In Claude Managed Agents, you upload a file with the Files API and mount it when you create the session, as a `file` entry under `resources`. A mounted file is a read-only copy, so modified versions go to another path in the sandbox. Files the agent writes to `/mnt/session/outputs/` appear in the Files API, scoped to the session.

```bash
# Output files for the session
curl -sS "${H[@]}" "https://api.anthropic.com/v1/files?scope_id=$SESSION_ID" | jq -c '.data[] | {id, filename, size_bytes}'

# Download all of them
OUT=~/Downloads/managed-$SESSION_ID
mkdir -p $OUT
curl -sS "${H[@]}" "https://api.anthropic.com/v1/files?scope_id=$SESSION_ID" \
  | jq -r '.data[] | "\(.id) \(.filename)"' \
  | while read id name; do
      curl -sS "${H[@]}" "https://api.anthropic.com/v1/files/$id/content" -o "$OUT/$name"
    done
ls -l $OUT
```

In this run, `fibonacci.txt` and `save_fibonacci.py` (1,025 bytes) appeared in the list right away. The documentation notes that a freshly written file can take a moment to appear. The limits are 500 MB per file, 1 TB per organization, and 500 mounted files per session. I did not check whether files survive after a session is deleted.

The OpenAI Agents API documents its limits in finer detail. A session creation request can include up to 50 files. Inline uploads are limited to 5 MiB per file and 10 MiB per request, and files copied from the Files API to 50 MiB each. Artifacts can be up to 200 MiB per file, and a single publication can total up to 500 MiB. Artifacts are published per turn and cannot be edited, so to get a new version you ask the agent to rewrite the file and tell versions apart by turn ID and path.

OpenAI is also more explicit about sandbox lifetime. A hosted sandbox receives keep-alives while connected, and it can be deleted after an hour without activity or keep-alives. That limit is not configurable. Deleting the session requests sandbox cleanup, and you may get a `409` while cleanup is in progress. Container sizes are `small` (1 vCPU, 1 GB), `medium` (2 vCPUs, 4 GB, the default), and `large` (4 vCPUs, 16 GB).

### Who operates the execution environment

Both providers offer self-hosting, and in both cases the operating responsibility moves to the customer.

- In a Claude Managed Agents `self_hosted` environment, a worker process on your infrastructure runs the tools. The worker host must run Linux, and the documentation recommends keeping the API key off that host. Custom tools are supported only by the SDK workers.
- In an OpenAI `self_hosted` environment, you start the compute and attach an executor to the session. Provisioning, reconnection, shutdown, and file retention are all your responsibility. The documentation states that deleting a session neither stops its environment nor emits a deletion webhook.

With self-hosting, "delete the session" and "stop the compute" are separate actions. If you only delete the session, the compute can keep costing money.

The OpenAI Agents SDK treats the sandbox as a layer on the application side. A `SandboxAgent` has the same surface as a regular agent and changes only the execution boundary to a live sandbox. You define the workspace's initial state with a `Manifest` and choose where it runs, from a local Unix environment, Docker, or a hosted provider, through a sandbox client. The documentation recommends keeping the harness in your application and only the compute in the sandbox, which is the opposite split from a hosted runtime API.

## 8. Resource lifecycle and cleanup

Claude's resources are deleted in different ways. The table below reflects what I confirmed in the experiment.

| Resource | Deletion | Other behavior |
| --- | --- | --- |
| Session | Deleted with `DELETE` | Response `session_deleted` |
| Environment | Deleted with `DELETE` | Response `environment_deleted` |
| Agent | `DELETE` returns `not_found` | Archived with `POST .../archive`; cannot be undone |

An archived agent disappears from the default list (`GET /v1/agents`) and comes back when you add `?include_archived=true`. The documentation does not describe this, so I report it as an observation. An agent's name can be changed through the update API, and the version went from 1 to 2 when I renamed one.

The agent list in the Console behaves the same way. With the status filter at its default, Active, no archived agent appears. Switching it to All brings them back with an Archived badge.

![The Console agent list with the status filter set to All, Korean UI. All five agents appear with an Archived badge, along with their model, creator and creation date](https://media.jaesolshin.com/media/2969c793c3ec8db3f72fd0d57d7f03aae2b0fc6982a4ac963c6111e8f633595c.png)

```bash
# List agents. archived_at is null for agents that are not archived
curl -sS "${H[@]}" https://api.anthropic.com/v1/agents | jq -c '.data[] | {id, name, version, archived_at}'

# Archive (cannot be undone). Run only when AGENT_ID starts with agent_
[[ "$AGENT_ID" == agent_* ]] && curl -sS -X POST "${H[@]}" https://api.anthropic.com/v1/agents/$AGENT_ID/archive | jq '{id, name, archived_at}'
```

The fact that agents cannot be deleted affects design. When agents with similar names accumulate, code that looks them up by name becomes ambiguous. Decide an agent's name and how many you need before you create them. On the OpenAI side, passing the agent inline in the session request leaves no separate agent resource behind. Deleting the session completes the cleanup, but as section 4 showed, the artifacts can no longer be downloaded afterward.

## 9. Where configuration lives

The biggest change a hosted runtime API brings is where configuration lives. With a local harness, configuration sits in files and code. With a hosted runtime, it sits in resources on the provider's servers.

`claude -p` spreads its configuration across the shell and files: command-line flags, project settings files, and instruction files in the current directory all apply, and you continue a conversation with `--resume` and a session ID. In the Claude Agent SDK, configuration is a `ClaudeAgentOptions` object in your code. It holds the model, allowed tools, MCP servers, turn limit, budget, and thinking settings, and `@tool` turns a Python function into a tool.

```python
import asyncio
from claude_agent_sdk import AssistantMessage, ClaudeAgentOptions, ResultMessage, TextBlock, query

async def main():
    options = ClaudeAgentOptions(model="claude-haiku-5-5", tools=[], max_turns=1)
    async for message in query(prompt="Reply with the single word hello.", options=options):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)
        elif isinstance(message, ResultMessage):
            print("Cost (reported by SDK):", message.total_cost_usd)

asyncio.run(main())
```

In the OpenAI Agents SDK, configuration is also an object in application code. You additionally choose one of four places to keep conversation state: the app passes earlier history itself, the app uses its own storage with SDK sessions, it uses a server-side Conversations object, or it chains from a previous response ID. The documentation recommends using one approach per conversation, because mixing local replay with server state duplicates context.

With a hosted runtime, configuration is a server resource, so a new question appears: which runs does a configuration change apply to? OpenAI's documentation spells out the rule. A change to a saved agent applies only to new sessions; a session copies the configuration at creation time. On an existing session, you can change only the model, reasoning effort, and service tier, and changing instructions or tools requires a new session. In partial updates, omitted fields keep their values, but object fields are replaced as a whole. Sending only `effort` under `reasoning` removes a previously saved `summary`, and sending a `tools` array replaces the entire existing list.

On Claude Managed Agents, I confirmed that renaming works through the update API and that it bumps the version. I did not confirm the partial update rules or whether a running session keeps a copy of the configuration. There is not yet evidence to say the two products behave the same here.

## 10. The human-facing outlet of the same runtime: Claude Code cloud and Codex Cloud

Hosted runtimes did not arrive only as APIs. Both providers also ship the same layer with a screen for people: Claude Code cloud sessions (claude.ai/code, `claude --cloud`) and Codex Cloud. These are products where a developer hands off a task from the web, mobile, or desktop app and picks it up later. In the table in section 1, they are the fourth layer, where the provider handles the screen as well.

| Aspect | Claude Code cloud session | Codex Cloud | Managed Agents | OpenAI Agents API |
| --- | --- | --- | --- | --- |
| Who drives it | A person (web, mobile, desktop, terminal) | A person (web, mobile, desktop, CLI) | A program | A program |
| Unit of work | Session | Task, each with its own workspace | Session and events | Session and turns |
| Reusable configuration | The repository's CLAUDE.md, hooks, skills, agents, commands | Environment (repositories, tools, service access) | Agent and environment resources | Saved agent, or inline configuration |
| How config changes apply | Not found in the documentation | Edit and republish the environment for new tasks; existing tasks keep their own state | Not confirmed | New sessions only |
| Starting material | Clone of a GitHub repository, or a bundle of a local repository | Prepared filesystem of a published environment | Mounted repository, uploaded files | Uploaded files |
| Where it runs | Anthropic-managed VM (Ubuntu 24.04) | OpenAI-managed VM | Anthropic sandbox or self-hosted | OpenAI sandbox, self-hosted, or no sandbox |
| Link to a local machine | `--teleport` brings a cloud session into the terminal (one direction) | Mobile app controls tasks on a connected Mac or Windows PC | Self-hosted worker | Self-hosted executor |
| State retention | Not found in the documentation | Task VM state recoverable for up to seven days after the last turn | Session history stays on the server; sandbox retention not confirmed | Sandbox may be deleted after an hour idle; artifacts until session deletion |
| Billing | Subscription usage limits (API credit does not apply) | ChatGPT plan (usage units not found) | API tokens, session active time, web search | API tokens, containers, web search |
| Server-side budget | None | Not found | `max_list_cost` | Not found |

Both cloud coding products configure work at the level of repositories and environments. Claude Code cloud reads the Claude Code settings stored in the repository, and does not use the `~/.claude` settings on your own machine. Codex Cloud has you prepare, test, and publish an environment that bundles repositories, dependencies, tools, and service access. Each task starts in its own workspace from that published environment, and file changes made inside a task do not update the environment. In Codex Cloud, skills stored in the repository are available in cloud tasks, but personal skills on your computer are not synced.

The Codex Cloud documentation goes into detail on networking and secrets. The current documentation describes turning on internet access in the environment settings and limiting it with a package-manager preset or custom domains. Secrets come in two kinds: environment variables that programs read directly, and network secrets sent only to specific HTTPS destinations. A program sees only a placeholder for a network secret, and a proxy substitutes the real value when a request goes to an allowed destination. I did not find rules at the same level in the Claude Code cloud documentation, so this item is not compared.

Codex lets you choose where a task runs from a single screen. When starting a task in the desktop app, you pick "This computer" or "Cloud," and for a local Git project you can isolate changes in a worktree. The mobile app controls both cloud tasks and tasks running on a connected PC, and you approve commands and review changes from the phone. A cloud task uses only the files and services in its cloud environment; your computer's local files, running processes, browser sign-ins, and VPN access do not carry over automatically.

Read in the context of section 1, the two providers ship the same hosted runtime through two outlets: to people, as a screen with repository-centered configuration, and to programs, as an API centered on resources and measurement. OpenAI calling the Agents API a "Codex harness" is an official acknowledgment of that connection. I did not confirm, however, whether Codex Cloud and the Agents API share infrastructure, or whether Claude Code cloud and Managed Agents share a harness. I did not run either cloud coding product, and the table reflects their documentation.

## 11. Controls

On a hosted runtime, you control execution through permissions, networking, budgets, and secrets. As the provider takes over execution, these controls become configuration settings.

Claude Managed Agents sets approval per tool with `permission_policy`. `always_allow` runs automatically, and `always_ask` pauses the session to wait for approval. The default is `always_allow` for the agent toolset and `always_ask` for MCP tools. Networking is set by the environment's `networking.type`, and the budget is set by the session's `max_list_cost`.

For the OpenAI Agents API, I did not find a session budget or spend cap in the documentation pages I checked. Networking is set in the sandbox configuration as `enabled`, `disabled`, or `restricted` (allowed domains only), and in my run a session with no network setting started as `enabled`. Secrets are kept outside the sandbox as vault credentials, and reserved names such as `PATH`, `CODEX_*`, and `OPENAI_API_KEY` cannot be used as environment variables.

The OpenAI Agents SDK treats approval as part of the application's flow. When a run pauses for approval, you handle its `interruptions` and resume from the saved `state`. This continues the paused run rather than starting a new user turn.

Among local harnesses, `claude -p` runs within subscription limits, so there is no server-side budget cap; you restrict execution with allowed tools and permission modes. The same command can land in a different billing ledger depending on how it authenticates, as covered in [Part 1](/posts/claude-api-credits-setup-guide/). The Claude Agent SDK accepts `max_budget_usd`, but when two agents that used web search each ran with a $1 cap, both spent more than $1 ($1.28 and $1.20). I did not confirm when the cap is checked, so do not rely on this value as a cost guarantee.

In short, among the products covered here, only Claude Managed Agents documents a server-enforced budget. I did not confirm that the enforcement actually works.

## 12. What changes with this layer

With hosted runtime APIs, it becomes clear what a developer gains and what they hand over. The following is my interpretation, based on these runs and the documentation.

**What you gain.** You no longer need a machine to run the agent; the session continues on the provider's side while your laptop sleeps. You no longer build the isolated execution environment, the path for moving files in and out, or the state storage that lets a task resume. Webhooks and scheduled runs sit in the same API, which makes it easier to open a session on an external event or at a set time. On the Claude side, you also get a server-enforced session budget.

**What you hand over.** First, local context: the sandbox is not your filesystem, and your machine's settings, sign-ins, and VPN do not carry over. Second, control over measurement: the provider decides the factors that drive cost, such as the harness's fixed input, hidden internal calls, rounding rules, and best-effort usage. Third, portability: agents, environments, and sessions are provider-specific resources, and Claude agents cannot even be deleted. Fourth, data location: session history and sandbox state remain on the provider's servers. Anthropic's documentation states that Managed Agents is not eligible for ZDR or a HIPAA BAA.

The convergence of the two providers on the same abstractions eases the portability problem somewhat. Because agents, environments, sessions, and events form the same skeleton, most of what changes when you move operational code from one provider to the other is names and paths. Behaviors that actually differed in these runs, however, such as how completion is detected, how reliable usage is, and how long artifacts live, need to be checked again with every move.

## 13. Which one to choose

These criteria are also my interpretation, not a settled recommendation.

- **If you work directly on files and repositories on your machine**, use `claude -p`, the Claude Agent SDK, or Codex's local runs. A hosted sandbox is not your filesystem. Self-hosting can reach local resources, but the operating responsibility moves to you.
- **If you want fine control over the loop, approvals, and state storage inside your application**, use the Claude Agent SDK or the OpenAI Agents SDK.
- **If a person hands off coding tasks from the web or mobile and picks them up later**, use Claude Code cloud or Codex Cloud. They use the repository's settings and run within your subscription or plan.
- **If a program opens sessions that run for a long time without your machine and returns results as files**, use Managed Agents or the OpenAI Agents API. They also fit sessions opened by external events, but you still build the receiver for those events.
- **If the server must enforce a budget**, the only documented option among the products covered here is the Managed Agents session budget.
- **If the work is interactive code editing**, a hosted runtime API does not fit. A local harness or a cloud coding product works better.

Whichever you choose, the judgment that most often goes wrong on a hosted runtime is cost. The harness's fixed input, the internal calls that come with web search, and container and session-time fees all fall outside a simple token calculation. After each run, look at the usage object and the per-model totals together, and check first that they reconcile.

## References

- [Claude Managed Agents overview, Claude Platform Docs](https://platform.claude.com/docs/en/managed-agents/overview)
- [Managed Agents quickstart, Claude Platform Docs](https://platform.claude.com/docs/en/managed-agents/quickstart)
- [Managed Agents files, Claude Platform Docs](https://platform.claude.com/docs/en/managed-agents/files)
- [Prompt caching, Claude Platform Docs](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)
- [Agent SDK reference (Python), Claude Code Docs](https://code.claude.com/docs/en/agent-sdk/python)
- [Use Claude Code in the cloud, Claude Code Docs](https://code.claude.com/docs/en/claude-code-on-the-web)
- [Agents, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents)
- [Agents API architecture, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents-api/architecture)
- [Configuring Agents, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents-api/configuration)
- [Run and continue sessions, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents-api/sessions)
- [OpenAI-hosted sandboxes, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents-api/environments/openai-hosted)
- [Sandbox lifecycle, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents-api/environments/lifecycle)
- [Files and artifacts, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents-api/environments/files)
- [Model usage and cost, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents-api/observability)
- [Agents SDK overview, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents/sdk)
- [Running agents, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents/running-agents)
- [Sandbox agents, OpenAI API Docs](https://developers.openai.com/api/docs/guides/agents/sandboxes)
- [Pricing, OpenAI API Docs](https://developers.openai.com/api/docs/pricing)
- [Codex Cloud, OpenAI Docs](https://learn.chatgpt.com/docs/cloud)
- [Cloud environments, OpenAI Docs](https://learn.chatgpt.com/docs/environments/cloud-environments)
- [Codex environments, OpenAI Docs](https://learn.chatgpt.com/docs/environments/modes)
- [Codex on mobile, OpenAI Docs](https://learn.chatgpt.com/docs/mobile)
