Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt

Use this file to discover all available pages before exploring further.

This guide covers running commands in sandboxes using the exec() method.

Basic execution

The exec() method runs commands in a sandbox and returns a Process handle:
from cwsandbox import Sandbox

with Sandbox.run() as sandbox:
    # Run a command and get the result
    result = sandbox.exec(["echo", "Hello, World!"]).result()

    print(result.stdout)      # "Hello, World!\n"
    print(result.returncode)  # 0

Getting results

The exec() method returns a Process object. Call .result() to block for the output:
# Returns Process immediately
process = sandbox.exec(["python", "-c", "print('hello')"])

# Block for result
result = process.result()
print(result.stdout)      # "hello\n"
print(result.stderr)      # ""
print(result.returncode)  # 0

# One-liner pattern
result = sandbox.exec(["ls", "-la"]).result()

Streaming output

For real-time output, iterate over process.stdout before calling .result():
# Returns Process immediately
process = sandbox.exec(["python", "long_script.py"])

# Stream stdout line by line
for line in process.stdout:
    print(f"[stdout] {line}", end="")

# Get final result
result = process.result()
print(f"Exit code: {result.returncode}")
Use streaming when you need to:
  • Monitor long-running processes
  • Process output as it arrives
  • Implement progress indicators

Stdin streaming

Send input to running commands by enabling stdin with stdin=True:
with Sandbox.run() as sandbox:
    process = sandbox.exec(["cat"], stdin=True)

    process.stdin.write(b"hello world\n").result()
    process.stdin.close().result()

    result = process.result()
    print(result.stdout)  # "hello world\n"

StreamWriter methods

When stdin=True, process.stdin is a StreamWriter with three methods:
  • write(data: bytes) - Write raw bytes. Returns OperationRef[None].
  • writeline(text: str) - Write text with a trailing newline (encodes to UTF-8). Returns OperationRef[None].
  • close() - Signal EOF. Pending writes complete first. Returns OperationRef[None].
When stdin=False (the default), process.stdin is None.

Multiple writes

Send data incrementally before closing:
process = sandbox.exec(["cat"], stdin=True)

process.stdin.writeline("line 1").result()
process.stdin.writeline("line 2").result()
process.stdin.writeline("line 3").result()
process.stdin.close().result()

result = process.result()
print(result.stdout)  # "line 1\nline 2\nline 3\n"

Interactive Python via stdin

Feed Python code to an interactive interpreter:
process = sandbox.exec(["python3"], stdin=True)

process.stdin.writeline("x = 40 + 2").result()
process.stdin.writeline("print(f'answer: {x}')").result()
process.stdin.close().result()

result = process.result()
print(result.stdout)  # "answer: 42\n"

Combining stdin and stdout streaming

Stream output while sending input:
process = sandbox.exec(["cat"], stdin=True)

# Send input
process.stdin.writeline("hello").result()
process.stdin.writeline("world").result()
process.stdin.close().result()

# Stream output as it arrives
for line in process.stdout:
    print(f"[out] {line}", end="")

result = process.result()

EOF-dependent commands

Some commands (like sort) read all input before producing output. Close stdin to signal EOF:
process = sandbox.exec(["sort"], stdin=True)

process.stdin.writeline("banana").result()
process.stdin.writeline("apple").result()
process.stdin.writeline("cherry").result()
process.stdin.close().result()  # sort needs EOF to begin

result = process.result()
print(result.stdout)  # "apple\nbanana\ncherry\n"

Async usage

In async contexts, await the OperationRefs directly:
async with Sandbox.run() as sandbox:
    process = sandbox.exec(["cat"], stdin=True)

    await process.stdin.write(b"async hello\n")
    await process.stdin.close()

    result = await process
    print(result.stdout)  # "async hello\n"

When to use stdin=True vs stdin=False

ScenariostdinReason
Run a command with argumentsFalseInput comes from args, not stdin
Pipe data into a commandTrueCommand reads from stdin
Interactive interpreterTrueInterpreter reads commands from stdin
Process that reads until EOFTrueNeed close() to signal EOF
Fire-and-forget commandFalseNo input needed

Working directory

Set the working directory with cwd:
result = sandbox.exec(
    ["ls", "-la"],
    cwd="/app/data",
).result()
The path must be absolute.

Timeouts

Set command timeout with timeout_seconds:
from cwsandbox import SandboxTimeoutError

try:
    result = sandbox.exec(
        ["sleep", "60"],
        timeout_seconds=5.0,
    ).result()
except SandboxTimeoutError:
    print("Command timed out")

Error handling with check

The check parameter controls error behavior for non-zero exit codes:

check=False (default)

Returns the result regardless of exit code:
result = sandbox.exec(["false"]).result()
print(result.returncode)  # 1 (no exception)

check=True

Raises SandboxExecutionError on non-zero exit:
from cwsandbox import SandboxExecutionError

try:
    result = sandbox.exec(
        ["python", "-c", "raise ValueError('oops')"],
        check=True,
    ).result()
except SandboxExecutionError as e:
    print(f"Command failed: {e.exec_result.returncode}")
    print(f"stderr: {e.exec_result.stderr}")

Running Python code

Execute Python scripts or one-liners:
# One-liner
result = sandbox.exec(
    ["python", "-c", "import sys; print(sys.version)"],
).result()

# Script from string
code = '''
import json
data = {"result": 42}
print(json.dumps(data))
'''
result = sandbox.exec(["python", "-c", code]).result()
output = json.loads(result.stdout)

Sequential vs. parallel execution

Sequential (order matters)

# Dependencies require sequential execution
sandbox.exec(["pip", "install", "requests"]).result()
sandbox.exec(["python", "script_using_requests.py"]).result()

Parallel (independent commands)

# Start multiple sandboxes
sandboxes = [Sandbox.run() for _ in range(3)]

# Start commands on each
processes = [
    sb.exec(["python", "-c", f"print({i})"])
    for i, sb in enumerate(sandboxes)
]

# Collect all results
results = [p.result() for p in processes]
for r in results:
    print(r.stdout)

Waiting for N of M to complete

Use cwsandbox.wait() to wait for a subset of processes:
import cwsandbox

processes = [sb.exec(["python", "task.py"]) for sb in sandboxes]

# Wait for first 2 to complete
done, pending = cwsandbox.wait(processes, num_returns=2)

# Process completed ones immediately
for p in done:
    print(p.result().stdout)

# Wait for remaining
for p in pending:
    print(p.result().stdout)

Process control

The Process object provides methods for monitoring and control:
process = sandbox.exec(["python", "server.py"])

# Check if running (non-blocking)
if process.poll() is None:
    print("Still running")

# Wait for completion
exit_code = process.wait()
print(f"Exited with code: {exit_code}")
Last modified on April 21, 2026