is probably one of the most useful capabilities we can give to an LLM agent.
Once the agent can write and execute code, many tasks become possible. For example, the agent can inspect files or datasets, write data processing logic, or produce artifacts for downstream consumption.
That opens the door to a much wider range of agentic applications.
In this post, let’s build a coding agent with the OpenAI Agents SDK and Docker. We’ll first build the mental model, then walk through a small case study where we ask the agent to analyze a CSV file, and return a report with charts.
In the end, we’ll also summarize the practical details that make this pattern reusable.
1. How Code-Executing Agents Work
There are three important components of a code-executing agent: the model, the workspace, and the execution environment. Let’s unpack them one by one.
1.1 The Model
A code-executing agent is, after all, an LLM agent. Naturally, it needs an LLM to power the agent.
In this specific scenario, the common tasks of the LLM would be to inspect the available files, decide what type of analysis is needed, write the actual code, read the results, and continue with further iterations.
1.2 Workspace
This is the space where the agent works, and it’s where the input files go in and the output files come out. The user may upload the data files (such as CSV, PDF, a folder of documents, etc) into the workspace, the agent can work on them, and save the artifacts back to it.
1.3 Execution Environment
The LLM agent only writes the code and doesn’t execute it. So we need an execution environment where the generated code can actually run.
There are multiple available options. For example, this code-execution environment can be a hosted one managed by the platform, or it can be a sandbox we control ourselves locally. If we control it ourselves, Docker is usually the default way to package the runtime and isolate the run.
1.4 Cross-Cutting Concern: Control
Then, there is one practical design question: control.
At the model layer, we need to decide how to build the agent system instruction and what artifacts the agent should produce.
At the workspace layer, we need to think about what files are staged into it and what final output artifacts should be brought back after the run.
At the execution environment layer, we need to determine what dependencies should be made available and whether network or shell access is allowed.
1.5 OpenAI Agents SDK
In the OpenAI Agents SDK, a SandboxAgent exactly implements the pattern we discussed above.
To configure the code-executing agent with the Agents SDK, we first need to describe the workspace with a Manifest, which basically specifies which local files should be staged into the workspace. A simple example is shown below:
```
pip install "openai-agents[docker]"
from pathlib import Path
from agents.sandbox import LocalFile, Manifest
manifest = Manifest(
entries={
"input/data.csv": LocalFile(src=Path("data/data.csv")),
},
)
```
This says: take a local file and make it available inside the workspace as input/data.csv.
Then, we specify the agent’s model, instructions, and the workspace manifest:
```
from agents.sandbox import SandboxAgent
agent = SandboxAgent(
name="coding agent",
instructions="Inspect the input files, write and run code when useful, and save requested artifacts.",
model="gpt-5.4",
default_manifest=manifest,
)
```
Next, we should create the execution sandbox. If we use Docker:
```
pip install "openai-agents[docker]"
import docker
from agents.sandbox.sandboxes.docker import DockerSandboxClient
from agents.sandbox.sandboxes.docker import DockerSandboxClientOptions
docker_client = DockerSandboxClient(docker.from_env())
sandbox_options = DockerSandboxClientOptions(image="my-agent-sandbox:latest")
sandbox_session = await docker_client.create(
manifest=manifest,
options=sandbox_options,
)
await sandbox_session.apply_manifest()
```
Here, the image argument of DockerSandboxClientOptions specifies the Docker image used by the sandbox. That is where we can customize the image, for example, by pre-installing the dependencies so that the agent can directly use them during the run without installing on the fly.
Finally, we connect the agent and the sandbox session at runtime:
```
from agents import Runner, RunConfig
from agents.sandbox import SandboxRunConfig
result = await Runner.run(
agent,
"Analyze input/data.csv and save a short report under output/report.md.",
run_config=RunConfig(
sandbox=SandboxRunConfig(session=sandbox_session),
),
)
```
After the run, the sandbox workspace can also be persisted as a tar archive:
workspace_archive = await sandbox_session.persist_workspace()
await sandbox_session.aclose()
We can then extract the output files we care about (e.g., reports, charts, tables, etc) and copy them back to the host machine.
Of course, there are other ways to enable code execution in the Agents SDK besides the above-mentioned
SandboxAgent. For example, you can attachCodeInterpreterToolto a regular agent, which allows the agent to run code in an OpenAI-managed environment. This comes in handy if you don’t want to manage Docker images and local runtimes yourself.If the workflow is more command-line oriented, the SDK also provides shell execution through
ShellTool. WithSandboxAgent, shell is included by default as part of its sandbox capabilities.
2. Case Study: An Agent That Analyzes a CSV
In this case study, we’ll build an agent that can write code and perform data analysis.
2.1 The Case Study Setup
Here, we consider a time series anomaly detection task. Specifically, we’ll task the agent to look into an hourly building energy dataset and to identify unusual energy use events.
I created a synthetic dataset in plain CSV:
data/building_energy.csv
with three columns:
timestamp, energy_kwh, outdoor_temp_c
The time series data is visualized below:
Figure 1. Hourly building energy consumption and outdoor temperature used as the input data for the agent. (Image by author)
To complete the task, the agent needs to inspect the CSV, build a normal baseline behavior, and compare the observations against the expected patterns.
We ask the agent to save three output files:
output/anomalies.csv
output/energy_anomalies.png
output/anomaly_report.md
2.2 Prepare the Docker Runtime
Before configuring the agent, we first need to prepare its code execution environment. Here, we use a Docker container.
This container will serve as the agent’s temporary machine, with a working directory, a Python runtime, and a set of libraries that the agent can use to perform data analysis. Note that the agent will only run code inside that container, our host machine stays outside the run.
To define that environment, we create a Dockerfile:
```
FROM python:3.12-slim
ENV MPLBACKEND=Agg
RUN pip install --no-cache-dir numpy scipy pandas matplotlib
WORKDIR /workspace
```
Note that we give the agent numpy, scipy, pandas, and matplotlib. Those libraries should be enough for the current task. We also set MPLBACKEND=Agg, which lets matplotlib save figures without needing a display. This is especially useful here because the code runs inside a non-interactive container.
Next, we can build the image:
```
import subprocess
IMAGE_NAME = "energy-agent-sandbox:latest"
subprocess.run(["docker", "build", "-t", IMAGE_NAME, "."], check=True)
```
Later, when we create the sandbox session, we can pass this image name into DockerSandboxClientOptions. That’s how the sandbox knows which execution environment to use.
For this case study, you need to make sure that Docker is installed and running on your machine. The reason is simple: later, our Python code will ask Docker to create the sandbox session, so the Python process needs to be able to talk to the Docker daemon.
On Windows or macOS, you can install Docker Desktop. On Linux, install Docker Engine directly from Docker’s official package repository.
You can check if Docker is properly set up by running:
docker –version
docker run hello-world
2.3 Define and Run the Agent
Now we define the actual agent. We start with the manifest, which tells the sandbox which local file should be available inside the workspace:
```
from pathlib import Path
from agents.sandbox import LocalFile, Manifest
manifest = Manifest(
entries={
"input/building_energy.csv": LocalFile(src=Path("data/building_energy.csv")),
},
)
```
In the code snippet above, we stage the local CSV file into the sandbox workspace as:
input/building_energy.csv
Next, we define the agent instruction for defining its role, expected outcome, as well as the libraries at its disposal:
```
Note: This instruction is iterated with AI
INSTRUCTIONS = """
You are a practical data analyst.
Use the sandbox workspace to inspect files, write and run code when useful,
and save clear artifacts.
Keep conclusions grounded in computed evidence.
The sandbox has Python with numpy, scipy, pandas, and matplotlib available.
""".strip()
```
Finally, we create the SandboxAgent:
```
from agents.sandbox import SandboxAgent
agent = SandboxAgent(
name="Energy anomaly analyst",
instructions=INSTRUCTIONS,
model="gpt-5.4",
default_manifest=manifest,
)
```
To run the agent, we used the following prompt:
```
PROMPT = """
I have an hourly energy-consumption export for one building at input/building_energy.csv.
The columns are timestamp, energy_kwh, and outdoor_temp_c. outdoor_temp_c is in degrees Celsius.
Please investigate the file and look for energy-use abnormal events.
Ignore tiny fluctuations that look like normal operating noise.
Use code in the sandbox to do the analysis, then save these files:
- output/anomalies.csv
- output/energy_anomalies.png
- output/anomaly_report.md
In the report, explain your method briefly,
and give plausible explanations based only on the timestamps, energy values, and outdoor temperature.
Use plain ASCII text such as deg C instead of the degree symbol.
""".strip()
```
Note that in the prompt above, we explicitly specified the files we expect back. Next, we create a Docker sandbox session from the image we built earlier:
```
import docker
from agents.sandbox.sandboxes.docker import DockerSandboxClient
from agents.sandbox.sandboxes.docker import DockerSandboxClientOptions
docker_client = DockerSandboxClient(docker.from_env())
sandbox_options = DockerSandboxClientOptions(image=IMAGE_NAME)
sandbox_session = await docker_client.create(
manifest=manifest,
options=sandbox_options,
)
await sandbox_session.apply_manifest()
```
Then, we can run the agent:
```
from agents import Runner, RunConfig
from agents.sandbox import SandboxRunConfig
result = await Runner.run(
agent,
PROMPT,
max_turns=25,
run_config=RunConfig(
sandbox=SandboxRunConfig(session=sandbox_session),
),
)
```
2.4 Inspect the Results
After the run, the agent created the three files we requested.
To bring them back to our local project folder, we need to persist the sandbox workspace and extract the expected files:
```
from pathlib import Path
workspace_archive = await sandbox_session.persist_workspace()
OUTPUTS_DIR = Path("outputs")
shutil.rmtree(OUTPUTS_DIR, ignore_errors=True)
OUTPUTS_DIR.mkdir(parents=True, exist_ok=True)
with tarfile.open(fileobj=workspace_archive, mode="r:*") as tar:
for filename in ["anomalies.csv", "energy_anomalies.png", "anomaly_report.md"]:
source = tar.extractfile(f"output/{filename}")
(OUTPUTS_DIR / filename).write_bytes(source.read())
await sandbox_session.aclose()
```
Now we can see that the following files exist in the local outputs/ folder:
anomalies.csv
energy_anomalies.png
anomaly_report.md
The agent found one clear abnormal event, as shown in the energy_anomalies.png:
Figure 2. The agent correctly identified the abnormal event. (Image by author)
We can further inspect how the agent reached this conclusion:
for item in result.new_items:
print(type(item).__name__, item)
In my run, I can roughly see that the agent first inspected the workspace and loaded the CSV with pandas. It then checked the row count, column names, data types, and missing values.
After that, it wrote and ran an anomaly detection script with numpy and pandas. The script first built an expected hourly baseline, followed by computing residuals and robust z-scores.
Finally, the agent generated the requested plot, saved the CSV, and output a markdown report. It even validated the outputs to wrap up the work.
We now have a working code-executing agent.
3. Practical Things To Keep In Mind
As we’ve seen in the previous case study, there are a few details we need to consider when building the code-executing agent:
- Start with the agent’s instruction, be explicit about its role, its task, and its expected outcome;
- Decide what files should enter the workspace. This is the set of files the agent will work on;
- Decide what runtime the agent can use, including the necessary libraries;
- State explicitly about the output file names and locations. This makes the later extraction and copy-paste easy.
Once those pieces are clear, you can reuse the same pattern for many other agentic workflows.
So, what would you build next with this capability?