All guides
OpenAI

Self-hosted sandboxes

Checked 09/15/2026View original
On this page

For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.

Connect your own environment when you want more control over the agent's environment or want to use compute you trust. The environment can be a laptop, a container, or a remote sandbox. To have OpenAI provision the environment, use an OpenAI-hosted sandbox.

How the connection works

OpenAI runs the agent harness. You run codex exec-server, the executor, inside your environment. It runs shell commands, reads and writes files, and uses local MCP servers at the harness's request.

The executor registers with the API using an environment ID and a restricted API key. It then connects over WebSocket to receive commands and return results. All connections are outbound. The executor reconnects if the connection drops.

Prepare your environment

Prepare the files and dependencies your agent needs. Isolate environments by user or workload. Agents that share an environment can access the same files, credentials, and other resources.

Create the working directory and install the Codex CLI inside the environment. This example uses /workspace:

mkdir -p /workspace
npm install -g @openai/codex@alpha

Network access

Allow outbound connections to these hosts:

  • https://api.openai.com for environment registration.
  • wss://codex-cloud-environments.chatgpt.com for commands and results.

Authentication

Use OPENAI_API_KEY for application requests. Grant it api.agents.read and api.agents.write for session operations, plus api.responses.write for model inference. Add api.vaults.read and api.vaults.write if your application manages vaults.

Create a separate environment key on the Agents tab in the platform dashboard. It must belong to the same organization, project, and user or service account that owns the session. Set every other permission to None.

Set OPENAI_EXECUTOR_API_KEY to this environment key in your application or provisioning service. Pass its value into the sandbox as CODEX_API_KEY, which codex exec-server reads. Keep your application's OPENAI_API_KEY outside the sandbox.

Agent-generated code can read the environment key, but the key only permits connecting environments. It cannot authorize any other API action. Keep it out of source code, container images, and logs. Rotate or revoke it when needed.

Create a session

Run this example in your application, outside the environment. If you already have a self-hosted session, reuse it.

Create a session with your own environment

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);
from openai import OpenAI

client = OpenAI()

session = 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"},
)
print(session.to_json())
import (
	"context"
	"fmt"

	"github.com/openai/openai-go/v3"
)

ctx := context.Background()
client := openai.NewClient()
result, err := client.Beta.Agents.Sessions.New(ctx,
	openai.BetaAgentSessionNewParams{
		Agent: openai.BetaAgentSessionNewParamsAgent{
			Model:        openai.String("gpt-6-astra"),
			Instructions: openai.String("You are a helpful coding assistant. Write clean code and verify that it works."),
		},
		Environment: openai.EnvironmentParamUnion{
			OfParamSelfHosted: &openai.EnvironmentParamSelfHosted{WorkspaceDirectory: "/workspace"},
		},
	})
if err != nil {
	panic(err)
}
fmt.Println(result)
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.beta.agents.EnvironmentParam;
import com.openai.models.beta.agents.sessions.SessionCreateParams;

OpenAIClient client = OpenAIOkHttpClient.fromEnv();
var result =
    client
        .beta()
        .agents()
        .sessions()
        .create(
            SessionCreateParams.builder()
                .agent(
                    SessionCreateParams.Agent.builder()
                        .model("gpt-6-astra")
                        .instructions(
                            "You are a helpful coding assistant. Write clean code and verify"
                                + " that it works.")
                        .build())
                .environment(
                    EnvironmentParam.SelfHosted.builder()
                        .workspaceDirectory("/workspace")
                        .build())
                .build());
System.out.println(result);
require "openai"

client = OpenAI::Client.new
result = 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"
  }
)
puts result

Store session.id with your application's conversation state. Pass session.environment.id and session.environment.remote_url to the executor. Use the remote URL unchanged, including when reconnecting. See Configuring Agents to use a stored agent.

You can reuse your environment image, workspace_directory, and capability_directories across sessions. Each session has its own environment ID and needs its own executor. API environment templates apply only to OpenAI-hosted environments.

Start the executor

Open the session event stream from your application to receive connection events. Then run this command inside the environment with the environment key configured as CODEX_API_KEY above. Replace the placeholders with the environment values returned by the API:

codex exec-server \
  --remote "<session.environment.remote_url>" \
  --environment-id "<session.environment.id>"

Leave the executor running while the agent works.

Send work and monitor the connection

Send input from your application while the event stream stays open. The agent needs both a connected environment and user input to start work.

The stream reports these connection states:

  • agent.session.environment.pending: The session is waiting for the executor to connect.
  • agent.session.environment.connected: The environment is ready.
  • agent.session.environment.failed: The connection failed. Check the environment error and executor logs.

Continue following the stream for the turn's outcome and output. See Environment lifecycle to manage startup, reconnection, and shutdown from your application or through webhooks.

Sandbox providers

Choose a sandbox provider to run code and work with files. See Sandbox lifecycle to compare application-managed and webhook-managed provisioning.

ProviderGuide
ModalModal setup
CloudflareCloudflare setup
VercelVercel setup
DaytonaDaytona setup
BlaxelBlaxel setup
E2BE2B setup
RunloopRunloop setup
DigitalOceanDigitalOcean setup
Oracle Cloud Infrastructure (OCI)OCI setup

For webhook-managed provisioning, implement a handler using Sandbox lifecycle and your provider's SDK or API. Keep provisioning ownership and cleanup policies explicit.