Code Sandboxes code_sandboxes is a Python package for safe, isolated environments where an AI system can write, run, and test code without affecting the real world or the user's device.
This package provides a unified API for code execution with features like:
- Code Execution: Execute Python code with streaming output and rich results
- Filesystem Operations: Read, write, list, upload, and download files
- Command Execution: Run shell commands with streaming support
- Context Management: Maintain state across multiple executions
- Snapshots: Save and restore sandbox state (Datalayer runtime)
- GPU Support: Access GPU compute for ML workloads (Datalayer runtime)
Eight variants are available. Canonical variant names are jupyter, docker,
eval, monty, kaggle, colab, modal, and datalayer. The older local-*
names are no longer supported.
| Variant | Isolation | Use Case |
|---|---|---|
jupyter |
Process (Jupyter kernel) | Persistent state, local/remote |
docker |
Container (Jupyter Server) | Local isolated execution |
eval |
None (Python exec) | Development, testing |
monty |
In-process secure interpreter | Fast, safe LLM snippets |
kaggle |
Kaggle notebook runtime | Free hosted GPU/CPU kernels |
colab |
Google Colab runtime | Free hosted GPU/CPU kernels |
modal |
Modal cloud container | On-demand isolated cloud compute |
datalayer |
Cloud VM | Production, GPU workloads |
See Backend Setup Guides below for per-variant installation, credentials, and usage.
Sandbox implementations are exposed as top-level modules:
code_sandboxes.jupyter_sandboxcode_sandboxes.docker_sandboxcode_sandboxes.eval_sandboxcode_sandboxes.monty_sandboxcode_sandboxes.kaggle_sandboxcode_sandboxes.colab_sandboxcode_sandboxes.modal_sandboxcode_sandboxes.datalayer_sandbox
Example direct imports:
from code_sandboxes.jupyter_sandbox import JupyterSandbox
from code_sandboxes.docker_sandbox import DockerSandbox
from code_sandboxes.eval_sandbox import EvalSandbox
from code_sandboxes.monty_sandbox import MontySandbox
from code_sandboxes.kaggle_sandbox import KaggleSandbox
from code_sandboxes.colab_sandbox import ColabSandbox
from code_sandboxes.modal_sandbox import ModalSandbox
from code_sandboxes.datalayer_sandbox import DatalayerSandbox# Basic installation
pip install code-sandboxes
# With Datalayer runtime support
pip install code-sandboxes[datalayer]
# With Docker support
pip install code-sandboxes[docker]
# With Kaggle support
pip install code-sandboxes[kaggle]
# With Google Colab support
pip install code-sandboxes[colab]
# With Monty (secure in-process interpreter) support
pip install code-sandboxes[monty]
# With Modal cloud sandbox support
pip install code-sandboxes[modal]
# All features
pip install code-sandboxes[all]The docker variant runs a Jupyter Server inside a Docker container and uses
jupyter-kernel-client to execute code.
Build the Docker image used by DockerSandbox:
docker build -t code-sandboxes-jupyter:latest -f docker/Dockerfile .from code_sandboxes import Sandbox
# Create a sandbox with timeout
with Sandbox.create(variant="eval", timeout=60) as sandbox:
# Execute code
result = sandbox.run_code("x = 1 + 1")
result = sandbox.run_code("print(x)") # prints 2
# Multi-statement blocks return the last expression
result = sandbox.run_code("""
x = 10
x * 2
""")
print(result.text) # "20"
# Access results
print(result.stdout) # "2"from code_sandboxes import Sandbox
# Create a cloud sandbox with GPU
with Sandbox.create(
variant="datalayer",
gpu="T4",
environment="python-gpu-env",
timeout=300,
) as sandbox:
sandbox.run_code("import torch")
result = sandbox.run_code("print(torch.cuda.is_available())")with Sandbox.create() as sandbox:
# Write files
sandbox.files.write("/data/test.txt", "Hello World")
# Read files
content = sandbox.files.read("/data/test.txt")
# List directory
for f in sandbox.files.list("/data"):
print(f.name, f.size)
# Upload/download
sandbox.files.upload("local_file.txt", "/remote/file.txt")
sandbox.files.download("/remote/file.txt", "downloaded.txt")with Sandbox.create() as sandbox:
# Run a command and wait for completion
result = sandbox.commands.run("ls -la")
print(result.stdout)
# Execute with streaming output
process = sandbox.commands.exec("python", "-c", "print('hello')")
for line in process.stdout:
print(line, end="")
# Install system packages
sandbox.commands.install_system_packages(["curl", "wget"])with Sandbox.create(variant="datalayer") as sandbox:
# Set up environment
sandbox.install_packages(["pandas", "numpy"])
sandbox.run_code("import pandas as pd; df = pd.DataFrame({'a': [1,2,3]})")
# Create snapshot
snapshot = sandbox.create_snapshot("my-setup")
print(f"Snapshot created: {snapshot.id}")
# Later: restore from snapshot
with Sandbox.create(variant="datalayer", snapshot_name="my-setup") as sandbox:
# State is restored
result = sandbox.run_code("print(df)")from code_sandboxes import Sandbox, OutputMessage
def handle_stdout(msg: OutputMessage):
print(f"[stdout] {msg.line}")
def handle_stderr(msg: OutputMessage):
print(f"[stderr] {msg.line}")
with Sandbox.create() as sandbox:
result = sandbox.run_code(
"for i in range(5): print(f'Step {i}')",
on_stdout=handle_stdout,
on_stderr=handle_stderr,
)
# Kaggle batch mode also supports streaming status/output events.
with Sandbox.create(variant="kaggle") as sandbox:
for event in sandbox.run_code_streaming("print('hello from kaggle stream')"):
if hasattr(event, "line"):
print(event.line)
### High-level Client API
`CodeSandboxClient` provides a variant-agnostic facade with normalized outcomes.
It is useful in higher-level systems that need a stable API across all sandbox
engines.
```python
from code_sandboxes import Sandbox, CodeSandboxClient
with Sandbox.create(variant="kaggle") as sandbox:
client = CodeSandboxClient(sandbox)
# One-shot normalized outcome.
outcome = client.execute_code("print('hello')")
print(outcome.success, outcome.stdout, outcome.stderr)
# Stream normalized events (sync).
for event in client.execute_code_streaming("print('streaming')"):
if hasattr(event, "line"):
print(event.line)import asyncio
from code_sandboxes import Sandbox, CodeSandboxClient
async def main():
with Sandbox.create(variant="kaggle") as sandbox:
client = CodeSandboxClient(sandbox)
async for event in client.execute_code_streaming_async("print('async stream')"):
if hasattr(event, "line"):
print(event.line)
asyncio.run(main())
## CLI REPL
`sandbox` includes a Typer-based CLI that launches an interactive REPL
against a selected sandbox variant and always terminates created resources on exit.
The `code-sandboxes` command remains available as an alias.
```bash
sandbox repl --variant jupyter
sandbox repl --variant monty
sandbox repl --variant modal
sandbox repl --variant colab
If --variant is omitted, the CLI prompts for one.
Variant notes:
jupyter: starts a managed local Jupyter server on a random port.kaggle: supports interactive runtime mode and batch mode (credentials based).monty: starts a Monty REPL-backed sandbox.modal: starts a Modal sandbox container.colab: prompts for runtime URL, kernel ID, and proxy token.
Exit with :exit, :quit, or Ctrl+D.
Each backend has its own installation, credential, and parameter requirements.
Select a backend by passing variant=... to Sandbox.create(). The sections
below explain, for every variant, exactly how to obtain the credentials and the
parameters you need to pass.
Runs code out-of-process against a local or remote Jupyter Server via the Jupyter
kernel protocol (jupyter-kernel-client), providing process isolation and
persistent kernel state.
Install (included by default):
pip install code-sandboxesParameters:
| Parameter | Description |
|---|---|
server_url |
Jupyter Server URL (default: an auto-started local server) |
token |
Jupyter Server authentication token |
host / port |
Bind address when the sandbox starts its own server |
python_executable |
Interpreter used to launch the managed server |
How to obtain the token:
- If you start the server yourself, you choose the token:
jupyter server --port 8888 --IdentityProvider.token MY_TOKEN
- For an already-running server, print the URL + token with:
The
jupyter server list # http://localhost:8888/?token=abcd1234... :: /home/you/notebookstoken=...query value is your token. You can also pass the full URL asserver_url(the?token=...is parsed automatically). - If you omit
server_urlentirely,JupyterSandboxstarts and manages its own local Jupyter Server and generates the token for you — no configuration needed.
Usage:
from code_sandboxes import Sandbox
# Connect to an existing server:
with Sandbox.create(
variant="jupyter",
server_url="http://localhost:8888",
token="MY_TOKEN",
) as sandbox:
sandbox.run_code("x = 40")
print(sandbox.run_code("x + 2").text) # 42
# Or let the sandbox manage a local server automatically:
with Sandbox.create(variant="jupyter") as sandbox:
print(sandbox.run_code("1 + 1").text) # 2Runs a Jupyter Server inside a Docker container for local, isolated execution and
connects to it with jupyter-kernel-client.
Install:
pip install code-sandboxes[docker]Prerequisites — verify Docker is installed and running:
docker version # must succeed (daemon reachable)Build the image used by DockerSandbox (default tag
code-sandboxes-jupyter:latest):
docker build -t code-sandboxes-jupyter:latest -f docker/Dockerfile .Parameters (no external credentials — the kernel token is generated
automatically):
| Parameter | Description |
|---|---|
image |
Container image to run (default code-sandboxes-jupyter:latest) |
container_name |
Optional fixed container name |
host / container_port |
Where the in-container server is exposed |
auto_remove |
Remove the container on stop (default True) |
workdir |
Host working directory to mount |
Usage:
from code_sandboxes import Sandbox
with Sandbox.create(
variant="docker",
image="code-sandboxes-jupyter:latest",
) as sandbox:
result = sandbox.run_code("import sys; print(sys.version)")
print(result.stdout)Executes code in the host process with Python's exec(). No isolation — intended
for development and testing only.
Install (included by default):
pip install code-sandboxesCredentials / parameters: none. There is nothing to configure.
Usage:
from code_sandboxes import Sandbox
with Sandbox.create(variant="eval") as sandbox:
sandbox.run_code("x = 1 + 1")
print(sandbox.run_code("print(x)").stdout) # 2
⚠️ evalshares memory with your process and provides no sandboxing. Never run untrusted code with it — usemonty,docker,modal, ordatalayerinstead.
Runs code in Monty, a minimal, secure Python
interpreter written in Rust (pydantic-monty). Monty executes a restricted
subset of Python in-process with microsecond startup and no access to the host
filesystem, environment, or network unless explicitly granted. Ideal for short,
LLM-generated snippets. Session state persists across run_code calls.
Install:
pip install code-sandboxes[monty]Credentials / parameters: none required (fully local, in-process). Optional
constructor parameters on MontySandbox:
| Parameter | How to obtain / when to use |
|---|---|
type_check |
Set True to type-check code before running it |
type_check_stubs |
Provide type stub definitions when type_check is enabled |
external_functions |
Dict of {name: callable} host functions the code may call |
limits |
Monty ResourceLimits mapping (memory, stack depth, time) |
Usage:
from code_sandboxes import Sandbox
with Sandbox.create(variant="monty") as sandbox:
sandbox.run_code("x = 21")
print(sandbox.run_code("x * 2").text) # 42
# Expose host callables and enable type checking:
from code_sandboxes.monty_sandbox import MontySandbox
sandbox = MontySandbox(
type_check=True,
external_functions={"now": lambda: "2026-01-01"},
)
sandbox.start()
sandbox.run_code("print(now())")Monty supports only a subset of Python — third-party libraries and rich display outputs are not available.
Runs code against Kaggle with two transparent modes:
- Interactive kernel mode via
jupyter-kernel-client'sKaggleKernelClient(connect/create kernel on a runtime proxy). - Batch job mode via
jupyter-kernel-client'sKaggleKernelExecutor(submit code as a Kaggle notebook job and return logs/results).
This makes the kaggle sandbox usable directly from higher-level systems such
as jupyter-mcp-server without requiring special routing logic.
Interactive-kernel authentication supports:
- API token (default). Provide a Kaggle API token via
tokenor theKAGGLE_API_TOKENenvironment variable. Whenkernel_idis omitted, a new kernel is created on the runtime. - Signed proxy URL. Connect to an already-running notebook session using its
server_urlandkernel_id; the signed JWT embedded in the proxiedserver_urlprovides the authentication (no token needed).
Install:
pip install code-sandboxes[kaggle]Parameters:
| Parameter | Description |
|---|---|
server_url |
The Kaggle runtime proxy URL (ending in /proxy) for interactive mode |
kernel_id |
The kernel identifier (omit to create a new kernel with a token in interactive mode) |
channels_url |
A notebook session channels URL to parse server_url/kernel_id from |
token |
Kaggle API token for interactive kernel mode (falls back to KAGGLE_API_TOKEN) |
gpu / accelerator |
Optional batch-mode accelerator. Supports Kaggle API values (NvidiaTeslaT4, NvidiaTeslaP100, NvidiaTeslaT4Highmem, NvidiaL4, NvidiaL4X1, NvidiaTeslaA100, NvidiaH100, NvidiaRtxPro6000) and friendly aliases (T4, P100, A100, H100). |
For batch mode (no server_url/channels_url), configure credentials as
the official kaggle package expects (~/.kaggle/kaggle.json or
KAGGLE_USERNAME + KAGGLE_KEY).
Obtaining connection values — to connect to an existing session, the
server_url / kernel_id come from an active browser session. The official
Kaggle API (kaggle CLI / kagglehub) only exposes batch kernel operations
(push/pull/status/output) for running notebooks as jobs, not an interactive
WebSocket kernel. Read the values from the WebSocket channels URL:
wss://kkb-production.jupyter-proxy.kaggle.net/k/<n>/<jwt>/proxy/api/kernels/<kernel_id>/channels?session_id=<...>
- Open your notebook on kaggle.com and start a session (run any cell).
- Open DevTools (
F12) → Network tab, select the WS filter (or typechannels), then run a cell to trigger kernel traffic. - Click the
.../proxy/api/kernels/<kernel_id>/channels?...request and copy its URL. The signed JWT in the/k/<n>/<jwt>/proxypath segment carries the authentication. These values are tied to your session and are short-lived — refresh them after reconnecting.
Usage:
import os
from code_sandboxes import Sandbox
# Option A: create a kernel with a Kaggle API token (omit kernel_id).
os.environ["KAGGLE_API_TOKEN"] = "..." # or export it in your shell
with Sandbox.create(
variant="kaggle",
server_url="https://kkb-production.jupyter-proxy.kaggle.net/k/12345678/eyJ.../proxy",
) as sandbox:
sandbox.run_code("x = 40")
print(sandbox.run_code("x + 2").text) # 42
# Option B: pass an existing session's channels URL and let the sandbox parse it.
with Sandbox.create(
variant="kaggle",
channels_url="wss://kkb-production.jupyter-proxy.kaggle.net/k/12345678/eyJ.../proxy/api/kernels/11e073f0-.../channels?session_id=...",
) as sandbox:
print(sandbox.run_code("print(1 + 1)").text)
# Option C: pass the server_url and kernel_id explicitly.
with Sandbox.create(
variant="kaggle",
server_url="https://kkb-production.jupyter-proxy.kaggle.net/k/12345678/eyJ.../proxy",
kernel_id="11e073f0-e82d-4029-be8d-3918f7ed1a9e",
) as sandbox:
print(sandbox.run_code("print(1 + 1)").text)
# Option D: transparent batch mode (no runtime URL needed).
# Requires kaggle.json or KAGGLE_USERNAME/KAGGLE_KEY credentials.
with Sandbox.create(variant="kaggle") as sandbox:
result = sandbox.run_code("print('hello from kaggle batch')")
print(result.text or result.stdout)
# Option E: batch mode with a specific accelerator.
with Sandbox.create(variant="kaggle", gpu="T4") as sandbox:
result = sandbox.run_code("import torch; print(torch.cuda.is_available())")
print(result.text or result.stdout)
# Option F: stream batch progress + outputs.
with Sandbox.create(variant="kaggle") as sandbox:
for event in sandbox.run_code_streaming("print('hello from kaggle stream')"):
if hasattr(event, "line"):
print(event.line)Note: Kaggle free-tier availability usually includes
P100andT4. Accelerators likeA100,H100, andL4are often restricted to specific competitions or internal Kaggle workloads.
Runs code against a Google Colab runtime. Colab exposes a Jupyter-compatible
kernel behind an authenticating proxy, so this variant connects using
jupyter-kernel-client's ColabKernelClient.
Install:
pip install code-sandboxes[colab]Parameters:
| Parameter | Description |
|---|---|
server_url |
The Colab runtime proxy/tunnel URL |
kernel_id |
The assigned kernel identifier |
proxy_token |
The colab-runtime-proxy-token value |
channels_url |
Optional Colab channels URL to parse the above values from |
How to obtain these values — they are the pieces of the WebSocket URL that Colab's own frontend uses to reach your assigned runtime:
wss://<host>/api/kernels/<kernel_id>/channels?session_id=<...>&colab-runtime-proxy-token=<proxy_token>&colab-client-agent=web
Read them from your browser's developer tools:
- Open your notebook on colab.research.google.com and connect to a runtime (Runtime → Connect, or run any cell).
- Open DevTools (
F12) → Network tab, select the WS filter (or typekernels), then run a cell to trigger kernel traffic. - Click the
.../api/kernels/<kernel_id>/channels?...request and read off:server_url— scheme + host before/api/kernels(changewss://tohttps://). Colab assigns a per-session host such ashttps://8080-m-s-kkb-...-d.us-east1-0.prod.colab.dev; there is usually no/tun/m/...path segment.kernel_id— the UUID segment right after/api/kernels/.proxy_token— thecolab-runtime-proxy-tokenquery parameter (same value as theX-Colab-Runtime-Proxy-Tokenrequest header). Ignore thesession_idandcolab-client-agentparameters.
Consumer Colab does not expose an official third-party API to provision runtimes from scratch. Start/connect a runtime in the Colab UI first, then reuse it here. The values are tied to your Colab session and are short-lived — refresh them after the runtime is reassigned or reconnected.
Usage:
from code_sandboxes import Sandbox
with Sandbox.create(
variant="colab",
server_url="https://8080-m-s-kkb-...-d.us-east1-0.prod.colab.dev",
kernel_id="c9bba548-3995-4f26-8e1a-7b8fbb10c578",
proxy_token="eyJhbGci....",
) as sandbox:
sandbox.run_code("x = 40")
print(sandbox.run_code("x + 2").text) # 42You can also pass the channels URL directly and let the sandbox parse it:
from code_sandboxes import Sandbox
with Sandbox.create(
variant="colab",
channels_url=(
"wss://<host>/api/kernels/<kernel_id>/channels"
"?session_id=<...>&colab-runtime-proxy-token=<proxy_token>&colab-client-agent=web"
),
) as sandbox:
print(sandbox.run_code("print(1 + 1)").text)Runs code in a Modal cloud sandbox, providing fully isolated, on-demand containers with configurable images and secrets.
Install:
pip install code-sandboxes[modal]How to obtain Modal credentials:
-
Create a free account at modal.com.
-
Authenticate the CLI — this opens a browser and writes credentials to
~/.modal.toml:modal token new
This is enough for local use: the Modal SDK reads credentials from
~/.modal.tomlautomatically. -
Alternatively, create a token in the Modal dashboard (Settings → API Tokens) and export it as environment variables:
Environment variable Description MODAL_TOKEN_IDModal token id (starts with ak-)MODAL_TOKEN_SECRETModal token secret (starts with as-)
Do you need both MODAL_TOKEN_ID and MODAL_TOKEN_SECRET?
- For environment-based auth (CI/CD, containers, hosted runners): yes, you need both values because Modal authenticates with a token pair (public id + secret).
- For local development with
modal token new: not necessarily. The SDK can authenticate directly from~/.modal.toml.
If you need to export environment variables from your local Modal config, you can
read them from ~/.modal.toml:
python - <<'PY'
import pathlib
import tomllib
cfg = tomllib.loads(pathlib.Path("~/.modal.toml").expanduser().read_text())
profile = cfg.get("default", cfg)
token_id = profile.get("token_id")
token_secret = profile.get("token_secret")
if token_id and token_secret:
print(f"export MODAL_TOKEN_ID={token_id}")
print(f"export MODAL_TOKEN_SECRET={token_secret}")
else:
raise SystemExit("Could not find token_id/token_secret in ~/.modal.toml")
PYParameters: app_name, image (a prebuilt modal.Image), pip_packages
(extra packages for the default image), python_executable.
Usage:
from code_sandboxes import Sandbox
with Sandbox.create(
variant="modal",
pip_packages=["numpy"],
) as sandbox:
result = sandbox.run_code("import numpy as np; print(np.arange(3).sum())")
print(result.stdout) # "3"Each
run_codecall runs in a freshpython -cprocess, so state does not persist across calls. Use a single multi-statement snippet when you need shared state.
Cloud-based execution with full isolation, GPU support, snapshots, and
persistence via the Datalayer runtime, powered by the
agent_runtimes package.
Install:
pip install code-sandboxes[datalayer]This extra installs agent_runtimes, which provides the runtime client used by
the datalayer sandbox variant.
How to obtain Datalayer credentials:
-
Create an account at datalayer.ai.
-
Generate an API token from your account settings (IAM → Tokens / API Keys).
-
Export it (or pass it as the
tokenparameter):Environment variable Description DATALAYER_API_KEYAPI key for Datalayer runtime authentication DATALAYER_RUN_URLCustom Datalayer service URL (optional, for self-hosted)
Parameters: token (defaults to DATALAYER_API_KEY), run_url,
snapshot_name, plus creation options like environment, gpu, cpu, memory.
Usage:
import os
from code_sandboxes import Sandbox
os.environ["DATALAYER_API_KEY"] = "your-datalayer-token"
with Sandbox.create(
variant="datalayer",
gpu="A100",
environment="python-gpu-env",
timeout=300,
) as sandbox:
sandbox.run_code("import torch")
print(sandbox.run_code("print(torch.cuda.is_available())").stdout)Factory method to create sandboxes:
sandbox = Sandbox.create(
variant="datalayer", # Sandbox type
timeout=60, # Execution timeout (seconds)
environment="python-cpu-env", # Runtime environment
gpu="T4", # GPU type (T4, A100, H100, etc.)
cpu=2.0, # CPU cores
memory=4096, # Memory in MB
env={"MY_VAR": "value"}, # Environment variables
network_policy="none", # Network access policy
allowed_hosts=["localhost"], # Allowlist when policy is allowlist
tags={"project": "demo"}, # Metadata tags
)
# Network policies:
# - inherit: default behavior for the sandbox variant
# - none: block all outbound connections
# - allowlist: allow only hosts in allowed_hosts
# - all: allow all outbound connectionsresult = sandbox.run_code("print('hello')")
result.success # bool: Whether execution succeeded
result.stdout # str: Standard output
result.stderr # str: Standard error
result.text # str: Main result text
result.results # list[Result]: Rich results (HTML, images, etc.)
result.code_error # CodeError: Error details if failed
result.execution_ok # bool: Infrastructure execution status
result.execution_error # str | None: Infrastructure error details
result.exit_code # int | None: Exit code if code called sys.exit()
# Error handling
if not result.execution_ok:
print(f"Sandbox failed: {result.execution_error}")
elif result.exit_code not in (None, 0):
print(f"Process exited with code: {result.exit_code}")
elif result.code_error:
print(f"Python error: {result.code_error.name}: {result.code_error.value}")
else:
print(result.text)| Method | Description |
|---|---|
Sandbox.create() |
Create a new sandbox |
Sandbox.from_id(id) |
Reconnect to an existing sandbox |
Sandbox.list() |
List all sandboxes |
sandbox.run_code(code) |
Execute Python code |
sandbox.files.read(path) |
Read file contents |
sandbox.files.write(path, content) |
Write file contents |
sandbox.files.list(path) |
List directory contents |
sandbox.commands.run(cmd) |
Run shell command |
sandbox.commands.exec(*args) |
Execute with streaming output |
sandbox.set_timeout(seconds) |
Update timeout |
sandbox.create_snapshot(name) |
Save sandbox state |
sandbox.terminate() / sandbox.kill() |
Stop sandbox |
DATALAYER_API_KEY: API key for Datalayer runtime authentication
from code_sandboxes import SandboxConfig
config = SandboxConfig(
timeout=30.0, # Default execution timeout
environment="python-cpu-env",
memory_limit=4 * 1024**3, # 4GB
cpu_limit=2.0,
gpu="T4",
working_dir="/workspace",
env_vars={"DEBUG": "1"},
max_lifetime=3600, # 1 hour
)
sandbox = Sandbox.create(config=config)Run the local test suite:
pytest tests/Required environment variables for tests:
- None for the default local suite (
eval, factory, model, and local Jupyter tests).
Optional environment variables for cloud-integration smoke tests:
DATALAYER_API_KEY: required only when running Datalayer runtime smoke tests.DATALAYER_RUN_URL: optional custom Datalayer runtime URL.DATALAYER_ENVIRONMENT: optional environment override (for exampleai-agents-env).MODAL_TOKEN_ID/MODAL_TOKEN_SECRET: required only if you add or run Modal integration tests.
This repository uses a reusable GitHub Actions workflow at .github/workflows/reusable-python.yml.
The following workflows call it:
.github/workflows/build.yml.github/workflows/py-tests.yml.github/workflows/py-code-style.yml.github/workflows/py-typing.yml
Reusable workflow inputs:
python-version: Python version to run.install-system-deps: Install Linux dependencies and unlock keyring.install-extras: Extras frompyproject.toml(for exampletest,typing).extra-packages: Additional packages installed withuv pip install.run-tests: Enable test execution.test-command: Command used for tests.run-mypy: Enable mypy.mypy-target: Package or module passed to mypy.run-pre-commit: Enable pre-commit checks.
Copyright (c) 2025-2026 Datalayer, Inc.
BSD 3-Clause License