Build a Coding Agent Using Codex SDK and Daytona
This guide demonstrates how to run an autonomous coding agent based on OpenAI Codex inside a Daytona sandbox environment. The agent can develop full-stack web apps, write code in any language, install dependencies, and run scripts. It can also start and manage dev servers, and generate preview links for live apps.
1. Workflow Overview
When you launch the main module, a Daytona sandbox is created and a Node.js agent is initialized inside it. The agent is based on the Codex SDK.
You interact with the main program via a command line chat interface. The program sends your prompts to the agent inside the sandbox, which executes them and returns the results:
$ npm run startCreating sandbox...Installing Codex agent in sandbox...Press Ctrl+C at any time to exit.User: create a 3d animated web-based, lunar lander gameThinking...π¨ β Run: /bin/sh -lc lsπ¨ β Run: /bin/sh -lc 'ls -a'π¨ β Run: /bin/sh -lc 'ls .daytona'π¨ β Run: /bin/sh -lc 'find /home/daytona -maxdepth 4 -name .git'π Add /home/daytona/index.htmlπ Add /home/daytona/style.cssπ Add /home/daytona/main.jsπ Update /home/daytona/main.js- Built a self-contained 3D lunar lander experience with HUD in index.html wired to main.js.- Styled a glassy mission card, typography, and neon accents in style.css.- Implemented the Three.js scene in main.js: starfield + noisy terrain with a flattened pad, modeled lander, thrust/fuel/rotation controls, gravity/drag physics, landing/crash checks, exhaust particles, and a chase camera. Controls: Space/β thrust, β/β yaw, W/S pitch, R restart.
Next steps:1) Serve locally (e.g., cd /home/daytona && python3 -m http.server 8080) and open https://8080-e7c5deb5-7723-4bb8-93c6-25258d9b7c53.proxy.daytona.works.2) Tune physics constants or terrain size if you want a harder/easier landing.ποΈ To-do list:- [x] Inspect workspace and set up project structure for web-based lunar lander game- [x] Implement 3D scene, lunar lander controls, physics, and game loop- [x] Add UI elements, polish, and quick sanity check (open file if feasible)Usage Summary: Cached: 71936, Input: 103238, Output: 11311User: start the serverThinking...π¨ β Run: /bin/sh -lc 'cd /home/daytona && nohup python3 -m http.server 8080 --bind 0.0.0.0 >/home/daytona/server.log 2>&1 & echo $!'Server started on port 8080 (pid 274). Open the game at:https://8080-e7c5deb5-7723-4bb8-93c6-25258d9b7c53.proxy.daytona.works
If you need to stop it later: kill 274.Usage Summary: Cached: 4096, Input: 22231, Output: 272User:Cleaning up...The agent can also host web apps and provide you with a preview link using the Daytona Preview Links feature. When your task involves running or previewing a web application, the agent automatically reasons about this need, hosts the app, and generates a preview link for you to inspect the live result:
You can continue interacting with your agent until you are finished. When you exit the program, the sandbox will be deleted automatically.
2. Project Setup
Clone the Repository
First, clone the daytona repository and navigate to the example directory:
git clone https://github.com/daytonaio/daytona.gitcd daytona/guides/typescript/openai/codex-sdkConfigure Environment
Get your API keys:
- Daytona API key: Daytona Dashboard
- OpenAI API key: OpenAI Developer Platform
Copy .env.example to .env and add your keys:
DAYTONA_API_KEY=your_daytona_keySANDBOX_OPENAI_API_KEY=your_openai_keyLocal Usage
Install dependencies:
npm installRun the agent:
npm run startThe agent will start and wait for your prompt.
3. Understanding the Agentβs Architecture
This example consists of two main components:
- Main Program: The main program is a Node.js script (
src/index.ts) that runs on your local machine. It uses the Daytona SDK to create and manage a Daytona sandbox. The main program provides a command line interface for interacting with the agent inside the sandbox. - Sandbox Agent: The sandbox agent is a Node.js script (
agent/index.ts) that runs inside the Daytona sandbox. It uses the Codex SDK to create a customized coding agent.
Initialization
On initialization, the main program:
- Creates a new Daytona sandbox with your OpenAI API key included in the environment variables.
- Configures the Codex system prompt with Daytona-specific instructions and writes it to a
.codex/config.tomlfile in the sandbox. - Uploads the agent package to the sandbox with file uploading.
- Installs the agent dependencies by running
npm installin the uploaded agent directory. - Waits for user input and runs the agent asynchronously for each prompt.
Main Program Code
Custom system prompts for Codex must be configured via a .codex/config.toml file, so the main program creates this file in the sandbox before starting the agent:
const systemPrompt = [ 'You are running in a Daytona sandbox.', 'Use the /home/daytona directory instead of /workspace for file operations.', `When running services on localhost, they will be accessible as: ${previewUrlPattern}`,].join(' ')const config = `developer_instructions = "${systemPrompt}"`await sandbox.fs.createFolder('.codex', '755')await sandbox.fs.uploadFile(Buffer.from(config, 'utf8'), '.codex/config.toml')This prompt instructs the agent to use the correct file paths and preview link format for Daytona sandboxes.
After installing dependencies, the main program enters a loop to read user input and send it to the agent. For each user prompt it receives, it creates a new Daytona process session to run the agent command asynchronously and stream back the output:
// Create a session to stream the agent outputconst sessionId = `codex-session-${Date.now()}`await sandbox.process.createSession(sessionId)
// Run the agent asynchronously, passing the prompt and OpenAI API keyconst command = await sandbox.process.executeSessionCommand(sessionId, { command: `${environmentPrefix({ PROMPT: prompt })} npm exec --prefix /tmp/agent tsx -- /tmp/agent/index.ts`, runAsync: true,})
// Stream agent output as it arrivesif (!command.cmdId) throw new Error('Failed to start agent command in sandbox')await sandbox.process.getSessionCommandLogs( sessionId, command.cmdId, onStdout, onStderr,)
// Delete the sessionawait sandbox.process.deleteSession(sessionId)The onStdout and onStderr callbacks are used to pass the agentβs output back to the main program. After the agent finishes responding to the prompt, the main program waits for the next user input.
Sandbox Agent Code
The sandbox agent uses the Codex SDK to create a customized coding agent. The agent is initialized with custom options that include the workspace directory:
// Configure Codex optionsconst options: ThreadOptions = { workingDirectory: '/home/daytona', skipGitRepoCheck: true, sandboxMode: 'danger-full-access',}The agent maintains thread state between requests by writing the thread ID to a file, allowing it to maintain context across multiple interactions:
const threadIdPath = '/tmp/codex-thread-id'const threadId = (await readFileIfExisting(threadIdPath))?.trim()const thread: Thread = threadId ? codex.resumeThread(threadId, options) : codex.startThread(options)Additional code to stream agent responses follows the examples in OpenAIβs Codex SDK documentation.
Clean up
When you exit the main program, the Daytona sandbox and all files are automatically deleted.
Key advantages:
- Secure, isolated execution in Daytona sandboxes
- Communicate with the agent directly in your terminal
- Automatic dev server detection and live preview links
- Multi-language and full-stack support
- Thread persistence across multiple requests
- Simple setup and automatic cleanup