Skip to main content
Execute code in an isolated Docker container with strict resource limits, network controls, and output sanitization.
isol8 run [file] [options]

Input Resolution

Code is resolved from three sources, checked in priority order. The first match wins:
  1. --eval flag — Inline code string passed directly on the command line. Defaults to python runtime if --runtime is not specified.
  2. File argument — Path to a script file. The runtime is auto-detected from the file extension via RuntimeRegistry.detect(). Use --runtime to override.
  3. Stdin — Piped input read from process.stdin. Defaults to python runtime if --runtime is not specified.

Extension-to-Runtime Mapping

When a file argument is provided without --runtime, the runtime is auto-detected from the file extension:
ExtensionRuntime
.pypython
.js, .mjs, .cjsnode
.tsbun
.mtsdeno
.shbash
If the extension doesn’t match any registered adapter, the CLI exits with an error and asks you to use --runtime.

Options

Code Input

--eval, -e
string
Execute inline code string. Defaults to python runtime if --runtime is not specified.
--runtime, -r
string
Force runtime: python, node, bun, deno, or bash. Overrides auto-detection from file extension.
--stdin
string
Data to pipe to the process via stdin. This is input to the running program, not the source code itself. The data is written to a file inside the container and piped into the command via cat.
--install
string
Install a package before execution using the runtime’s package manager. Repeatable — use --install pkg1 --install pkg2 for multiple packages.

Execution

--persistent
boolean
default:"false"
Use a persistent container that preserves state between runs. Without this flag, each execution uses a fresh container from the warm pool. In persistent mode, the CLI creates a RemoteIsol8 session (when --host is used) with a unique sessionId, or a local DockerIsol8 in persistent mode.
--persist
boolean
default:"false"
Keep the container running after execution completes, instead of cleaning it up. Useful for debugging — you can inspect the container’s filesystem, processes, and state after a run. Note: this is different from --persistent, which keeps a container alive between runs for stateful sessions.
--debug
boolean
default:"false"
Enable debug logging for internal engine operations. When set, isol8 prints detailed logs about container lifecycle, pool operations, persist decisions, and other internal state. These logs use the [DEBUG] prefix and are suppressed by default.
--no-stream
boolean
default:"false"
Disable real-time output streaming. By default, output is streamed as it is generated. Use this flag to buffer output and display it only after execution completes.
--timeout
number
default:"30000"
Execution timeout in milliseconds. The process is killed with SIGKILL via the timeout -s KILL wrapper when the limit is reached. Falls back to config.defaults.timeoutMs.

Resource Limits

--memory
string
default:"512m"
Memory limit for the container. Accepts Docker memory format: 256m, 512m, 1g, 2g. Falls back to config.defaults.memoryLimit.
--cpu
number
default:"1.0"
CPU limit as a fraction of one core. 0.5 = half a core, 2.0 = two cores. Converted to Docker NanoCpus internally. Falls back to config.defaults.cpuLimit.
--pids-limit
number
default:"64"
Maximum number of processes (PIDs) allowed inside the container. Prevents fork bombs.
--sandbox-size
string
default:"64m"
Size of the /sandbox tmpfs mount. Increase for data-intensive workloads that write large files. Accepts Docker size format: 64m, 128m, 256m.
--max-output
number
default:"1048576"
Maximum output size in bytes before truncation. Default is 1MB (1,048,576 bytes). When exceeded, output is truncated and result.truncated is set to true.

Security

--net
string
default:"none"
Network mode for the container:
  • none — No network access (default, most secure). Container is created with NetworkDisabled: true.
  • host — Full host network access. Container uses NetworkMode: "host".
  • filtered — Bridge network with an HTTP/HTTPS filtering proxy. Container gets NetworkMode: "bridge" with HTTP_PROXY/HTTPS_PROXY env vars pointing to the internal proxy.mjs process.
--allow
string
Whitelist regex pattern for filtered network mode. Only hostnames matching the pattern are allowed through the proxy. Repeatable — use --allow pattern1 --allow pattern2 for multiple patterns. Falls back to config.network.whitelist.
--deny
string
Blacklist regex pattern for filtered network mode. Hostnames matching the pattern are blocked by the proxy. Repeatable — use --deny pattern1 --deny pattern2 for multiple patterns. Falls back to config.network.blacklist.
--image
string
Override the Docker image used for execution. Bypasses the runtime adapter’s default image and the resolveImage() custom image check entirely.
--writable
boolean
default:"false"
Disable read-only root filesystem. By default, containers run with ReadonlyRootfs: true and writable tmpfs mounts at /sandbox and /tmp. Enable this flag if your code needs to write outside those directories.
--secret
string
Secret environment variable in KEY=VALUE format. The value is injected into the container as an env var and automatically masked with *** in all stdout and stderr output. Repeatable — use --secret KEY1=val1 --secret KEY2=val2 for multiple secrets.

Output

--out
string
Write stdout to a local file instead of printing to the terminal. The output is still displayed on the terminal — this writes an additional copy to the specified file path.

Remote Execution

--host
string
Execute on a remote isol8 server instead of local Docker. Provide the server URL (e.g. http://localhost:3000). The CLI creates a RemoteIsol8 client that sends the execution request over HTTP.
--key
string
API key for remote server authentication. Required when using --host. Falls back to the $ISOL8_API_KEY environment variable. The CLI exits with an error if neither is set.

Package Installation

The --install flag uses the runtime’s native package manager to install packages before code execution:
RuntimeInstall CommandExample
pythonpip install --no-cache-dir --break-system-packages--install numpy
nodenpm install -g--install lodash
bunbun install -g--install zod
denodeno cache--install https://deno.land/std/path/mod.ts
bashapk add --no-cache--install jq
Packages are installed inside the container before code execution begins. For frequently used packages, consider using isol8 setup --python numpy,pandas to bake them into a custom image instead.

Examples

Basic Execution

# Inline Python (default runtime)
isol8 run -e "print(2 ** 10)"

# Inline with explicit runtime
isol8 run -e "console.log('hello')" --runtime node

# Run a file (runtime auto-detected from extension)
isol8 run script.py
isol8 run app.js
isol8 run handler.ts   # Uses bun runtime

# Pipe code via stdin
echo "console.log('hello')" | isol8 run --runtime node

# Pipe code from a file via stdin
cat script.py | isol8 run --runtime python

Real-Time Streaming

# Watch output as it happens
isol8 run long_task.py --stream

# Stream inline code
isol8 run -e "import time; print('start'); time.sleep(1); print('done')" --runtime python --stream

Package Installation

# Single package
isol8 run -e "import numpy; print(numpy.array([1,2,3]))" --runtime python --install numpy

# Multiple packages (repeat the flag)
isol8 run -e "import pandas; import numpy" --runtime python \
  --install numpy --install pandas

# Node.js with lodash
isol8 run -e "const _ = require('lodash'); console.log(_.chunk([1,2,3,4], 2))" \
  --runtime node --install lodash

Resource Configuration

# High memory for data processing
isol8 run script.py --memory 2g --sandbox-size 256m --timeout 60000

# Limited CPU
isol8 run -e "while True: pass" --runtime python --cpu 0.5 --timeout 5000

# Large output allowance
isol8 run generate_report.py --max-output 10485760

# Limit processes to prevent fork bombs
isol8 run script.sh --pids-limit 16

Secrets

# Secret is injected as env var and masked in all output
isol8 run -e "import os; print(os.environ['API_KEY'])" \
  --runtime python --secret API_KEY=sk-1234
# stdout: ***

# Multiple secrets
isol8 run script.py \
  --secret DB_PASSWORD=hunter2 \
  --secret API_TOKEN=tok_abc123

Network Filtering

# Allow only specific API endpoints
isol8 run script.py --net filtered --allow "^api\.openai\.com$"

# Allow multiple domains
isol8 run script.py --net filtered \
  --allow "^api\.openai\.com$" \
  --allow "^cdn\.jsdelivr\.net$"

# Block specific domains
isol8 run script.py --net filtered --deny ".*\.ru$"

# Full network access (use with caution)
isol8 run script.py --net host

Persistent Sessions

# Step 1: Create data in the sandbox
isol8 run --persistent -e \
  "import json; json.dump({'count': 42}, open('/sandbox/data.json', 'w'))" \
  --runtime python

# Step 2: Read it back (same container, data persists)
isol8 run --persistent -e \
  "import json; print(json.load(open('/sandbox/data.json')))" \
  --runtime python
In persistent mode, each container is locked to a single runtime. Attempting to switch runtimes (e.g. running Python after Node.js in the same persistent session) throws an error: “Cannot switch runtime from “node” to “python”. Each persistent container supports a single runtime. Create a new Isol8 instance for a different runtime.”

Remote Execution

# Execute on a remote isol8 server
isol8 run -e "print('hello')" --host http://remote-server:3000 --key my-api-key

# Using environment variable for the key
export ISOL8_API_KEY=my-api-key
isol8 run script.py --host http://remote-server:3000

# Remote persistent session
isol8 run --persistent -e "x = 42" --runtime python \
  --host http://remote-server:3000 --key my-api-key
The --net flag defaults to "none" at the Commander level, which means the config file’s defaults.network value is effectively ignored when using the CLI. To use a different network mode, pass --net explicitly (e.g. --net filtered or --net host).

FAQ

What is the difference between --persist and --persistent?

  • --persistent keeps a container alive between runs so that state (files, environment) is preserved across multiple executions. This is for stateful workflows where you want to build up state incrementally.
  • --persist keeps the container running after execution completes, instead of cleaning it up. This is a debugging tool — it lets you inspect the container’s filesystem, logs, and processes post-execution.
You can use both together: --persistent --persist gives you a stateful session whose container is not cleaned up when stop() is called.

What does --debug do?

--debug enables verbose internal logging from the isol8 engine. It prints messages about container pool operations, container lifecycle events, and cleanup decisions with a [DEBUG] prefix. It does not affect the executed code’s output — only isol8’s own internal logs.

What happens with different flag combinations?

--persist--debugBehavior
falsefalseDefault. Containers are cleaned up silently after execution.
falsetrueContainers are cleaned up after execution, but internal engine logs are printed.
truefalseContainers are left running after execution for inspection. No debug logs.
truetrueContainers are left running after execution, and internal engine logs are printed.

How is --persist different from cleanup.autoPrune in the config?

  • --persist (engine-level): Controls per-execution container cleanup. When true, the container used for that execution is not destroyed.
  • cleanup.autoPrune (config-level): Controls whether the server (isol8 serve) automatically prunes idle sessions. This is a server-side periodic cleanup and has no effect on local CLI usage.
These are independent settings that operate at different levels.