Metadata-Version: 2.4
Name: impello
Version: 0.3.0
Summary: Python SDK for Impello sandboxes.
Keywords: impello,sandbox,microvm,agents,code-interpreter
License-Expression: MIT
Requires-Dist: python-dateutil>=2.8.2
Requires-Dist: wcmatch>=10.1,<12
Requires-Dist: protobuf-py>=0.1.1,<0.2
Requires-Dist: httpx>=0.27.0,<1.0.0
Requires-Dist: h2>=4.4.1,<5
Requires-Dist: attrs>=23.2.0
Requires-Dist: packaging>=24.1
Requires-Dist: typing-extensions>=4.10.0
Requires-Dist: connectrpc>=0.11.1,<0.12
Requires-Dist: pyqwest>=0.10.0,<0.11
Requires-Python: >=3.10
Project-URL: Homepage, https://impello.ai
Project-URL: Repository, https://github.com/21-Dreams/impello/tree/main/packages/sdk-python
Project-URL: Bug Tracker, https://github.com/21-Dreams/impello/issues
Description-Content-Type: text/markdown

# `impello`

The Python SDK for Impello sandboxes.

## Install

```bash
pip install impello
```

## Use

```python
from impello import Sandbox

sandbox = Sandbox.create()
result = sandbox.commands.run("echo hello")

print(result.stdout)

sandbox.pause()
```

Set your key in the environment, or pass it to each call:

```bash
export IMPELLO_API_KEY=imp_...
```

```python
Sandbox.list(api_key="imp_...")
```

For a process that talks to more than one account or more than one fleet, bind
the settings to a client instead:

```python
from impello import Impello

client = Impello(api_key="imp_...")
sandbox = client.Sandbox.create()
```

## Settings

Every setting reads an `IMPELLO_` name first, then the matching `E2B_` name.

| Variable | Default | What it does |
|---|---|---|
| `IMPELLO_API_KEY` | none | The key. Starts with `imp_` |
| `IMPELLO_DOMAIN` | `sandbox.impello.ai` | The domain the API and the sandboxes sit on |
| `IMPELLO_API_URL` | `https://api.<domain>` | The API address. Set this to reach a self-hosted API |
| `IMPELLO_SANDBOX_URL` | derived from the domain | The address a sandbox is reached at |
| `IMPELLO_DEBUG` | `false` | Talk to `http://localhost:3000` |

The `E2B_` fallback is the migration, not politeness. Callers already export
`E2B_API_KEY`, `E2B_API_URL` and `E2B_DOMAIN`. Rename when it suits you.
Nothing breaks if you never do.

Only the domain has a default. Without one the SDK resolves E2B's own
`e2b.app`, and the failure is a connection to somebody else's fleet,
authenticated with a key that host has never seen.

Params passed to a single call beat a client's params, which beat the
environment.

## This is a copy of E2B's client, not a wrapper around it

`impello` used to depend on `e2b` and bind a few defaults underneath it. That
worked. It was replaced because of what it *said*: `pip show impello` listed
`e2b` as a requirement, and every request carried a `publisher: e2b` header to
our own fleet. Both are things a customer and our own logs can read, and
`@impello/sdk` had already stopped saying them.

So this package is now E2B's MIT-licensed Python client, vendored. The
copyright notice stays (`LICENSE`). It is **sandbox scope only** — template,
volume and secret management are not shipped, matching `@impello/sdk`. Four
tests in `tests/test_no_e2b_dependency.py` hold the claim: no declared
dependency on `e2b`, no import of it anywhere in the package, `publisher:
impello` on the wire, and no shipped module pointing a customer at `e2b.dev`.

`src/impello/api/client` is generated, not written. `make generate-api`
rebuilds it from the API spec in the infra repo. Both tools in that pipeline
are pinned, and the pins matter — the Makefile says why.

We do not follow upstream. See `docs/decisions/fork-independence.md`.

## Keys

A key starts with `imp_`. Keys minted before 2026-08-30 started with `e2b_` and
**no client can make one work** — the server compares the whole prefix before it
hashes anything. This SDK recognises an old key and says so, rather than letting
it become a bare 401:

```python
>>> Sandbox.create(api_key="e2b_...")
AuthenticationException: This key starts with "e2b_" and was minted before
Impello moved to its own key prefix on 2026-08-30. ...
```

## Develop

```bash
uv sync
make test
make lint
```
