Skip to main content

The Command Line

Code Sandboxes ships a Typer CLI that does two things: it RUNS code in any variant — exec for one snippet, repl for a prompt — and it MANAGES sandboxes across variants, with the same four verbs everywhere. Running comes first below, managing after it.

exec and repl create a sandbox, use it, and terminate it. Nothing is left running behind you — to keep one, see create.

For canonical variant setup details (requirements, credentials, and parameters), see Providers. For package installation and extras, see Installation.

code-sandboxes exec --variant eval 'print(40 + 2)'
code-sandboxes repl --variant jupyter-server

code-sandbox is available as an alias for the same command.

Running Code​

exec — one snippet​

The code comes from an argument, from --file, or from standard input:

code-sandboxes exec -v eval 'x = 40; x + 2'
code-sandboxes exec -v eval --file analysis.py
echo 'print("hello")' | code-sandboxes exec -v eval

The exit status is the code's own — 0 when it ran cleanly, 1 when it raised or the sandbox could not run it — so this composes in a shell. With --quiet nothing is printed but what the code produced:

if code-sandboxes exec -v eval -q 'import numpy' ; then
echo "numpy is there"
fi

repl — a prompt​

# Explicit variant
code-sandboxes repl --variant monty

# Or omit it and choose interactively
code-sandboxes repl

# Datalayer with overrides
code-sandboxes repl --variant datalayer --token "$DATALAYER_API_KEY" \
--run-url "https://prod1.datalayer.run"

State is kept between lines, and the value of an expression is shown as a REPL shows it. The prompt names the sandbox the line will run in, which matters as soon as two are open side by side:

sandbox(daytona:tan-law-5384)>>> x = 40
sandbox(daytona:tan-law-5384)>>> x + 2
42

Use any of :exit, :quit, exit, quit or Ctrl+D to leave, and :help for a reminder. On exit, the sandbox is terminated.

Examples At The Prompt​

A sandbox can carry snippets worth running in it, and the prompt offers them:

sandbox(daytona:tan-law-5384)>>> :examples

# 1. What the GPU is, straight from the driver
import subprocess
print(subprocess.run(["nvidia-smi"], capture_output=True, text=True).stdout)

# 2. A workload that actually uses it: a matmul, timed on the device
import time, torch
...

:examples:N runs one of them — 1 to 5.

Two ways to use one. Copy it into the prompt, or ask for it by number and let the prompt run it — :examples:2 prints the snippet and then executes it, so the answer arrives with its cause above it:

sandbox(daytona:tan-law-5384)>>> :examples:2
>>> code:
import time, torch
...
'312.4 TFLOP/s'

They are declared once, where the sandbox is made, because what is worth running depends on what was created — a sandbox with an H100 in it wants device discovery, one that runs in this very process wants neither:

from code_sandboxes import Sandbox, run_repl

examples = [
("What the GPU is", "import torch\ntorch.cuda.get_device_name(0)"),
("How much memory it has", "import torch\ntorch.cuda.mem_get_info()"),
]

with Sandbox.create(variant="daytona", gpu="H100", examples=examples) as sandbox:
run_repl(sandbox) # reads them off the sandbox

run_repl(sandbox, examples=[...]) still overrides them for one prompt, and :help lists both forms whenever a sandbox has any.

note

A snippet asked for by number runs as ONE execution, so it may contain a for or a def. A snippet meant to be PASTED cannot: the prompt reads a line at a time, and a block would arrive without its body. The examples that ship with this package are written to be safe either way.

Every REPL example under examples/repl ships its own set; see Examples.

Variant Selection​

Supported variants:

  • cloudflare
  • coreweave
  • datalayer
  • daytona
  • docker
  • e2b
  • eval
  • google-colab
  • jupyter-server
  • kaggle
  • modal
  • monty

exec and repl take the same options: --variant, --timeout, --environment, --gpu, --spot, and the connection settings a variant needs.

Variant-specific Behavior​

  • cloudflare: talks to a deployed sandbox bridge Worker, named by CLOUDFLARE_SANDBOX_API_URL with the CLOUDFLARE_SANDBOX_API_KEY it was deployed with. Each snippet — and each line of the REPL — runs in a process of its own, so a definition on one line is gone by the next.
  • coreweave: starts a CoreWeave sandbox and holds a session process for it, so lines share a namespace. --gpu takes a CoreWeave GPU kind; CoreWeave places a sandbox on runners of one kind only, so if several are given comma-separated the first one is used rather than walked as a fallback list.
  • daytona: starts a Daytona sandbox; --gpu takes Daytona's own flavors (H100, H200, RTX-4090, ...), several of them comma-separated to fall back along, and --spot runs on preemptible capacity.
  • e2b: starts an E2B microVM from the interpreter's own template, code-interpreter-v1. Another is named from Python with template=, and has to be built on top of it — only a template carrying a Jupyter kernel can serve this variant. State persists between lines.
  • google-colab: prompts for runtime URL, kernel ID, and proxy token.
  • jupyter-server: starts a managed local Jupyter server on a random port.
  • kaggle: supports either interactive runtime settings or credential-based batch execution.
  • modal: starts a Modal sandbox container.
  • monty: starts a Monty REPL-backed sandbox.

The Same Machinery, From Python​

The CLI has nothing of its own: exec and repl are show_and_run and run_repl, which the package exports and every example uses.

from code_sandboxes import Sandbox, run_repl, show_and_run

with Sandbox.create(variant="eval") as sandbox:
show_and_run(sandbox, "x = 40")
result = show_and_run(sandbox, "x + 2") # prints the code, then "42"
assert result.text == "42"

with Sandbox.create(variant="eval") as sandbox:
run_repl(sandbox) # the prompt, on your own sandbox

show_code, show_result and repl_prompt are exported too, for a program that wants the pieces rather than the whole.

Creating and Managing Sandboxes​

Beyond running code, sandboxes can be created, listed, inspected and deleted — from the CLI or from Python. Every variant answers the same four verbs:

VerbCLIPython
Createcode-sandboxes create -v <variant>get_manager(variant).create(**kwargs)
Read (all)code-sandboxes list [-v <variant>]get_manager(variant).list()
Read (one)code-sandboxes get <id> -v <variant>get_manager(variant).get(id)
Updatecode-sandboxes update <id> -v <variant> [...]get_manager(variant).update(id, **changes)
Deletecode-sandboxes delete <id> -v <variant>get_manager(variant).delete(id)

CLI​

# Every variant that answers, in one table
code-sandboxes list

# One variant
code-sandboxes list -v kaggle
code-sandboxes list -v modal

# One sandbox, with its live status
code-sandboxes get sb-XXXX -v modal
code-sandboxes get my-kernel-slug -v kaggle # user/slug or bare slug

# Update — what changes depends on the variant
code-sandboxes update <container> -v docker --name proud-noether
code-sandboxes update sb-XXXX -v modal --tag team=ai --tag env=dev
code-sandboxes update <runtime-uid> -v datalayer --capability gpu
code-sandboxes update my-kernel -v kaggle --code "print('v2')"

# Delete (asks for confirmation without --yes)
code-sandboxes delete sb-XXXX -v modal --yes

# Create a sandbox and leave it running, detached from this process
code-sandboxes create -v modal
code-sandboxes create -v docker
code-sandboxes create -v jupyter-server --server-url http://localhost:8888

# The environments sandboxes can be created in
code-sandboxes environments

Results are rendered as tables (via rich). When list is asked for every variant, a variant that cannot answer — no credentials, no daemon, no runtime URL — is skipped with the reason printed below the table instead of hiding the ones that answered.

Python​

from code_sandboxes import get_manager, manageable_variants

print(manageable_variants())
# ['cloudflare', 'coreweave', 'datalayer', 'daytona', 'docker', 'e2b', 'eval', 'google-colab', 'jupyter-server', 'kaggle', 'modal', 'monty']

manager = get_manager("modal")
for info in manager.list():
print(info.id, info.status)

info = manager.create() # detached: keeps running after this process
manager.delete(info.id)

Connection settings go to get_manager and stay out of the verbs:

get_manager("jupyter-server", server_url="http://localhost:8888", token="...")
get_manager("google-colab", server_url="https://...", proxy_token="...")
get_manager("modal", app_name="code-sandboxes")
get_manager("daytona", api_key="dtn_...", target="eu")
get_manager("e2b", api_key="e2b_...", domain="e2b.example.com")
get_manager("coreweave", api_key="...", base_url="https://api.cwsandbox.com")
get_manager("cloudflare", api_url="https://...workers.dev", api_key="...")
get_manager("kaggle", username="...")
get_manager("datalayer", token="...", run_url="https://...")

What each variant maps to​

VariantA sandbox isUpdate changesDelete removes
cloudflarea container of a deployed sandbox bridge— nothing in placethe Cloudflare sandbox
coreweavea sandbox of the CoreWeave organization— nothing in placethe CoreWeave sandbox
datalayera runtime of the Datalayer platformthe capabilitiesthe runtime
daytonaa sandbox of the Daytona organizationthe labelsthe Daytona sandbox
dockera container labelled code-sandboxesthe namethe container (forced)
e2ba sandbox of the E2B account— nothing in placethe E2B sandbox
eval, montyan object inside the creating process— not supported— not supported
google-colaba kernel of the Colab runtime— nothing in placethe kernel
jupyter-servera kernel of the Jupyter Server— nothing in placethe kernel
kagglea kernel on kaggle.com (batch mode creates one per run)the code (a new version)the kernel
modala Modal sandbox of the code-sandboxes appthe tagsthe Modal sandbox

Not every provider can honour every verb. A manager states what it supports through manager.capabilities and raises SandboxManagementError with the reason for the rest — an eval sandbox lives and dies inside the process that made it, so list truthfully answers [] and delete explains itself rather than silently doing nothing.

Cloudflare notes: create, get and delete are answered; list is not. The sandbox bridge exposes a sandbox by its id and has no endpoint that enumerates them, so code-sandboxes list -v cloudflare raises with that reason instead of answering with an empty list — "none" and "cannot know" are different facts, and a management tool that confuses them loses sandboxes.

Kaggle notes: list enumerates your kernels (mine=True), get adds the live run status, and create pushes a batch kernel with the given --code — creation on Kaggle is a code push. Both user/slug and a bare slug of the authenticated user are accepted as ids.