---
title: "Run a shell command"
method: POST
path: "/sandboxes/{id}/exec"
tags: ["Runtime"]
---

# Run a shell command

`POST /sandboxes/{id}/exec`

Runs `cmd` inside the sandbox via a shell, so pipes, `&&`, redirects, and
installed CLI tools all work. Sandbox must be in status `ready`.

Pass `stream: true` to receive `stdout` / `stderr` as they arrive. The
response then uses `Content-Type: text/event-stream` with one JSON
object per `data:` line; the final event is `{ "type": "done", ... }`.
See `ExecStreamFrame` for the event shape.

## Path parameters

- `id` string, required

## Request body

- ExecInput
  - `cmd` string, required — Shell command to run. Pipes / `&&` / redirects all work.
  - `timeout_seconds` integer — Defaults to 30. Process is killed at the limit.
  - `cwd` string — Absolute path inside the sandbox. Defaults to `/`.
  - `env` object — Extra environment variables for this command only. Layered on top of the sandbox's existing environment; same-named keys here override the sandbox-level ones for this call. Values must be strings. Scoped to a single invocation, the next call starts with the sandbox defaults again.
  - `stream` boolean — When true, the server keeps the connection open and streams stdout/stderr as Server-Sent Events (`text/event-stream`). Each event is a JSON object on a `data:` line; the last event is always `{ "type": "done", ... }` or `{ "type": "error", ... }`.

## Response `200`

Command completed.

When the request body has `stream: true`, the response is
`text/event-stream`, one `ExecStreamFrame` per `data:` event, the
last being a `done` event.

- ExecResultEnvelope
  - `message` string, required
  - `data` ExecResult, required
    - `stdout` string, required
    - `stderr` string, required
    - `exit_code` integer, required
    - `duration_ms` integer, required

## Other responses

- `400` — Validation error / invalid state transition
- `404` — Sandbox or related resource not found (also returned when owned by another user)

## Changes

- **2026-06-29** `4a016f074bc0` — 1 breaking, 1 info
  - removed the media type `application/x-ndjson` for the response with the status `200`
  - added the media type `text/event-stream` for the response with the status `200`
- **2026-05-23** `b236bf76f9a7` — 1 info
  - added the new optional request property `env`

[Change history](https://skmtc.dev/brimblehq/apis/brimble-sandbox-api/changes/sandboxes/:id/exec/post.md)

---

[API](https://skmtc.dev/brimblehq/apis/brimble-sandbox-api.md) · [All operations](https://skmtc.dev/brimblehq/apis/brimble-sandbox-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/brimblehq/brimble-sandbox-api/revisions/7fe2df041597/schema)
