コンテンツにスキップ

Build a Coding Agent Using Codex SDK and Daytona

View as Markdown

このコンテンツはまだ日本語訳がありません。

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 start
Creating sandbox...
Installing Codex agent in sandbox...
Press Ctrl+C at any time to exit.
User: create a 3d animated web-based, lunar lander game
Thinking...
🔨 ✓ 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: 11311
User: start the server
Thinking...
🔨 ✓ 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: 272
User:
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:

Lunar lander game demo generated by Codex coding agent

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:

Terminal window
git clone https://github.com/daytonaio/daytona.git
cd daytona/guides/typescript/openai/codex-sdk

Configure Environment

Get your API keys:

Copy .env.example to .env and add your keys:

Terminal window
DAYTONA_API_KEY=your_daytona_key
SANDBOX_OPENAI_API_KEY=your_openai_key

Local Usage

Install dependencies:

Terminal window
npm install

Run the agent:

Terminal window
npm run start

The 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:

  1. Creates a new Daytona sandbox with your OpenAI API key included in the environment variables.
  2. Configures the Codex system prompt with Daytona-specific instructions and writes it to a .codex/config.toml file in the sandbox.
  3. Uploads the agent package to the sandbox with file uploading.
  4. Installs the agent dependencies by running npm install in the uploaded agent directory.
  5. 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 output
const sessionId = `codex-session-${Date.now()}`
await sandbox.process.createSession(sessionId)
// Run the agent asynchronously, passing the prompt and OpenAI API key
const 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 arrives
if (!command.cmdId) throw new Error('Failed to start agent command in sandbox')
await sandbox.process.getSessionCommandLogs(
sessionId,
command.cmdId,
onStdout,
onStderr,
)
// Delete the session
await 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 options
const 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