Skip to content

Running Commands

pocketdock supports three execution modes: blocking, streaming, and detached.

Blocking Mode (Default)

Run a command, wait for it to finish, get all output at once:

result = c.run("echo hello")
result.exit_code    # 0
result.stdout       # "hello\n"
result.stderr       # ""
result.ok           # True (exit_code == 0 and not timed_out)
result.duration_ms  # 47.2
result.timed_out    # False
result.truncated    # False

Run Python Code

Use lang="python" to wrap the command with python3 -c:

result = c.run("print(2 + 2)", lang="python")
print(result.stdout)  # "4\n"

Timeout

Set a per-command timeout (in seconds):

result = c.run("sleep 60", timeout=5)
result.timed_out  # True
result.ok         # False

The default timeout is set at container creation (30 seconds).

Output Cap

Limit the amount of output collected:

result = c.run("cat /dev/urandom | head -c 1000000", max_output=1024)
result.truncated  # True

Default: 10 MB (10_485_760 bytes).

Streaming Mode

Yield output chunks as they arrive. Useful for builds, long-running scripts, and real-time monitoring:

for chunk in c.run("make all 2>&1", stream=True):
    print(chunk.data, end="")
    # chunk.stream is "stdout" or "stderr"

Each StreamChunk has:

  • stream"stdout" or "stderr"
  • data — the text content

Get Final Result After Streaming

The stream object exposes a .result property after iteration completes:

stream = c.run("echo hello && exit 1", stream=True)
for chunk in stream:
    print(chunk.data, end="")
print(stream.result.exit_code)  # 1

Detached Mode

Start a background process and get a handle to monitor or kill it:

proc = c.run("python -m http.server 8080", detach=True)
proc.is_running()  # True

Read Buffered Output

Detached processes write to a ring buffer (1 MB default). Read from it without blocking:

# Consume and clear the buffer
output = proc.read()
print(output.stdout)
print(output.stderr)

# Peek without consuming
output = proc.peek()

Both return a BufferSnapshot with .stdout and .stderr strings.

Buffer Overflow

Check if the ring buffer has overflowed (older data was evicted):

proc.buffer_size      # Current bytes in buffer
proc.buffer_overflow  # True if data was evicted

Wait for Completion

result = proc.wait(timeout=60)  # -> ExecResult
print(result.exit_code)

Kill

proc.kill()           # Send SIGTERM (default)
proc.kill(signal=9)   # Send SIGKILL

Callbacks

Register callbacks to be notified of output and exit events on detached processes:

c.on_stdout(lambda container, data: print(f"[out] {data}", end=""))
c.on_stderr(lambda container, data: print(f"[err] {data}", end=""))
c.on_exit(lambda container, code: print(f"Exited with code {code}"))

proc = c.run("python long_task.py", detach=True)

Callback signatures:

  • on_stdout(fn)fn(container, data: str)
  • on_stderr(fn)fn(container, data: str)
  • on_exit(fn)fn(container, exit_code: int)

Callbacks are invoked for all detached processes on the container. They are dispatched synchronously from the read loop.