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

# Run Claude Code in a CoreWeave sandbox

> Use Claude Code from your terminal while its commands and workspace run on CoreWeave.

Run Claude Code inside a CoreWeave sandbox and interact with it from your terminal. This guide covers launching the agent, working on a repository, retrieving a result, and stopping the sandbox. Claude's model requests still go to your configured model provider.

<Note>
  CoreWeave Serverless sandboxes are in public preview.
</Note>

## Prerequisites

Before you begin, you need the following:

* A [Weights & Biases (W\&B) API key](https://wandb.ai/authorize). These examples use W\&B authentication. For other credentials, see [Choose a credential](/products/sandboxes/get-started#choose-a-credential).
* A Claude account or API credentials supported by Claude Code.
* A repository URL the sandbox can clone. The examples use a public repository. Private repositories require Git credentials inside the sandbox.

Export your W\&B API key in the terminal where you run this guide. Unset any CoreWeave token so `cws-agent` selects W\&B authentication:

```bash theme={"system"}
export WANDB_API_KEY="[WANDB-API-KEY]"
unset CWSANDBOX_API_KEY
```

W\&B users don't need the `SANDBOX_USER` IAM action. That permission applies only when authenticating with a CoreWeave API access token.

## Quick start with cws-agent

Follow the [`cws-agent` installation instructions](https://github.com/coreweave/cws-agent#install). The tool configures a snapshot volume to save and restore your workspace with [file system snapshots](/products/sandboxes/file-system-snapshots#start-a-sandbox-with-a-snapshot-mount).

To use an Anthropic API key, load it into `ANTHROPIC_API_KEY` in your local terminal before launching or restoring the sandbox. `cws-agent` passes this variable into the sandbox. API-key authentication doesn't require browser sign-in. See [Claude Code authentication](https://code.claude.com/docs/en/authentication).

Replace `[SANDBOX-NAME]` with a `cws-agent` session name for this workspace and `[REPOSITORY-URL]` with the repository to clone. For the session name, use 1 to 40 lowercase letters, digits, or hyphens, starting with a letter or digit:

```bash theme={"system"}
cws-agent launch [SANDBOX-NAME] --repo-url [REPOSITORY-URL] --permission-mode native
```

Claude Code opens in the sandbox's project directory. Follow any workspace trust prompts. For API-key authentication, approve the key when prompted. If you need account authentication, exit Claude and run `cws-agent login [SANDBOX-NAME]`, then complete `/login` there. The `--permission-mode native` option uses Claude's own approval settings. Without it, `cws-agent` defaults to bypassing those approval prompts. See [permission modes](https://github.com/coreweave/cws-agent/blob/main/docs/permissions.md).

If Claude reports **Not logged in** despite a configured API key and never offers to approve it, exit with `/exit`, then reconnect with onboarding enabled:

```bash theme={"system"}
cws-agent connect [SANDBOX-NAME] --cmd 'unset IS_DEMO; exec claude'
```

This command uses Claude's native approval settings. Accept the workspace trust and API-key prompts before continuing.

Ask Claude to create a file you can check afterward:

```text theme={"system"}
Create sandbox-proof.txt in the current directory containing "Hello from CoreWeave", then read it back.
```

Exit Claude with `/exit`. From your local terminal, read the file and save the workspace before stopping compute:

```bash theme={"system"}
cws-agent exec [SANDBOX-NAME] 'cat /workspace/project/sandbox-proof.txt'
cws-agent down [SANDBOX-NAME]
```

The file should contain `Hello from CoreWeave`. `down` takes a snapshot and stops the sandbox. Exiting Claude alone leaves it running. If the snapshot fails, inspect `cws-agent status [SANDBOX-NAME]` and retry after resolving the failure. If you can discard unsaved changes, use `cws-agent down [SANDBOX-NAME] --no-snapshot`.

To return to the saved workspace, run:

```bash theme={"system"}
cws-agent restore [SANDBOX-NAME] --connect --permission-mode native
```

For saved conversations and parallel worktrees, see the [`cws-agent` sessions guide](https://github.com/coreweave/cws-agent/blob/main/docs/sessions.md).

## Set up with the Sandbox SDK

Run Python snippets in the virtual environment below. Save TypeScript snippets as `.mts` files in the project where you install the client, then run them with `npx tsx [FILENAME].mts`.

Use this path to manage the sandbox directly. It's independent of `cws-agent` and doesn't configure snapshots.

### Create the sandbox

Choose a client and install it locally:

<Tabs>
  <Tab title="Python">
    Use Python 3.11 or later and `uv`:

    ```bash theme={"system"}
    uv venv --python 3.11
    source .venv/bin/activate
    uv pip install 'cwsandbox[wandb]>=1.14.2'
    ```
  </Tab>

  <Tab title="TypeScript">
    Use Node.js 22 or later. Install the client and TypeScript runner in your project:

    ```bash theme={"system"}
    npm install @coreweave/cwsandbox@0.5.0-beta.0 tsx
    ```
  </Tab>
</Tabs>

Save the script for your language using the filename shown. It creates a serverless sandbox, installs Claude Code, and clones the repository passed on the command line. If setup fails, it stops the sandbox before raising the error.

<Tabs>
  <Tab title="Python">
    ```python title="create_claude_sandbox.py" theme={"system"}
    import sys

    from cwsandbox import AuthStrategy, Sandbox

    sandbox = Sandbox.run(
        auth=AuthStrategy.WANDB,
        container_image="node:22-bookworm",
        resources={"cpu": "2", "memory": "4Gi"},
        max_lifetime_seconds=4 * 3600,
        tags=["claude-code-cli"],
    )
    try:
        sandbox.wait()
        commands = [
            ["bash", "-o", "pipefail", "-ec", "curl -fsSL https://claude.ai/install.sh | bash"],
            ["mkdir", "-p", "/workspace"],
            ["git", "clone", "--", sys.argv[1], "/workspace/project"],
        ]
        for command in commands:
            result = sandbox.exec(command, timeout_seconds=900).result()
            if result.returncode != 0:
                raise RuntimeError(result.stderr or result.stdout)
    except BaseException:
        sandbox.stop().result()
        raise

    print(f"Sandbox ID: {sandbox.sandbox_id}")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript title="create_claude_sandbox.mts" theme={"system"}
    import { createSandboxClientFromEnv } from "@coreweave/cwsandbox/wandb";

    const repository = process.argv[2];
    if (!repository) throw new Error("Pass a repository URL.");

    const client = createSandboxClientFromEnv();
    const sandbox = await client.create({
      containerImage: "node:22-bookworm",
      resources: { cpu: "2", memory: "4Gi" },
      maxLifetimeSeconds: 4 * 3600,
      waitUntilRunning: false,
      tags: ["claude-code-cli"],
    });
    try {
      await sandbox.wait();
      const commands = [
        ["bash", "-o", "pipefail", "-ec", "curl -fsSL https://claude.ai/install.sh | bash"],
        ["mkdir", "-p", "/workspace"],
        ["git", "clone", "--", repository, "/workspace/project"],
      ];
      for (const command of commands) {
        await sandbox.commands.run(command, { timeoutMs: 900_000, check: true });
      }
    } catch (error) {
      await sandbox.stop();
      throw error;
    }
    console.log(`Sandbox ID: ${sandbox.sandboxId}`);
    ```
  </Tab>
</Tabs>

Replace `[REPOSITORY-URL]` with your repository URL, then run the script:

<Tabs>
  <Tab title="Python">
    ```bash theme={"system"}
    python create_claude_sandbox.py [REPOSITORY-URL]
    ```
  </Tab>

  <Tab title="TypeScript">
    ```bash theme={"system"}
    npx tsx create_claude_sandbox.mts [REPOSITORY-URL]
    ```
  </Tab>
</Tabs>

Record the printed sandbox ID. The sandbox continues running after the script exits, until you stop it or its 4-hour lifetime expires.

### Open Claude Code

Use the SDK to attach your local terminal with W\&B authentication. The script forwards keystrokes to a sandbox shell and restores your terminal when the shell exits.

<Tabs>
  <Tab title="Python">
    On macOS or Linux, save this as `attach_sandbox.py`:

    ```python title="attach_sandbox.py" theme={"system"}
    import os
    import shutil
    import sys
    import termios
    import threading
    import tty

    from cwsandbox import AuthStrategy, Sandbox

    if not sys.stdin.isatty() or not sys.stdout.isatty():
        raise SystemExit("Run this script in an interactive terminal.")

    sandbox = Sandbox.from_id(sys.argv[1], auth=AuthStrategy.WANDB).result()
    size = shutil.get_terminal_size()
    terminal = sandbox.shell(["/bin/bash"], width=size.columns, height=size.lines)
    fd = sys.stdin.fileno()
    saved = termios.tcgetattr(fd)


    def forward_input():
        while data := os.read(fd, 1024):
            terminal.stdin.write(data).result()
        terminal.stdin.close().result()


    try:
        tty.setraw(fd)
        threading.Thread(target=forward_input, daemon=True).start()
        for chunk in terminal.output:
            sys.stdout.buffer.write(chunk)
            sys.stdout.buffer.flush()
        result = terminal.result()
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, saved)
        terminal.stdin.close().result()

    raise SystemExit(result.returncode)
    ```
  </Tab>

  <Tab title="TypeScript">
    Save this as `attach_sandbox.mts`:

    ```typescript title="attach_sandbox.mts" theme={"system"}
    import { createSandboxClientFromEnv } from "@coreweave/cwsandbox/wandb";

    if (!process.stdin.isTTY || !process.stdout.isTTY) {
      throw new Error("Run this script in an interactive terminal.");
    }
    const sandboxId = process.argv[2];
    if (!sandboxId) throw new Error("Pass a sandbox ID.");
    const client = createSandboxClientFromEnv();
    const sandbox = await client.fromId(sandboxId);
    const terminal = await sandbox.shell({
      command: ["/bin/bash"],
      cols: process.stdout.columns,
      rows: process.stdout.rows,
    });
    const wasRaw = process.stdin.isRaw;
    const forwardInput = (chunk: Buffer) => {
      void terminal.stdin.write(chunk).catch((error) => {
        console.error(error);
        void terminal.cancel();
      });
    };

    try {
      process.stdin.setRawMode(true);
      process.stdin.on("data", forwardInput);
      process.stdin.resume();
      for await (const chunk of terminal.output) {
        process.stdout.write(chunk);
      }
      const result = await terminal.wait();
      process.exitCode = result.exitCode;
    } finally {
      process.stdin.off("data", forwardInput);
      process.stdin.setRawMode(wasRaw);
      process.stdin.pause();
      await terminal.stdin.close();
    }
    ```
  </Tab>
</Tabs>

Replace `[SANDBOX-ID]` with the printed ID, then run:

<Tabs>
  <Tab title="Python">
    ```bash theme={"system"}
    python attach_sandbox.py [SANDBOX-ID]
    ```
  </Tab>

  <Tab title="TypeScript">
    ```bash theme={"system"}
    npx tsx attach_sandbox.mts [SANDBOX-ID]
    ```
  </Tab>
</Tabs>

For a sandbox created with a CoreWeave API access token, `cwsandbox sh [SANDBOX-ID]` is an optional shortcut. Install the `cli` extra to use it. It requires `CWSANDBOX_API_KEY` and does not accept W\&B keys.

For API-key authentication, enter the key in the sandbox's Bash shell before starting Claude. The input is hidden and isn't included in the command history:

```bash theme={"system"}
read -r -s -p 'Anthropic API key: ' ANTHROPIC_API_KEY
export ANTHROPIC_API_KEY
printf '\n'
```

Inside the sandbox, start Claude from the cloned repository:

```bash theme={"system"}
cd /workspace/project
/root/.local/bin/claude
```

Approve the API key, or complete account sign-in if you aren't using a key, then accept the workspace trust prompts. Ask Claude to create the `sandbox-proof.txt` file using the prompt from the quick start. When prompted, approve the file write.

### Retrieve the result and stop

Exit Claude with `/exit`, then exit the sandbox shell with `exit`. From your local terminal, read the file through the SDK. Replace `[SANDBOX-ID]` with the printed ID:

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    from cwsandbox import AuthStrategy, Sandbox

    sandbox = Sandbox.from_id("[SANDBOX-ID]", auth=AuthStrategy.WANDB).result()
    result = sandbox.exec(["cat", "/workspace/project/sandbox-proof.txt"], check=True).result()
    print(result.stdout, end="")
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"system"}
    import { createSandboxClientFromEnv } from "@coreweave/cwsandbox/wandb";

    const client = createSandboxClientFromEnv();
    const sandbox = await client.fromId("[SANDBOX-ID]");
    const result = await sandbox.commands.run(["cat", "/workspace/project/sandbox-proof.txt"], { check: true });
    process.stdout.write(result.stdout);
    ```
  </Tab>
</Tabs>

Confirm that the output contains `Hello from CoreWeave`, then stop the sandbox:

<Tabs>
  <Tab title="Python">
    ```python theme={"system"}
    from cwsandbox import AuthStrategy, Sandbox

    sandbox = Sandbox.from_id("[SANDBOX-ID]", auth=AuthStrategy.WANDB).result()
    sandbox.stop().result()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript theme={"system"}
    import { createSandboxClientFromEnv } from "@coreweave/cwsandbox/wandb";

    const client = createSandboxClientFromEnv();
    const sandbox = await client.fromId("[SANDBOX-ID]");
    await sandbox.stop();
    ```
  </Tab>
</Tabs>

This SDK example has no persistent mount. For larger results, use [file operations](/products/sandboxes/client/guides/file-operations). For a workspace you can restore into a new sandbox, configure [file system snapshots](/products/sandboxes/file-system-snapshots) at creation.

## Troubleshoot

Use these checks to resolve common issues:

* If sandbox creation fails, check your W\&B API key and [authentication settings](/products/sandboxes/get-started#choose-a-credential). Only CoreWeave API access tokens require the `SANDBOX_USER` IAM action.
* If installation, cloning, or model requests fail, check outbound connectivity and the relevant provider credentials. For [CoreWeave Kubernetes Service (CKS) placement](/products/sandboxes/get-started#deploy-sandboxes-on-your-own-cks-cluster), your runner's policy must permit those destinations.
* If the terminal disconnects, attach again while the sandbox is running. To retain a process across terminal disconnects, run it in a terminal multiplexer such as `tmux`.

## Next steps

For more information, see these guides:

* [Interactive shells and TTY](/products/sandboxes/client/guides/interactive-shells) covers terminal access from the SDK.
* [Sandbox lifecycle](/products/sandboxes/client/guides/sandbox-lifecycle) covers waiting, reconnecting, and stopping.
* [Claude Code documentation](https://code.claude.com/docs/en/overview) covers agent configuration and authentication.


## Related topics

- [About CoreWeave sandboxes](/products/sandboxes.md)
