protocol
protocol
¶
Container runtime protocol — the how behind running and observing containers.
Defines the backend-neutral surface used by higher layers (executor, terok).
Concrete implementations: .podman.PodmanRuntime (default),
.null.NullRuntime (tests / dry-run). A future KrunRuntime for
microVM-isolated containers slots in alongside without touching callers.
The protocol deliberately covers only runtime concerns — state queries,
lifecycle, image inspection, exec. Gate, shield, credentials, vault, and
SSH are orthogonal services that compose with the runtime at a higher
layer (see terok_sandbox.sandbox.Sandbox).
ExecResult(exit_code, stdout, stderr)
dataclass
¶
Outcome of ContainerRuntime.exec.
Backend-neutral so the SSH-over-passt krun backend can fill it from
an SSH response without pretending to be a subprocess.CompletedProcess.
ContainerRemoveResult(name, removed, error=None)
dataclass
¶
Per-container outcome from ContainerRuntime.force_remove.
Container
¶
Bases: Protocol
Handle to a container managed by a ContainerRuntime.
Handles are cheap — construction does not verify that the container
exists. Operations return sensible defaults (None, False, [])
when the underlying container is absent, matching podman's own semantics.
name
instance-attribute
¶
state
property
¶
Lifecycle state ("running", "exited", ...) or None.
running
property
¶
Shortcut: state == "running".
image
property
¶
Handle to the image this container was created from, or None.
rw_size
property
¶
Writable-layer size in bytes, or None if unavailable.
start()
¶
Start the container. Raises RuntimeError on failure.
stop(*, timeout=10)
¶
wait(timeout=None)
¶
Block until the container exits; return its exit code.
Raises TimeoutError when timeout elapses.
copy_in(src, dest)
¶
login_command(*, command=())
¶
Return an argv suitable for os.execvp to attach interactively.
Empty command uses the backend default (typically tmux
new-session -A -s main).
Source code in src/terok_sandbox/runtime/protocol.py
logs(*, follow=False, tail=None)
¶
stream_initial_logs(ready_check, timeout_sec)
¶
Stream logs until ready_check returns True or timeout_sec.
Returns True if the ready marker was seen, False on timeout.
Each line is printed to stdout as it is received.
Source code in src/terok_sandbox/runtime/protocol.py
Image
¶
Bases: Protocol
Handle to a local container image. Cheap to construct.
ref
instance-attribute
¶
Tag ("terok-l2-cli:abcd") or ID ("sha256:...") used on lookup.
id
property
¶
Resolved image ID, or None if the image is not present.
repository
property
¶
Repository portion of the tag ("<none>" for dangling).
tag
property
¶
Tag portion ("<none>" for dangling).
size
property
¶
Podman-rendered human-readable size ("1.2GB").
created
property
¶
Podman-rendered creation timestamp.
exists()
¶
labels()
¶
history()
¶
LogStream
¶
Bases: Protocol
Context-managed iterator over decoded log lines.
__exit__ releases the backing process (or the krun-backend
equivalent). Safe to use in a with block plus for line in
stream loop.
PortReservation
¶
Bases: Protocol
Context manager for a reserved host-side TCP port.
The port is held open for the lifetime of the reservation; closing releases it. Use to pass a port number to an external process that will bind it shortly.
ContainerRuntime
¶
Bases: Protocol
The container runtime — factory for handles, plus operations that have no single-object receiver.
One instance per process, typically constructed at the top-level entry
point and threaded down through higher layers (Sandbox, executor's
AgentRunner, terok's CLI/TUI).
container(name)
¶
Return a handle to the container named name.
Does not verify existence; call Container.state for that.
containers_with_prefix(prefix)
¶
image(ref)
¶
Return a handle to the image identified by tag or ID ref.
Does not verify existence; call Image.exists for that.
images(*, dangling_only=False)
¶
Enumerate local images.
dangling_only narrows to untagged images (those listed as
<none>:<none>).
exec(container, cmd, *, timeout=None)
¶
Run cmd inside container and return its completion record.
The operation that diverges most across backends: podman uses
podman exec; the krun backend uses SSH over a passt-forwarded
TCP port.
Source code in src/terok_sandbox/runtime/protocol.py
exec_stdio(container, cmd, *, stdin, stdout, stderr=None, env=None, timeout=None)
¶
Run cmd inside container with stdio bridged to caller-supplied streams.
Forwards bytes bidirectionally between stdin/stdout/stderr and the
spawned process — distinct from exec, which captures output into
an ExecResult. Used by the host-side ACP proxy to bridge a Unix
socket to an in-container ACP-stdio agent without the runtime ever
materialising the conversation.
Blocks until the child exits; returns the exit code. EOF on either side terminates forwarding cleanly. Implementations are expected to be transport-agnostic — stdin/stdout are arbitrary byte streams (a socket's file-object face, a pipe end, a test buffer).
Source code in src/terok_sandbox/runtime/protocol.py
force_remove(containers)
¶
Forcibly stop and remove containers.
Best-effort — continues through individual failures and returns
one ContainerRemoveResult per input. An already-absent
container counts as removed (the post-condition holds).
Source code in src/terok_sandbox/runtime/protocol.py
reserve_port(host='127.0.0.1')
¶
Reserve a free TCP port on host.
The returned PortReservation exposes the port number via
reservation.port and releases the socket on close. Use to
pass a pre-reserved port to an external process.