docs/sdk/python/execution.mdx
Run commands inside a running sandbox. See Commands for usage examples.
async def exec(
cmd: str,
args: list[str] | ExecOptions | None = None,
*,
cwd: str | None = None,
user: str | None = None,
env: Mapping[str, str] | None = None,
timeout: float | None = None,
stdin: Stdin | bytes | None = None,
tty: bool = False,
rlimits: list[Rlimit] | None = None,
) -> ExecOutput
out = await sandbox.exec(
"python3",
["script.py"],
cwd="/app",
env={"PYTHONPATH": "/app/lib"},
timeout=30.0,
)
print(out.stdout_text)
print(out.exit_code) # 0
Run a command inside the sandbox and wait for it to complete, buffering all stdout and stderr into memory. The keyword-only options apply to this call alone and don't change the sandbox's defaults. For long-running processes or large output, use exec_stream() instead. Raises ExecTimeoutError if timeout elapses and ExecFailedError if the process can't be spawned.
async def shell(
script: str,
*,
cwd: str | None = None,
user: str | None = None,
env: Mapping[str, str] | None = None,
timeout: float | None = None,
stdin: Stdin | bytes | None = None,
tty: bool = False,
rlimits: list[Rlimit] | None = None,
) -> ExecOutput
out = await sandbox.shell("ls -la /app && echo done")
print(out.stdout_text)
Run a command through the sandbox's configured shell (defaults to /bin/sh). Shell syntax like pipes, redirects, and && chains works. Accepts the same keyword-only options as exec().
async def exec_stream(
cmd: str,
args: list[str] | ExecOptions | None = None,
*,
cwd: str | None = None,
user: str | None = None,
env: Mapping[str, str] | None = None,
timeout: float | None = None,
stdin: Stdin | bytes | None = None,
tty: bool = False,
rlimits: list[Rlimit] | None = None,
) -> ExecHandle
import sys
from microsandbox import ExecEventType
handle = await sandbox.exec_stream("tail", ["-f", "/var/log/app.log"])
async for event in handle:
if event.event_type is ExecEventType.STDOUT:
sys.stdout.buffer.write(event.data)
elif event.event_type is ExecEventType.EXITED:
break
Run a command with streaming output. Returns an ExecHandle that emits stdout, stderr, and exit events as they happen rather than buffering everything. Takes the same per-call options as exec(). Pass stdin=Stdin.pipe() to write to the process while it runs via take_stdin(). For TTY sessions, call resize(rows, cols) when the terminal dimensions change.
async def shell_stream(
script: str,
*,
cwd: str | None = None,
user: str | None = None,
env: Mapping[str, str] | None = None,
timeout: float | None = None,
stdin: Stdin | bytes | None = None,
tty: bool = False,
rlimits: list[Rlimit] | None = None,
) -> ExecHandle
import sys
from microsandbox import ExecEventType
handle = await sandbox.shell_stream("for i in 1 2 3; do echo $i; sleep 1; done")
async for event in handle:
if event.event_type is ExecEventType.STDOUT:
sys.stdout.buffer.write(event.data)
Streaming variant of shell(): runs script through the configured shell but returns an ExecHandle instead of buffering output.
async def attach(
cmd: str,
args: list[str] | None = None,
*,
cwd: str | None = None,
user: str | None = None,
env: Mapping[str, str] | None = None,
detach_keys: str | None = None,
) -> int
code = await sandbox.attach("bash", cwd="/app", env={"EDITOR": "vim"})
Bridge your terminal directly to a process inside the sandbox for a fully interactive PTY session. Press the configured detach key sequence (default Ctrl+]) to disconnect without stopping the process. Returns the process exit code.
async def attach_shell() -> int
code = await sandbox.attach_shell()
Bridge your terminal to the sandbox's default shell in a fully interactive PTY session. Returns the shell's exit code.
<p className="msb-label">Returns</p> <div className="msb-params"> <div className="msb-param"> <div className="msb-param-key"><span className="msb-type">int</span></div> <div className="msb-param-desc">Exit code of the shell process.</div> </div> </div>A handle to a running streaming execution and its events.
str
Correlation ID for this execution
take_stdin()
Take the stdin writer. Returns None after the first call, or when stdin wasn't piped
ExecSink \| None
recv()
(async) Receive the next event. Returns None when the stream ends
ExecEvent \| None
wait()
(async) Wait for the process to exit. Returns (code, success)
tuple[int, bool]
collect()
(async) Drain remaining output and wait for exit
<p className="msb-label">Returns</p>signal(sig)
(async) Send a POSIX signal (numeric) to the process
kill()
(async) Send SIGKILL to the process
resize(rows, cols)
(async) Resize the PTY to the given uint16 dimensions
Writer for sending data to a running process's stdin. Obtained from ExecHandle.take_stdin() when the execution was configured with stdin=Stdin.pipe().
write(data)
(async) Write bytes to the process's stdin
close()
(async) Close the sink. Sends EOF in non-TTY pipe mode; the guest PTY remains open in TTY mode
Factory for process stdin configuration.
Stdin.null()
Connect stdin to /dev/null (default)
Stdin.pipe()
Open a writable pipe. Write via take_stdin() on the handle
Stdin.bytes(data)
Inline data sent before the process starts, then EOF
The factories set the corresponding StdinMode member.
Frozen dataclass describing a POSIX resource limit. Construct one directly or via a factory, then pass a list as the rlimits argument.
Which resource is limited
int
Soft limit
int
Hard limit
Rlimit.nofile(limit)
Max open file descriptors
Rlimit.cpu(secs)
CPU time limit in seconds
Rlimit.as_(\*, soft, hard)
Virtual memory size
Rlimit.nproc(limit)
Max number of processes
Rlimit.fsize(limit)
Max file size
Rlimit.memlock(limit)
Max locked memory
Rlimit.stack(limit)
Max stack size
Typed dictionary for passing arguments and per-call options together as the second positional argument. Use a Stdin object to select a mode or raw bytes for inline data.
| Key | Type | Description |
|---|---|---|
| args | list[str] | Command arguments |
| cwd | str | Working directory |
| user | str | Guest user |
| env | Mapping[str, str] | Per-command environment variables |
| timeout | float | Timeout in seconds |
| stdin | Stdin | bytes | Stdin configuration or inline bytes |
| stdin_data | bytes | Inline stdin bytes when stdin is omitted |
| tty | bool | Whether to allocate a pseudo-terminal |
| rlimits | list[Rlimit] | POSIX resource limits |
The result of a completed command execution: collected output plus exit status. All members are properties. In TTY mode, stdout_bytes contains the combined terminal output and stderr_bytes is empty because a PTY doesn't preserve separate stdout and stderr streams.
| Property | Type | Description |
|---|---|---|
| exit_code | int | Process exit code |
| success | bool | True when exit_code == 0 |
| stdout_text | str | Collected stdout decoded as UTF-8. Raises on invalid encoding |
| stderr_text | str | Collected stderr decoded as UTF-8. Raises on invalid encoding |
| stdout_bytes | bytes | Raw stdout bytes |
| stderr_bytes | bytes | Raw stderr bytes |
Native event object emitted by recv() and by iterating an ExecHandle. Fields that don't apply to a given event are None.
| Property | Type | Description |
|---|---|---|
| event_type | ExecEventType | Exact event discriminator |
| pid | int | None | Guest PID, set on ExecEventType.STARTED |
| data | bytes | None | Output bytes on STDOUT / STDERR, or a UTF-8 failure message on FAILED / STDIN_ERROR |
| code | int | None | Exit code on EXITED, or errno when available on FAILED / STDIN_ERROR |
String enum (enum.StrEnum) identifying a streaming execution event.
| Member | Value | Description |
|---|---|---|
ExecEventType.STARTED | "started" | Process started; pid is populated |
ExecEventType.STDOUT | "stdout" | Standard-output bytes are available in data |
ExecEventType.STDERR | "stderr" | Standard-error bytes are available in data |
ExecEventType.EXITED | "exited" | Process exited; code is populated |
ExecEventType.FAILED | "failed" | Process startup failed |
ExecEventType.STDIN_ERROR | "stdin_error" | Writing process stdin failed |
Frozen dataclass describing a process exit result. ExecHandle.wait() returns the same information as a (code, success) tuple.
| Field | Type | Description |
|---|---|---|
| code | int | Process exit code |
| success | bool | True when code == 0 |
String enum (enum.StrEnum) identifying how command stdin is connected.
| Member | Value | Description |
|---|---|---|
StdinMode.NULL | "null" | Connect stdin to /dev/null |
StdinMode.PIPE | "pipe" | Expose a writable ExecSink |
StdinMode.BYTES | "bytes" | Send inline bytes, then EOF |
String enum (enum.StrEnum) naming a limitable POSIX resource.
| Member | Value | Description |
|---|---|---|
RlimitResource.CPU | "cpu" | CPU time |
RlimitResource.FSIZE | "fsize" | File size |
RlimitResource.DATA | "data" | Data segment size |
RlimitResource.STACK | "stack" | Stack size |
RlimitResource.CORE | "core" | Core file size |
RlimitResource.RSS | "rss" | Resident set size |
RlimitResource.NPROC | "nproc" | Number of processes |
RlimitResource.NOFILE | "nofile" | Open file descriptors |
RlimitResource.MEMLOCK | "memlock" | Locked memory |
RlimitResource.AS | "as" | Virtual memory |
RlimitResource.LOCKS | "locks" | File locks |
RlimitResource.SIGPENDING | "sigpending" | Pending signals |
RlimitResource.MSGQUEUE | "msgqueue" | Message queue size |
RlimitResource.NICE | "nice" | Nice priority ceiling |
RlimitResource.RTPRIO | "rtprio" | Real-time priority ceiling |
RlimitResource.RTTIME | "rttime" | Real-time CPU time |