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

# Python Sandbox SDK quickstart

> Create and manage Porter Sandboxes from Python

The Python Sandbox SDK is published as `porter-sandbox`. Use it from application code running in your sandbox-enabled Porter cluster.

<Warning>
  Sandboxes are in a private beta. Please reach out to us at [support@porter.run](mailto:support@porter.run) or over Slack if you are interested in joining.
</Warning>

## Install

Add the SDK to your application image:

```bash theme={null}
pip install porter-sandbox
```

Or with `uv`:

```bash theme={null}
uv add porter-sandbox
```

## Create your first sandbox

Create a sandbox, execute a command, print the command output, and terminate the sandbox when the work is done:

```python theme={null}
from porter_sandbox import Porter

with Porter() as porter:
    sandbox = porter.sandboxes.create(
        image="python:3.12-slim",
        name="python-quickstart",
        tags={"example": "python-quickstart"},
    )

    result = sandbox.exec(["python", "-c", "print('hello from porter')"])
    print(result.stdout)

    sandbox.terminate()
```

The SDK connects to the in-cluster Sandbox API automatically when this code runs as a Porter Application in the same cluster where sandboxes are enabled.

If you need to invoke sandboxes from outside that cluster, set `PORTER_SANDBOX_API_KEY` to a Porter API token and `PORTER_CLUSTER_ID` to the target cluster. The SDK reads the project from the token and builds the external Porter API URL automatically; see [calling from outside the cluster](/sandboxes/getting-started#calling-from-outside-the-cluster) for details.

Use sandbox names when you need to fetch, inspect, exec into, or terminate a sandbox later. Sandbox names must be unique within a cluster and currently cannot be reused, even after the sandbox is terminated.

## Fetch logs

Logs are returned as structured log lines:

```python theme={null}
from porter_sandbox import Porter

with Porter() as porter:
    sandbox = porter.sandboxes.create(
        image="python:3.12-slim",
        name="python-logs-demo",
    )

    try:
        sandbox.exec(["python", "-c", "print('log me')"])

        for line in sandbox.logs(limit=100):
            print(f"{line.timestamp} [{line.level}] {line.line}")
    finally:
        sandbox.terminate()
```

## Get a sandbox by name

Use `get(name)` when you know the sandbox name:

```python theme={null}
from porter_sandbox import Porter

with Porter() as porter:
    sandbox = porter.sandboxes.get("python-quickstart")
    print(sandbox.phase)
```

## List sandboxes

Use tags to find sandboxes created by a workflow:

```python theme={null}
from porter_sandbox import Porter

with Porter() as porter:
    sandboxes = porter.sandboxes.list(tags={"workflow": "agent-run"})

    for sandbox in sandboxes:
        print(sandbox.phase)
```

## Async usage

Use `AsyncPorter` from async application code:

```python theme={null}
import asyncio
from porter_sandbox import AsyncPorter

async def main():
    async with AsyncPorter() as porter:
        sandbox = await porter.sandboxes.create(
            image="python:3.12-slim",
            name="async-python-demo",
        )

        try:
            result = await sandbox.exec(["python", "-c", "print(2 + 2)"])
            print(result.stdout)
        finally:
            await sandbox.terminate()

asyncio.run(main())
```

Launch many sandboxes concurrently with `asyncio.gather`:

```python theme={null}
async with AsyncPorter() as porter:
    sandboxes = await asyncio.gather(*[
        porter.sandboxes.create(
            image="python:3.12-slim",
            name=f"batch-demo-{i}",
            tags={"batch": "demo"},
        )
        for i in range(10)
    ])
```

## Next steps

* [Python Sandbox SDK reference](/sandbox/sdk/python/reference)
* [Python Sandbox SDK volumes](/sandbox/sdk/python/volumes)
* [Python Sandbox SDK errors](/sandbox/sdk/python/errors)
* [Sandboxes getting started](/sandboxes/getting-started)
