Global options
| Option | Description |
|---|---|
--config PATH |
Path to a custom configuration file |
--engine-socket |
Container engine socket path or URL |
--image |
Container image to use for the sandbox |
Subcommands
run
Run an AI agent in a sandboxed container.
podbot run --repo owner/name --branch main --agent claude
The CLI converts --repo and --branch into podbot::api::RunRequest before
dispatching to the library orchestration boundary. Rust embedders can construct
the same request directly without using CLI parse types.
| Option | Required | Default | Description |
|---|---|---|---|
--repo |
Yes | - | Repository in owner/name format |
--branch |
Yes | - | Branch to check out |
--agent |
No | Config/defaults | Agent type: claude, codex, or custom |
--agent-mode |
No | Config/defaults | Agent mode; run accepts only podbot semantically |
host
Host an app-server protocol for a long-lived agent runtime.
This subcommand is temporarily unavailable in the current release. If you run
podbot host, Podbot will return an error rather than starting a hosted
session. Use podbot run or the library exec API for now; the release notes
will call out when hosted mode becomes available.
When hosted mode uses Agentic Control Protocol (ACP), podbot masks terminal/*
and fs/* capabilities from the initial ACP initialize request before
forwarding it to the sandboxed agent. After initialization, podbot also
enforces a runtime denylist on agent-emitted requests in those capability
families. If the hosted agent attempts a method such as terminal/create or
fs/read_text_file, podbot refuses to forward the request and returns a
JSON-RPC 2.0 error response carrying the original request id, error code
-32001, message Method blocked by Podbot ACP capability policy, and a
structured data.reason = "podbot_capability_policy" field so the agent can
branch on reason programmatically. Each denial also produces a single warning
line on podbot's stderr with the target podbot::acp::policy, the container
identifier, the blocked method name, and the request id (or null for
notifications). Permitted methods pass through byte-for-byte. Both the
initialization-time masking and the runtime denylist apply only to the
protocol/library path used by hosted mode and ACP until podbot host is
implemented; the operator override to opt back in to host-side delegation is
tracked in roadmap Step 2.6.3.
| Option | Required | Default | Description |
|---|---|---|---|
--agent |
No | Config/defaults | Agent type: claude, codex, or custom |
--agent-mode |
No | Config/defaults | Hosted mode: codex_app_server or acp |
token-daemon
Run the GitHub token refresh daemon for a container.
podbot token-daemon <container-id>
ps
List running podbot containers.
podbot ps
stop
Stop a running container.
podbot stop <container>
exec
Execute a command in a running container.
podbot exec <container> -- command arg1 arg2
Use attached mode by default, or detached mode with --detach:
# Attached mode (default): streams are forwarded to the local terminal
podbot exec <container> -- sh -lc "echo hello"
# Detached mode: no stream attachment, but podbot still waits for completion
podbot exec --detach <container> -- sh -lc "exit 7"
Execution behaviour:
- Attached mode forwards stdin/stdout/stderr between the local terminal and the container exec session.
- Detached mode does not attach streams and always uses
tty = false. - Protocol mode (
ExecMode::Protocol) connects streams like attached mode but permanently disables TTY allocation. This mode is used internally by the hosting subsystem to proxy protocol bytes without TTY framing corruption. Library consumers can use it for non-TTY attached execution where stdout must remain a pure byte stream. In protocol mode, podbot forwards host stdin to container stdin, container stdout to host stdout, and container stderr to host stderr without terminal framing or interactive echo injection. Protocol mode uses bounded buffering (64 KiB buffers for stdin forwarding and output chunks) so hosted protocols can apply backpressure; if the host stdout writer blocks, the proxy yields and backpressure propagates to the container.ExecMode::Protocolpreserves raw byte-forwards on the default path, so podbot does not alter the firstinitializeframe there and forwards it unchanged. ACP initialize-request rewriting occurs only on the hosted ACP path for opt-in hosting; it is not a generalExecMode::Protocolguarantee. - TTY allocation is enabled only when attached mode is selected and both local stdin and stdout are terminals.
- When TTY is enabled, podbot sends an initial resize to the daemon. On Unix
targets, podbot also listens for
SIGWINCHand propagates window-size changes. Detached mode, protocol mode, or attached mode with TTY disabled do not register a resize listener. podbot reads terminal size usingstty size; if that command is unavailable or returns unexpected output, resize propagation is skipped and execution continues. - Protocol mode ignores daemon
StdInecho records, so stdout contains only bytes that originated from container stdout or console output. When host stdin reaches EOF, podbot flushes and closes container stdin before waiting for the command to finish. - podbot polls exec status until the command exits, then uses the daemon exit
code as the CLI outcome. Exit code
0returns success. Non-zero values in the1..=255range are returned directly, negative values are mapped to1, and values above255are clamped to255. - If the daemon reports completion without an exit code, podbot returns an exec failure instead of guessing the result.