Documentation · Quick Start · Issues
Boxer is a sandboxed container execution service backed by gVisor. It exposes a simple HTTP API for running arbitrary commands inside any container image, with strong isolation guarantees and configurable resource limits.
Running untrusted code is a hard problem. Docker alone provides namespace isolation but shares the host kernel - a compromised container can exploit kernel vulnerabilities and escape. Boxer wraps every execution in gVisor's user-space kernel (runsc), which intercepts and validates all system calls before they reach the host. The attack surface is dramatically reduced.
This makes Boxer a good fit for:
- LLM training and inference pipelines - execute model-generated code safely without exposing your host to arbitrary syscalls
- Decentralized oracle evaluations - run untrusted verification scripts submitted by network participants
- Prediction markets and agent frameworks - evaluate outcomes by executing code from unknown sources
- Code execution as a service - any scenario where you need to run unstructured, user-supplied, or LLM-generated code at scale
- A client sends a
POST /runrequest with a container image, command, optional files, and resource limits. - Boxer pulls and caches the image rootfs locally (shared read-only across executions).
- It constructs a hardened OCI bundle and spawns
runsc(gVisor) to execute the command. - Stdout, stderr, wall time, and exit code are returned in the response.
Files can be uploaded before a run and bind-mounted read-only inside the container. Output files written to /output/ inside the container are captured and retrievable after the run.
docker run -d --privileged -p 8080:8080 theonekeyg/boxerOr with Docker Compose:
# Replace "main" with the version tag you want to deploy, e.g. refs/tags/v1.0.0
curl -fsSL https://raw.githubusercontent.com/theonekeyg/boxer/main/docker-compose.prod.yml -o docker-compose.prod.yml
docker compose -f docker-compose.prod.yml up -dWhy
--privileged? Boxer manages cgroups and network namespaces and spawns gVisor to sandbox each execution. See the Docker installation guide for details.
Prerequisites: gVisor runsc in PATH, Go 1.22+
cd packages/core
go run . --config config.dev.jsonThe server listens on :8080 by default. Configuration can also be set via $BOXER_CONFIG or ~/.boxer/config.json.
pip install boxer-sdkfrom boxer import BoxerClient
with BoxerClient("http://localhost:8080") as client:
result = client.run(
image="python:3.12-slim",
cmd=["python3", "-c", "print('hello world')"],
)
print(result.stdout) # hello world
print(result.exit_code) # 0
print(result.wall_ms) # e.g. 312See packages/sdk/python for the full SDK reference including async support, file upload/download, resource limits, and error handling.
npm install boxer-sdkimport { BoxerClient } from "boxer-sdk";
const client = new BoxerClient({ baseUrl: "http://localhost:8080" });
const result = await client.run(
"python:3.12-slim",
["python3", "-c", "print('hello world')"],
);
console.log(result.stdout); // hello world
console.log(result.exit_code); // 0
console.log(result.wall_ms); // e.g. 312See packages/sdk/typescript for the full SDK reference including file upload/download, resource limits, and error handling.
curl -s http://localhost:8080/run \
-H 'Content-Type: application/json' \
-d '{"image":"python:3.12-slim","cmd":["python3","-c","print(42)"]}'Swagger UI is available at http://localhost:8080/swagger.
Minimal Python script that runs a sandboxed "hello world" via the Boxer SDK. Good starting point for understanding the basic client flow.
Uploads a local Python project (source + tests) to Boxer and runs its pytest suite inside a sandboxed container. Demonstrates the file upload workflow and output capture.
Evaluates OpenAI's o3-mini on the HumanEval benchmark (164 code-generation problems). Each LLM-generated solution is executed inside the Boxer sandbox and scored by exit code. A real-world example of using Boxer in an LLM evaluation pipeline.
Before writing any code, please check the open issues. If your bug report, feature request, or proposal is not already tracked there, open an issue first and describe what you want to do. Once the issue is confirmed, open a pull request that references it.
This keeps discussion focused, avoids duplicate work, and ensures effort is spent on changes that will be accepted.