Command-line interface (CLI)

Updated Jul 27, 2026

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::Protocol preserves raw byte-forwards on the default path, so podbot does not alter the first initialize frame there and forwards it unchanged. ACP initialize-request rewriting occurs only on the hosted ACP path for opt-in hosting; it is not a general ExecMode::Protocol guarantee.
  • 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 SIGWINCH and propagates window-size changes. Detached mode, protocol mode, or attached mode with TTY disabled do not register a resize listener. podbot reads terminal size using stty size; if that command is unavailable or returns unexpected output, resize propagation is skipped and execution continues.
  • Protocol mode ignores daemon StdIn echo 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 0 returns success. Non-zero values in the 1..=255 range are returned directly, negative values are mapped to 1, and values above 255 are clamped to 255.
  • If the daemon reports completion without an exit code, podbot returns an exec failure instead of guessing the result.