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
const result = await sbx.commands.run("echo 'Hello from Declaw!'");
console.log(result.stdout); // Hello from Declaw!
console.log(result.exitCode); // 0
CommandResult model
| Field | Type | Description |
|---|
stdout | str | Full standard output from the command |
stderr | str | Full standard error from the command |
exit_code | int | Process 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
)
const result = await sbx.commands.run('python3 script.py', {
envs: { PYTHONPATH: '/opt/mylib' },
cwd: '/workspace',
user: 'root',
timeout: 30,
});
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)
const result = await sbx.commands.run(
'for i in 1 2 3 4 5; do echo $i; sleep 0.1; done',
{
onStdout: (line) => console.log('OUT:', line),
onStderr: (line) => console.error('ERR:', line),
},
);
console.log('Exit:', result.exitCode);
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)
const handle = await sbx.commands.run('python3 -m http.server 8080', {
background: true,
});
console.log(handle.pid);
// Kill when done
await sbx.commands.kill(handle.pid);
CommandHandle
| Field/Method | Description |
|---|
pid | Process 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)
const processes = await sbx.commands.list();
for (const p of processes) {
console.log(p.pid, p.cmd, p.isPty);
}
ProcessInfo model
| Field | Type | Description |
|---|
pid | int | Process ID inside the sandbox |
cmd | str | Command string that was run |
is_pty / isPty | bool | Whether the process is running in a PTY |
envs | dict / Record | Environment 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)
const handle = await sbx.commands.run('cat', { background: true });
await sbx.commands.sendStdin(handle.pid, 'line one\n');
await sbx.commands.sendStdin(handle.pid, 'line two\n');
await sbx.commands.kill(handle.pid);
Kill a command
sbx.commands.kill(pid=42)
await sbx.commands.kill(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")
import { CommandExitError, TimeoutError } from '@declaw/sdk';
try {
await sbx.commands.run('exit 1');
} catch (e) {
if (e instanceof CommandExitError) {
console.log(`Failed with exit code ${e.exitCode}`);
}
}
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