Run commands and work with files in a DigitalOcean sandbox while OpenAI runs the agent and maintains session state.
How it works
DigitalOcean’s Managed Agents Runtime Services (M.A.R.S.) starts a Firecracker microVM using the codex-agentapi image. The image includes Codex and starts the executor, which connects outbound to the Agents API.
Choose webhook-managed provisioning to start or resume sandboxes from OpenAI events, or application-managed provisioning to control them from your application. For an interactive quickstart, use the optional DigitalOcean CLI flow. See Sandbox lifecycle for connection and recovery behavior.
M.A.R.S. is in invite-only private preview. Request access through DigitalOcean’s private-preview announcement.
Before you begin
You need a sandbox-enabled DigitalOcean account with access to codex-agentapi and an OpenAI project with Agents API access.
Set OPENAI_API_KEY for your application or CLI and a separate restricted OPENAI_EXECUTOR_API_KEY for the sandbox. The keys must have the same owner, organization, and project. Store only the executor key in the sandbox’s CODEX_API_KEY secret. See executor authentication.
For webhook controllers or Python applications, set DIGITALOCEAN_TOKEN and install the PyDo beta SDK with async support (pydo[aio]). Use the OpenAI SDK for Agents API requests. CLI installation is needed only for the CLI flow.
Webhook-managed
- Create a stored agent and save its ID as
OPENAI_AGENT_ID. Deploy an HTTPS webhook controller in DigitalOcean App Platform with this ID,OPENAI_API_KEYfor session reads,DIGITALOCEAN_TOKEN, andOPENAI_EXECUTOR_API_KEY. - Register its
/webhookendpoint with your OpenAI project. Enableagent.session.action_requiredandagent.session.failed, then store the signing secret asOPENAI_WEBHOOK_SECRETand redeploy the controller. - Follow the session steps with the same
OPENAI_AGENT_IDand/workspaceas the working directory. Open the event stream and send input. When OpenAI requests anenvironment_connection, the controller verifies the signature, retrieves the current session, and checks its agent ID and required actions. It looks upmars-{session_id}in DigitalOcean and resumes a paused sandbox or creates one if none is active. - On
agent.session.failed, retrieve the session again and delete its sandbox only if the current session status is stillfailed.
The image connects the executor to the session’s environment. Your application sends input and streams results through the Agents API; the controller handles provisioning and reconnection. Serialize provisioning per session to handle duplicate and concurrent deliveries. See webhook-managed lifecycle guidance for controller requirements.
Try it with the DigitalOcean CLI
The CLI creates both resources and lets you interact with the agent from your terminal. It provisions the sandbox directly, without a webhook controller.
Install the doctl beta release that includes harness-runtime, then authenticate:
doctl auth init
Save this manifest as agents.yaml:
name: openai-codex-session
agent: codex-agentapi
config:
agent:
model: gpt-5.6-sol
instructions: Work from the files in /workspace.
environment:
type: self_hosted
workspace_directory: /workspace
egress:
- api.openai.com
- codex-cloud-environments.chatgpt.com
env:
CODEX_ENVIRONMENT_ID: ${ENV_ID}
secrets:
CODEX_API_KEY: ${OPENAI_EXECUTOR_API_KEY}
The config block is the OpenAI create-session request. The CLI authenticates that request with OPENAI_API_KEY, fills ${ENV_ID} from the response, and passes only the restricted executor key to the sandbox. Keep resolved manifests out of logs and source control. Add any destinations your tools need to egress.
Create the session and sandbox:
doctl harness-runtime create --spec agents.yaml
The command waits up to 300 seconds for readiness by default. Save the OpenAI session ID and DigitalOcean session ID from the session details, then attach:
doctl harness-runtime launch openai-codex-session
Ask the agent to write hello to /workspace/hello.txt and read it back. Press Ctrl+D to detach without deleting the session, and run the same launch command to reattach. Follow Cleanup when finished.
Application-managed
Use this path when your application owns session creation and sandbox provisioning. Create the OpenAI session first:
import OpenAI from "openai";
const client = new OpenAI();
const session = await client.beta.agents.sessions.create({
agent: {
model: "gpt-6-astra",
instructions:
"You are a helpful coding assistant. Write clean code and verify that it works.",
},
environment: {
type: "self_hosted",
workspace_directory: "/workspace",
},
});
console.log(session);Save session.id and the environment ID as described in Connect a sandbox. Save this sandbox-only manifest as sandbox.yaml; the agent configuration was already sent to OpenAI:
agent: codex-agentapi
egress:
- api.openai.com
- codex-cloud-environments.chatgpt.com
env:
CODEX_ENVIRONMENT_ID: ${ENV_ID}
secrets:
CODEX_API_KEY: ${OPENAI_EXECUTOR_API_KEY}
- Create a
pydo.aio.ClientusingDIGITALOCEAN_TOKENand callclient.agents.create_session. Setparams.openai_session_idto the OpenAI session ID,body.manifestto the contents ofsandbox.yaml, andbody.variablesto a mapping ofENV_IDandOPENAI_EXECUTOR_API_KEYto their values. Save the returned DigitalOceansession_id. - Open the event stream and send input, asking the agent to write and read
/workspace/hello.txt. Input waits for the executor to connect. Confirm the connection event and a completed turn, and inspect the agent’s output for tool failures. - Retrieve the file with
workspace_download, using the relative pathhello.txt. Keep both resources for follow-up turns, or clean up.
Use bounded setup and execution timeouts and handle connection failures in your application. Do not attach a provisioning webhook handler to sessions your application or CLI manages directly.
Cleanup
Save any files you need, then delete the OpenAI session and destroy the DigitalOcean sandbox. Session deletion does not emit a webhook, so perform both operations and report cleanup failures.
With PyDo, call client.agents.destroy_session with the DigitalOcean session ID. With the CLI, pass that ID or the sandbox’s name:
doctl harness-runtime remove openai-codex-session
Remove the OpenAI webhook registration before deleting a webhook controller.