Skip to main content
The commands module on a sandbox lets you run shell commands inside the microVM. Commands have access to the full Linux userspace, can read and write the sandbox filesystem, and respect environment variables set at the sandbox or command level.

Run a command (blocking)

run() executes the command and waits for it to complete, then returns a CommandResult.
result = sbx.commands.run("echo 'Hello from Declaw!'")
print(result.stdout)    # Hello from Declaw!
print(result.stderr)    # (empty)
print(result.exit_code) # 0

CommandResult model

FieldTypeDescription
stdoutstrFull standard output from the command
stderrstrFull standard error from the command
exit_codeintProcess exit code (0 = success)

Run options

result = sbx.commands.run(
    "python3 script.py",
    envs={"PYTHONPATH": "/opt/mylib"},   # per-command env vars
    cwd="/workspace",                     # working directory
    user="root",                          # run as user
    timeout=30,                           # seconds before TimeoutException
)

Run with output callbacks

run() accepts on_stdout/on_stderr callbacks that are invoked after the command completes, iterating over the collected output lines. Each callback receives a plain str.
For true real-time streaming as the command produces output, use run_stream() / runStream() instead.
result = sbx.commands.run(
    "python3 -c \"import time; [print(i, flush=True) or time.sleep(0.1) for i in range(5)]\"",
    on_stdout=lambda line: print("OUT:", line),
    on_stderr=lambda line: print("ERR:", line),
)
# OUT: 0
# OUT: 1
# OUT: 2
# OUT: 3
# OUT: 4
print("Exit:", result.exit_code)

Background processes

Pass background=True to start a long-running process and get a CommandHandle back immediately.
# Start a background HTTP server
handle = sbx.commands.run(
    "python3 -m http.server 8080",
    background=True,
)
print(handle.pid)  # 42

# Do other work...
sbx.commands.run("curl http://localhost:8080")

# Wait for it to finish
result = handle.wait()

# Or kill it explicitly
sbx.commands.kill(handle.pid)

CommandHandle

Field/MethodDescription
pidProcess identifier within the sandbox
wait()Block until the process finishes; returns CommandResult. Raises CommandExitException/CommandExitError on non-zero exit code.

List running commands

processes = sbx.commands.list()
for p in processes:
    print(p.pid, p.cmd, p.is_pty)

ProcessInfo model

FieldTypeDescription
pidintProcess ID inside the sandbox
cmdstrCommand string that was run
is_pty / isPtyboolWhether the process is running in a PTY
envsdict / RecordEnvironment variables for the process

Send stdin to a running process

handle = sbx.commands.run("cat", background=True)

sbx.commands.send_stdin(handle.pid, "line one\n")
sbx.commands.send_stdin(handle.pid, "line two\n")

# Close stdin by killing, or wait if process exits naturally
sbx.commands.kill(handle.pid)

Kill a command

sbx.commands.kill(pid=42)

Wait for a command by PID

If you lost the CommandHandle reference, reconnect using connect() and call wait().
handle = sbx.commands.connect(pid=42)
result = handle.wait()
print(result.exit_code)

Error handling

from declaw import CommandExitException, TimeoutException

try:
    result = sbx.commands.run("exit 1")
except CommandExitException as e:
    print(f"Command failed with exit code {e.exit_code}")
    print(e.stderr)

try:
    result = sbx.commands.run("sleep 100", timeout=5)
except TimeoutException:
    print("Command timed out")
commands.run() does not throw on non-zero exit codes — check result.exit_code yourself. However, handle.wait() (on background processes) always throws CommandExitException / CommandExitError on non-zero exit codes.

Multi-language execution

The default sandbox template includes Python 3, Node.js, Go, and standard shell utilities.
# Python
r = sbx.commands.run("python3 -c 'print(2+2)'")
print(r.stdout)  # 4

# Node.js
r = sbx.commands.run("node -e 'console.log(2+2)'")
print(r.stdout)  # 4

# Go
sbx.files.write("/tmp/main.go", """
package main
import "fmt"
func main() { fmt.Println(2+2) }
""")
r = sbx.commands.run("go run /tmp/main.go")
print(r.stdout)  # 4