A lightweight code-execution sandbox that exposes a FastAPI service backed by a Jupyter Kernel Gateway and Redis (Valkey). The current codebase is adapted from https://github.com/ChenShawn/MultiModal-Jupyter-Sandbox.
flowchart TB
subgraph app["Application Layer"]
main["main.py<br/>FastAPI App"]
api["api.py<br/>API Endpoints"]
config["config.py"]
logging["logging_setup.py"]
end
subgraph jupyter["jupyter/ Package"]
init["__init__.py<br/>Public API"]
manager["manager.py<br/>KernelSessionManager"]
sessions["sessions.py<br/>SessionRegistry"]
channels["channels.py<br/>KernelChannels"]
executor["executor.py<br/>JupyterExecutor"]
gateway["gateway_http.py<br/>KernelGatewayClient"]
persistence["state_persistence.py<br/>StatePersistence"]
models["models.py<br/>ExecuteResult"]
types["types.py<br/>Protocols & TypedDicts"]
internal["internal_states.py<br/>Dump/Load Code"]
end
subgraph external["External Services"]
redis[(Redis/Valkey)]
kernel[Jupyter Gateway]
end
main --> api
main --> config
main --> logging
api --> init
init --> manager
manager --> sessions
manager --> channels
manager --> executor
sessions --> gateway
sessions --> persistence
persistence --> internal
persistence --> executor
executor --> channels
executor --> models
channels --> kernel
gateway --> kernel
persistence --> redis
sessions --> types
| Component | Description |
|---|---|
main.py |
FastAPI application entry point |
api.py |
API endpoints (/run_jupyter, /jupyter_sandbox, etc.) |
jupyter/manager.py |
Coordinates kernel sessions, channels, and execution |
jupyter/sessions.py |
Session-to-kernel mapping with LRU eviction |
jupyter/channels.py |
WebSocket connection management for kernel communication |
jupyter/executor.py |
Builds execute requests and collects output |
jupyter/gateway_http.py |
REST client for Jupyter Kernel Gateway |
jupyter/state_persistence.py |
Dumps/restores session state via Redis |
jupyter/models.py |
Pydantic models for execution results |
jupyter/types.py |
Type definitions (Protocols, TypedDicts) |
- Jupyter Kernel Gateway: Executes Python code (with GPU support)
- Redis/Valkey: Stores evicted session state for restoration
Default setup uses the Jupyter Kernel Gateway. If you need scalable compute,
deploy your own enterprise gateway and point KERNEL_GATEWAY_URL to it.
docker compose up --buildThe API will be available at http://localhost:12345.
The jupyter container is configured to use all available NVIDIA GPUs. Prerequisites:
- NVIDIA driver installed on host
- Install nvidia-container-toolkit:
sudo apt install nvidia-container-toolkit sudo systemctl restart docker
To use specific GPUs, edit docker-compose.yaml:
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 2 # use 2 GPUs
# or
device_ids: ["0", "2"] # use specific GPUs
capabilities: [gpu]The Jupyter container comes with common data science packages pre-installed (numpy, pandas, matplotlib, scikit-learn, torch, etc.). See jupyter-gateway/requirements.txt for the full list.
Execute Python code with structured output (separates result, stdout, stderr, images).
Request body:
{
"session_id": "optional-session-id",
"code": "x = 42\nprint('hello')\nx",
"timeout": 5.0
}Response body:
{
"output": {
"result": "42",
"stdout": "hello\n",
"stderr": "",
"images": ["iVBORw0KGgo..."],
"debug_info": {"msg": ""}
},
"status": "success",
"execution_time": 0.123
}| Field | Description |
|---|---|
result |
Last expression value (like Jupyter cell output) |
stdout |
print() output |
stderr |
Error messages / tracebacks |
images |
Base64-encoded images from matplotlib, etc. |
Execute Python code with combined output format.
Request body:
{
"session_id": "optional-session-id",
"code": "print('hello')",
"timeout": 5.0
}Response body:
{
"output": {
"stdout": "hello\n42\n",
"stderr": "",
"stdout_raw": "hello\n42\n",
"stderr_raw": "",
"images": ["data:image/png;base64,iVBORw0KGgo..."]
},
"status": "success",
"execution_time": 0.123
}| Field | Description |
|---|---|
stdout |
Combined print() output + expression values (ANSI stripped) |
stderr |
Error messages (ANSI stripped) |
stdout_raw |
Raw stdout with ANSI codes |
stderr_raw |
Raw stderr with ANSI codes |
images |
Images with data URI prefix |
| Feature | V1 (/jupyter_sandbox) |
V2 (/run_jupyter) |
|---|---|---|
result field |
Yes (separate) | No (merged into stdout) |
| Image format | Pure base64 | Data URI (data:image/png;base64,...) |
| ANSI codes | Stripped | Both raw and stripped available |
debug_info |
Yes | No |
Notes:
session_iddefaults toJupyterSandboxDefaultif omitted.timeoutdefaults to5.0seconds.
Clear a kernel session and delete its marker from Redis.
Request body:
{
"session_id": "optional-session-id"
}Response body:
{
"status": "success"
}Health check endpoint.
Response body:
{
"status": "ok"
}List all active and persisted sessions.
Response body:
{
"active_sessions": 2,
"max_sessions": 16,
"sessions": [
{
"session_id": "abc123",
"kernel_id": "kernel-uuid-1",
"status": "active",
"idle_seconds": 45.2
},
{
"session_id": "xyz789",
"kernel_id": null,
"status": "persisted",
"idle_seconds": null
}
]
}| Status | Description |
|---|---|
active |
Kernel is running, kernel_id and idle_seconds available |
persisted |
Kernel was evicted, state saved to Redis, will restore on next request |
Environment variables used by the FastAPI service:
KERNEL_GATEWAY_URL(required): Base URL for the Jupyter Kernel Gateway.KERNEL_GATEWAY_TOKEN(optional): Token for the Kernel Gateway auth header.REDIS_URL(optional): Full Redis connection URL.REDIS_HOST(default:valkey)REDIS_PORT(default:6379)REDIS_DB(default:0)PORT(default:12345)MAX_CONCURRENT_RUNS(default:4): Maximum concurrent code executions.MAX_ACTIVE_SESSIONS(default:MAX_CONCURRENT_RUNS): Maximum active kernel sessions. When exceeded, LRU session is evicted to Redis.
The provided docker-compose.yaml sets defaults for local usage.
- Ensure you have a running Jupyter Kernel Gateway and Redis-compatible server.
- Set
KERNEL_GATEWAY_URLand Redis settings. - Run:
uvicorn llm_codebox.main:app --host 0.0.0.0 --port 12345