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

# Migrate an E2B shell tool to Sailboxes

> Give this guide to your coding agent to migrate an E2B shell tool to Sailboxes. It covers command execution, file transfers, and workers that depend on a persistent notebook.

## Sailboxes vs. E2B: CPU billing and session length

You can raise the CPU limit on Sail without paying for unused cores. Sail charges \$0.015 per used vCPU-hour. E2B Hobby and Pro charge \$0.0504 per configured vCPU-hour while the sandbox runs. A Sailbox has no fixed lifetime by default. E2B Pro limits each continuous session to 24 hours. [Sail pricing](https://docs.sailresearch.com/sailboxes-pricing.md#rates) · [Sailbox lifecycle](https://docs.sailresearch.com/sailboxes-lifecycle.md) · [E2B pricing and plan limits](https://e2b.dev/pricing)

## Create the Sailbox

Install the [Sail Python SDK](https://docs.sailresearch.com/reference/python-sdk.md) on the machine that runs your controller. Run `python -m pip install sail`. Sign in with `sail auth login`. Create one Sailbox per session. This example saves its ID in a local file. In your application, store the ID with the agent session.

```python theme={null}
from pathlib import Path
import sail

app = sail.App.find(name="migration-demo", mint_if_missing=True)
sb = sail.Sailbox.create(app=app, name="e2b-worker")
Path("sailbox-id.txt").write_text(sb.sailbox_id)
```

## Transfer files

Replace `sandbox.files.write(path, data)` with `sb.fs.write(path, data)`. Run this code from the directory that contains `worker.py` and `job.json`. The example worker reads `/tmp/job.json` and writes `/tmp/result.json` inside the Sailbox. Use the paths your worker needs.

```python theme={null}
sb.fs.write("/tmp/worker.py", Path("worker.py").read_bytes())
sb.fs.write("/tmp/job.json", Path("job.json").read_bytes())
```

Install the template dependencies in a [Sail image](https://docs.sailresearch.com/sailboxes-images). Start the worker with a command. Sail does not run the Dockerfile’s `CMD` or `ENTRYPOINT`.

## Run your existing worker

Replace `sandbox.commands.run()` with `sb.run()`. Read the output from `result.stdout`. On Sail, `check=True` raises an exception if the command fails.

```diff theme={null}
- result = sandbox.commands.run("python3 /tmp/worker.py")
+ result = sb.run(["python3", "/tmp/worker.py"], check=True)
  print(result.stdout)
```

Each `sb.run()` call starts a new process. For E2B notebooks that use `run_code()`, keep an interpreter running if you need to preserve variables. Keep the same response format for notebook output.

## Reconnect after sleep

An idle Sailbox [sleeps automatically by default](https://docs.sailresearch.com/sailboxes-autosleep). Use the saved ID to find the same Sailbox. Read the result file. This operation wakes a sleeping Sailbox.

```python theme={null}
from pathlib import Path
import sail

sb = sail.Sailbox.get(Path("sailbox-id.txt").read_text().strip())
print(sb.fs.read("/tmp/result.json").decode())
```

Sleep preserves files and memory. [Termination deletes the Sailbox.](https://docs.sailresearch.com/sailboxes-lifecycle.md)

## Check the worker output

Run your worker with the same input on E2B and on Sail. Compare the command output and the files from both runs.
