> ## Documentation Index
> Fetch the complete documentation index at: https://docs.together.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Code sandbox

> Run commands and code in isolated runtime environments built from Docker-image snapshots.

<Note>
  The `together-sandbox` SDK and CLI must be enabled for your organization for you to use them. [Contact us](https://www.together.ai/contact) to request access.
</Note>

Together code sandbox runs your code in isolated runtime environments. You define an environment as a **snapshot** built from a Docker image or Dockerfile, then create **sandboxes**, running instances of a snapshot where you execute commands and work with files. Use it to run untrusted or model-generated code, execute tool calls from agents, or provide rollout environments for reinforcement learning.

The `together-sandbox` package ships as a Python SDK, a TypeScript SDK, and a CLI. This page covers the core workflow. The [full reference](#full-reference) lives in the `together-sandbox` repo.

## Installation

<CodeGroup>
  ```bash Python theme={null}
  pip install together-sandbox
  ```

  ```bash TypeScript theme={null}
  npm install together-sandbox
  ```

  ```bash CLI theme={null}
  curl -fsSL https://raw.githubusercontent.com/togethercomputer/together-sandbox/main/install.sh | bash
  ```
</CodeGroup>

The Python SDK requires Python 3.10 or later, and the TypeScript SDK requires Node.js 18 or later. The CLI installer downloads a self-contained binary to `~/.local/bin`, with no Node.js or npm required.

## Authentication

The SDKs and CLI read your Together API key from the `TOGETHER_API_KEY` environment variable:

```bash theme={null}
export TOGETHER_API_KEY=<your_key>
```

You can also pass the key directly when constructing an SDK client, with `api_key` in Python or `apiKey` in TypeScript.

## Create a snapshot

Every sandbox starts from a snapshot. Create one from a public Docker image, or from a Docker build context. Both are processed by Together's remote image builder, which also optimizes the image for fast cold starts, so you don't need Docker installed locally.

<CodeGroup>
  ```python Python theme={null}
  import asyncio

  from together_sandbox import CreateImageSnapshotParams, TogetherSandbox


  async def main():
      async with TogetherSandbox() as sdk:
          result = await sdk.snapshots.create(
              CreateImageSnapshotParams(
                  image="python:3.12-slim",
                  alias="my-python@v1",
              )
          )
          print(result.snapshot_id)


  asyncio.run(main())
  ```

  ```typescript TypeScript theme={null}
  import { TogetherSandbox } from "together-sandbox";

  const sdk = new TogetherSandbox({ apiKey: process.env.TOGETHER_API_KEY! });

  const result = await sdk.snapshots.create({
    image: "python:3.12-slim",
    alias: "my-python@v1",
  });

  console.log(result.snapshotId);
  ```

  ```bash CLI theme={null}
  together-sandbox snapshots create --image python:3.12-slim --alias my-python@v1
  ```
</CodeGroup>

An alias names a snapshot as `namespace@tag`, so later calls can reference `my-python@v1` instead of a snapshot ID.

To build from a Dockerfile instead, pass a build context: `CreateContextSnapshotParams(context="./my-app")` in Python, `{ context: "./my-app" }` in TypeScript, or `--context ./my-app` in the CLI. The builder uses the `Dockerfile` in the context directory unless you point at another file with the `dockerfile` parameter.

<Tip>
  If you rebuild the same project often, set a stable `cache_key` (`--cache-key` in the CLI) so builds share a layer cache. Without one, every build starts cold.
</Tip>

## Run commands in a sandbox

Create a sandbox from a snapshot. The create call starts the sandbox and returns a connected client, so there is no separate start step.

<CodeGroup>
  ```python Python theme={null}
  import asyncio

  from together_sandbox import TogetherSandbox


  async def main():
      sdk = TogetherSandbox()
      sandbox = await sdk.sandboxes.create(snapshot_alias="my-python@v1")

      result = await sandbox.execs.exec("python3", ["-c", "print(6 * 7)"])
      print(result["exit_code"], result["output"])

      await sandbox.files.create("/tmp/data.txt", "Hello, sandbox!")
      print(await sandbox.files.read("/tmp/data.txt"))

      await sandbox.terminate()


  asyncio.run(main())
  ```

  ```typescript TypeScript theme={null}
  import { TogetherSandbox } from "together-sandbox";

  const sdk = new TogetherSandbox({ apiKey: process.env.TOGETHER_API_KEY! });
  const sandbox = await sdk.sandboxes.create({ snapshotAlias: "my-python@v1" });

  const result = await sandbox.execs.exec("python3", ["-c", "print(6 * 7)"]);
  console.log(result.exitCode, result.output);

  await sandbox.files.create("/tmp/data.txt", "Hello, sandbox!");
  console.log(await sandbox.files.read("/tmp/data.txt"));

  await sandbox.terminate();
  ```

  ```bash CLI theme={null}
  # Run one command in a throwaway sandbox
  together-sandbox sandboxes run @my-python@v1 --rm -- python3 -c "print(6 * 7)"

  # Or keep a sandbox and run commands in it repeatedly
  SANDBOX_ID=$(together-sandbox sandboxes create @my-python@v1 | awk '{print $3}')
  together-sandbox sandbox exec run "$SANDBOX_ID" -- python3 -c "print(6 * 7)"
  together-sandbox sandbox exec run "$SANDBOX_ID" -it -- bash
  together-sandbox sandboxes terminate "$SANDBOX_ID"
  ```
</CodeGroup>

In the CLI, a leading `@` on an argument resolves it as a snapshot alias.

Each sandbox gets 1 vCPU and 2 GiB of memory by default. Set `cpu` (0.1 to 16 cores) and `memory_bytes` or `memoryBytes` (1 to 8 GB per CPU) at creation to size it differently. The CLI flags are `--cpu` and `--memory-bytes`.

<Note>
  In Python, using the SDK or a sandbox as an async context manager closes the HTTP connection on exit. It does not terminate the sandbox. Call `terminate()` when you're done with it.
</Note>

## Sandbox lifecycle

* **Sandboxes run until you terminate them:** Nothing cleans them up automatically unless you set a `ttl` at creation or pass `--rm` to `sandboxes run` in the CLI. `together-sandbox sandboxes list` shows what is still running.
* **Termination is permanent:** A terminated sandbox cannot be restarted.
* **Sandboxes are ephemeral by default:** Terminating one discards its filesystem.
* **Snapshot on termination to keep state:** Pass `snapshot={"aliases": ["my-app@v2"]}` to `terminate()` in Python, `{ snapshot: { aliases: ["my-app@v2"] } }` in TypeScript, or `--snapshot-alias my-app@v2` to `sandboxes terminate` in the CLI. The produced snapshot also gets the alias `sandbox:<sandbox_id>` automatically. Create a new sandbox from that snapshot to continue where the old one left off.

## Full reference

The complete reference, covering file and directory operations, streaming exec output, port discovery, filesystem watching, resource listing and tagging, retries, and error handling, lives in the `together-sandbox` repo:

* [Python SDK reference](https://github.com/togethercomputer/together-sandbox/blob/main/docs/python-sdk.md).
* [TypeScript SDK reference](https://github.com/togethercomputer/together-sandbox/blob/main/docs/typescript-sdk.md).
* [CLI reference](https://github.com/togethercomputer/together-sandbox/blob/main/docs/cli.md).

## Legacy SDK

The earlier code sandbox offering built on `@codesandbox/sdk` remains documented at [Code sandbox legacy SDK](/docs/together-code-sandbox-legacy) for existing users. Use the `together-sandbox` SDK on this page for new integrations.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.