Code Interpreter

Working with files

Uploading inputs, reading them from code, collecting outputs, and the full lifecycle in between.

Files move through the service in a loop: you upload them, the sandbox stages them into its workspace, code reads and writes, and anything left behind comes back as a downloadable artifact.

The lifecycle

Uploading

curl -sX POST http://localhost:3112/v1/upload \
  -F 'file=@data.csv' \
  -F 'kind=user' | jq
Response
{
  "message": "success",
  "storage_session_id": "7fZq2NkP0aRcVbXsLmTdY",
  "files": [
    {
      "id": "V1StGXR8Z5jdHi6BmyT",
      "name": "data.csv",
      "storage_session_id": "7fZq2NkP0aRcVbXsLmTdY",
      "size": 20481,
      "contentType": "text/csv"
    }
  ]
}

Keep both the storage_session_id and each file's id: you need both to reference the file later.

The service chooses the storage session

You never pick a storage session or namespace. The service mints one and derives its namespace from your authenticated identity, which is what stops one caller from addressing another's files.

Form fields

FieldRequiredPurpose
fileYesOne or more file parts. Repeat for multiple.
kindYesuser, agent, or skill: see file kinds.
idFor shared kindsResource id owning the storage session.
versionFor skillRequired when kind=skill, rejected otherwise.
read_onlyNotrue marks these as infrastructure inputs that must never be emitted back as outputs, even if code modifies them on disk.

Subdirectory components in filenames are preserved, so pptx/editing.md arrives as a nested path rather than being flattened to a basename.

Limits

LimitDefaultVariable
Per-file size25 MiBMAX_FILE_SIZE
Uploads per window30 per 5 minUPLOAD_MAX_REQUESTS

Exceeding the size limit returns 413; the rate limit returns 429 with a Retry-After header.

Batch uploads

POST /v1/upload/batch has the same contract, tuned for writing many files into a single storage session in one request: the shape skill bundles use.

Using files in a run

Reference them in the files array of your exec request:

curl -sX POST http://localhost:3112/v1/exec \
  -H 'Content-Type: application/json' \
  -d '{
    "lang": "py",
    "code": "import pandas as pd\nprint(pd.read_csv(\"data.csv\").describe())",
    "files": [{
      "id": "V1StGXR8Z5jdHi6BmyT",
      "resource_id": "user-42",
      "storage_session_id": "7fZq2NkP0aRcVbXsLmTdY",
      "name": "data.csv",
      "kind": "user"
    }]
  }' | jq

Each entry needs:

FieldMeaning
idThe storage file id from the upload response.
storage_session_idThe storage session from the upload response.
nameThe filename to write inside /mnt/data. Need not match the original.
kindThe resource kind.
resource_idThe entity owning the storage session; informational for user.
versionRequired when kind is skill.

The file is staged into /mnt/data under name, which is the working directory, so code opens it by bare filename.

Two different session ids

storage_session_id is where the file's bytes live. It is not the session_id of the execution you are starting. Mixing them up is the most common file-handling error: see core concepts.

Collecting outputs

Anything the run leaves in /mnt/data comes back in the response's files:

{
  "session_id": "Kd8vN2mPxQ7wLzR4bYtCa",
  "stdout": "",
  "files": [
    { "id": "8ZqL2mVxRt0PnCbWyKdSa", "name": "chart.png", "storage_session_id": "Kd8vN2mPxQ7wLzR4bYtCa", "kind": "user" }
  ]
}

For output files the storage_session_id equals the run's session_id: a run writes its outputs under its own execution session.

The inherited flag

Some refs carry inherited: true. That means the ref is an unchanged passthrough of an input you already own, not something the run created.

Skip post-processing those. Re-downloading a skill- or agent-scoped input with the end user's session key will 403, and it is wasted work regardless: the bytes are already persisted where they came from.

The modified_from field

When a run modified a staged input rather than creating a new file, the output ref carries modified_from pointing at the original { id, storage_session_id }.

Downloading

curl -s http://localhost:3112/v1/download/{session_id}/{fileId} -o chart.png

Rate limited to 60 downloads per minute by default.

Listing and deleting

# List a session's files
curl -s http://localhost:3112/v1/files/{session_id} | jq

# With full metadata
curl -s 'http://localhost:3112/v1/files/{session_id}?detail=full' | jq

# One file's metadata, no bytes
curl -s http://localhost:3112/v1/sessions/{session_id}/objects/{fileId} | jq

# Delete
curl -sX DELETE http://localhost:3112/v1/files/{session_id}/{fileId}

The metadata route exists for freshness checks: read lastModified to decide whether a previously uploaded bundle is still present before re-uploading it. Without it, every priming call falls through to a fresh upload: a lot of needless egress at scale.

Access control

Every file route is scoped to the authenticated principal. The service derives the storage namespace from your identity and the resource kind; requesting a session that derives to a different namespace fails rather than returning someone else's data.

This is why there is no "list all my sessions" endpoint: the caller is expected to track the session ids it received.

Complete example

Upload an input

UPLOAD=$(curl -sX POST http://localhost:3112/v1/upload \
  -F 'file=@sales.csv' -F 'kind=user')

STORAGE=$(echo "$UPLOAD" | jq -r '.storage_session_id')
FILE_ID=$(echo "$UPLOAD" | jq -r '.files[0].id')

Run code against it

RESULT=$(curl -sX POST http://localhost:3112/v1/exec \
  -H 'Content-Type: application/json' \
  -d "{
    \"lang\": \"py\",
    \"code\": \"import pandas as pd, matplotlib.pyplot as plt\\ndf = pd.read_csv('sales.csv')\\ndf.plot()\\nplt.savefig('sales.png')\",
    \"files\": [{
      \"id\": \"$FILE_ID\",
      \"resource_id\": \"user-42\",
      \"storage_session_id\": \"$STORAGE\",
      \"name\": \"sales.csv\",
      \"kind\": \"user\"
    }]
  }")

Download the artifact

SESSION=$(echo "$RESULT" | jq -r '.session_id')
OUT_ID=$(echo "$RESULT" | jq -r '.files[] | select(.name=="sales.png") | .id')

curl -s "http://localhost:3112/v1/download/$SESSION/$OUT_ID" -o sales.png

On this page