os/exec conventions: a non-zero exit code is not a Go error. Transport, timeout, and spawn-failure paths return an error; a program that ran and exited non-zero is a normal *ExecOutput result — inspect Success() or ExitCode().
Sandbox methods
The exec surface lives on*Sandbox:
| Method | Returns | Description |
|---|---|---|
Exec(ctx, cmd, args, opts...) | (*ExecOutput, error) | Run a command and collect output |
ExecStream(ctx, cmd, args, opts...) | (*ExecHandle, error) | Run a command with streaming events |
Shell(ctx, command, opts...) | (*ExecOutput, error) | Run via /bin/sh -c |
ShellStream(ctx, command, opts...) | (*ExecHandle, error) | Streaming shell |
Attach(ctx, cmd, args...) | (int, error) | Interactive PTY session |
AttachShell(ctx) | (int, error) | Interactive PTY session in the default shell |
Types
ExecOutput
The result of a completed command execution.| Method | Returns | Description |
|---|---|---|
Stdout() | string | Collected stdout decoded as UTF-8 |
Stderr() | string | Collected stderr decoded as UTF-8 |
StdoutBytes() | []byte | Raw stdout bytes |
StderrBytes() | []byte | Raw stderr bytes |
ExitCode() | int | Exit code, or -1 if the guest did not report one (e.g. killed by signal) |
Success() | bool | true if ExitCode() is 0 |
Stdout()
Stderr()
StdoutBytes()
StderrBytes()
ExitCode()
-1 if the guest did not report one (e.g. the process was killed by a signal).
Success()
true if the process exited with code 0.
ExecHandle
A live streaming exec session returned byExecStream and ShellStream. The handle MUST be closed with Close when done. Not safe for concurrent use from multiple goroutines.
| Method | Returns | Description |
|---|---|---|
ID() | (string, error) | Correlation ID assigned by the guest agent |
Recv(ctx) | (*ExecEvent, error) | Block until the next event arrives |
TakeStdin() | *ExecSink | Take the stdin writer (single-take; only with WithExecStdinPipe) |
Collect(ctx) | (*ExecOutput, error) | Drain remaining output and assemble into an ExecOutput |
Wait(ctx) | (int, error) | Wait for exit, discarding output; returns the exit code |
Kill(ctx) | error | Send SIGKILL |
Signal(ctx, sig) | error | Send a Unix signal (e.g. syscall.SIGTERM) |
Close() | error | Release the Rust-side handle |
ID()
Recv()
Kind == ExecEventDone when all events have been consumed.
ctx controls the wait; cancellation causes Recv to return ctx.Err() immediately. The underlying Rust call may continue to completion in the background.
TakeStdin()
nil if:
- the session was not started with
WithExecStdinPipe, or TakeStdinhas already been called on this handle (single-take semantics, matching Node and Python).
Collect()
*ExecOutput. Equivalent to calling Recv in a loop and assembling the result.
Wait()
Collect, stdout and stderr are discarded.
Kill()
Signal()
syscall (e.g. int(syscall.SIGTERM)).
Close()
Signal(ctx, 9) or Kill first if you need to terminate it. Safe to call after ExecEventDone has been received.
ExecSink
A write-only pipe to a running process’s stdin, obtained fromExecHandle.TakeStdin. Implements io.WriteCloser.
Write and Close use context.Background() under the hood. For caller-controlled cancellation use WriteCtx, or tear the session down via ExecHandle.Kill / Close.
| Method | Returns | Description |
|---|---|---|
Write(p []byte) | (int, error) | Implements io.Writer |
WriteCtx(ctx, data) | error | Write with explicit context |
Close() | error | Send EOF and finalise |
ExecEvent
One event emitted byExecHandle.Recv.
| Field | Type | Description |
|---|---|---|
| Kind | ExecEventKind | Identifies which fields are populated |
| PID | uint32 | Guest process ID — set on ExecEventStarted |
| Data | []byte | Chunk of stdout or stderr — set on ExecEventStdout / ExecEventStderr |
| ExitCode | int | Process exit code — set on ExecEventExited |
| Failure | *ExecFailure | Structured spawn-failure detail — set on ExecEventFailed |
ExecEventKind
| Constant | Description |
|---|---|
ExecEventStarted | Sent once when the guest process starts; PID is valid |
ExecEventStdout | A chunk of stdout; Data is valid |
ExecEventStderr | A chunk of stderr; Data is valid |
ExecEventExited | The process exited; ExitCode is valid |
ExecEventFailed | The user program never started (binary missing, permission denied, …); Failure is valid |
ExecEventStdinError | A stdin write failed; Failure is valid. Non-terminal: the process may still emit output and exit normally |
ExecEventDone | All events have been consumed |
ExecFailure
ExecEventFailed. See Error Handling for the kinds it carries (not_found, permission_denied, etc.) and how to branch on them.
ExecConfig
The config struct populated byExecOption functions. Most callers go through Exec(ctx, cmd, args, ...opts); ExecConfig is exported for callers that prefer to construct one directly.
| Field | Type | Description |
|---|---|---|
| Cwd | string | Working directory inside the guest |
| Timeout | time.Duration | Kill the process after this duration. Sub-second precision is rounded up |
| StdinPipe | bool | Enable a stdin pipe; required for TakeStdin |
| User | string | Guest user (UID or name) |
| Env | map[string]string | Per-command environment variables |
ExecOption
Exec, Shell, ExecStream, and ShellStream.
WithExecCwd()
WithExecTimeout()
Kind == ErrExecTimeout. Sub-second precision rounds up to whole seconds; pass at least 1 second.
WithExecStdinPipe()
ExecHandle.TakeStdin.