Modal-style sandbox API on top of Hugging Face Jobs.
from hf_sandbox import Sandbox
sb = Sandbox.create(image="python:3.12")
proc = sb.exec("python", "-c", "print(1+1)") # → CompletedProcess(stdout='2\n', returncode=0, ...)
sb.write_file("/tmp/foo.txt", "hello")
print(sb.read_file("/tmp/foo.txt")) # → 'hello'
sb.terminate()Sandbox.create() launches an HF Job that:
pip installs a tiny FastAPI RPC server (FastAPI + uvicorn)- starts the server on
localhost:8000 - declares port 8000 as exposed on the Job (
expose=[8000]), so the HF Jobs proxy registershttps://<job_id>--8000.hf.jobs
The client computes the URL from the Job id and talks to the sandbox over plain HTTPS through the Jobs proxy.
exec, write_file, read_file are simple authenticated POSTs.
terminate() cancels the job.
pip install hf-sandboxRequires hf auth login (the same token authenticates against the Jobs proxy and, opt-in, is forwarded to the sandbox so it can access HF Hub).
- Image must have Python +
pip(used to install the RPC server).
The sandbox runs untrusted code by design. A few things to be aware of:
- HF token forwarding is opt-in. By default, your HF token is not exposed to the sandbox. Pass
forward_hf_token=TruetoSandbox.create()if your workload needs it. With it enabled, anything running inside the sandbox can read the token from/proc/self/environand use it to act as you on the Hub. - Traffic stays on Hugging Face infrastructure. Requests reach the sandbox through the HF Jobs proxy and require an HF token with read access to the job's namespace; the sandbox URL alone (
https://<job_id>--8000.hf.jobs) is unauthenticated and returns 401. - Sandbox token is a 256-bit random URL-safe string per sandbox, sent as
X-Sandbox-Tokenon every authenticated endpoint and validated by the in-pod RPC server. Defends against namespace-mates being able to reach your sandbox once they pass the proxy.
hf-sandbox reports anonymous usage data to help us understand how the library is used. Two events are sent per sandbox:
hf-sandbox/create— flavor, timeout, whetherforward_hf_tokenwas set, and a random per-sandbox session idhf-sandbox/terminate— same session id, duration in seconds, and termination reason
We never send: the image name, commands, file paths, file contents, the tunnel URL, the auth token, your HF token, your username, or anything from inside the sandbox.
Disable by setting HF_HUB_DISABLE_TELEMETRY=1 (or DO_NOT_TRACK=1).