/docs/Sandbox/Running Tools
back to app →

Running tools

Every tool execution follows the same path: deploy → execute → stream logs → return result. You don't have to do any of this manually — the UI handles it — but it helps to know what's happening.

Deploy

The first time you run a tool (or the first time after you've edited it), the sandbox fetches a fresh copy:

  1. The browser asks the sandbox to deploy tool T.
  2. The sandbox calls the backend with its API token: GET /api/tools/T/archive.zip.
  3. The backend verifies you own the tool and streams back a zip archive.
  4. The sandbox extracts it to /sandbox/tools/T/, detects the language (Python or JavaScript), and installs dependencies (uv for Python requirements.txt, pnpm for JavaScript package.json).
  5. If the tool exports an init() hook, the sandbox starts it in the background and deploy returns immediately.

Deployment typically takes a second or two; dependency‑heavy tools can take longer on first deploy.

init() deliberately doesn't block the deploy response — it may be downloading a model that takes minutes, and the deploy call itself is bounded by a 30‑second round trip. The func reports its own state through progress(), which the UI renders as a progress bar, and the first Run waits for init to finish before executing. If init fails, runs are refused with that error rather than failing somewhere deeper in.

Execute

Once deployed, the sandbox keeps a worker for that tool — a pre‑warmed process ready to receive input. When you click Run:

  1. The browser sends the input and any settings to the sandbox over a WebSocket.
  2. The sandbox hands the request to the tool's worker.
  3. The worker calls the tool's process(input, settings) function.
  4. The result comes back over the same WebSocket.

Because the worker is already alive, repeated runs of the same tool are fast — there's no cold start cost after the first execution.

Worker pool

Each sandbox keeps up to 20 workers alive simultaneously. Beyond that, the least‑recently‑used worker is evicted to make room. Workers also time out after ~15 minutes of idleness.

In practice you almost never need to think about this — the pool self‑manages. The main visible effect is that a tool you just ran will run again instantly, while a tool you haven't touched in a while may take a beat to warm up.

Logs

Anything your tool writes to stdout / stderr or logs through the SDK is streamed back in real time and displayed in the execution console. Log messages include a timestamp and severity level.

Logs are also kept for the duration of the execution so you can review them after the tool finishes.

Timeouts and limits

  • Default timeout: 30 seconds per execution. Long‑running tools can request a higher timeout.
  • init() is not bound by that 30 seconds — it runs outside the execute path precisely so one‑off setup (fetching a model, warming a cache) doesn't have to fit in a single run's budget.
  • Concurrent workers: 20 per sandbox.
  • Tool worker idle timeout: 15 minutes.

If a tool exceeds the timeout, the worker is killed and you'll see a TimeoutError. A subsequent run starts a fresh worker automatically.

What if the sandbox is offline?

If your sandbox isn't running when you click Run, the UI shows the red / orange status and the execution is blocked. Start the sandbox and try again.

For cloud sandboxes that auto‑stopped, the UI will offer to start it for you.