Agent Runtime Reference
This is the canonical runtime reference for ProPR coding agents. It covers the shared Docker execution model used by Claude Code, Codex, Antigravity, OpenCode, and Mistral Vibe. For the higher-level integration contract, routing model, and worker responsibilities, see Coding Agent Integration.
Runtime Model
Every coding agent runs in a Docker container so ProPR can control runtime dependencies, workspace mounts, credential mounts, timeouts, logging, and resource boundaries. The agent implementation changes the CLI command, image, credential directory, and output parser, but the container shape is shared:
- A task worktree mounted at
/home/node/workspace - Agent credentials mounted from a ProPR-managed per-agent directory or a configured existing host directory
- GitHub credentials passed through
GH_TOKENandGITHUB_TOKEN - Agent, model, timeout, and task metadata passed as environment variables or CLI flags
--security-opt no-new-privileges,--cap-add CHOWN(Vibe omits it), and Docker's defaultbridgenetwork; the repository setup hook runs without sudo privileges before the agent entrypoint- Memory, CPU, and process limits from
AGENT_CONTAINER_MEMORY_LIMIT(default6g),AGENT_CONTAINER_CPU_LIMIT(default: available CPUs, capped at 4), andAGENT_CONTAINER_PIDS_LIMIT(default512) - For every agent except Vibe, the host's
/tmp/git-processordirectory (all clones and worktrees) mounted at the same path so git works in the linked worktree - Structured stdout, stderr, exit code, duration, session ID, and token usage capture when the CLI exposes those fields
All agents run from the unified Debian/glibc propr/agent image. Its internal base stage includes Node.js 22, Git and repository tooling, a scoped gh wrapper, and entrypoint support used by the worker. The image uses Node.js 22 to satisfy current agent CLI engine requirements. Independent CLI build stages preserve Docker cache reuse when one configured version changes.
This table maps each agent type to the unified image, its type-specific entrypoint, and its credential mount; other pages link here instead of repeating it.
| Agent | Image | Dockerfile | Entrypoint | Existing host credential mount | Container credential path |
|---|---|---|---|---|---|
| Claude Code | propr/agent | Dockerfile.agent | scripts/claude-entrypoint.sh | HOST_CLAUDE_DIR (~/.claude) | /home/node/.claude |
| Codex | propr/agent | Dockerfile.agent | scripts/codex-entrypoint.sh | HOST_CODEX_DIR (~/.codex) | /home/node/.codex |
| Antigravity | propr/agent | Dockerfile.agent | scripts/antigravity-entrypoint.sh | HOST_ANTIGRAVITY_DIR (~/.gemini) | /home/node/.gemini |
| OpenCode | propr/agent | Dockerfile.agent | scripts/opencode-entrypoint.sh | HOST_OPENCODE_XDG_DIR (~/.config/opencode) plus HOST_OPENCODE_DATA_DIR | /home/node/.config/opencode |
| Mistral Vibe | propr/agent | Dockerfile.agent | scripts/vibe-entrypoint.sh | HOST_VIBE_DIR (~/.vibe) | /home/node/.vibe |
Container Configuration
The worker launches the unified agent image with a prepared worktree, a generated container name, the selected type's credential mount, and any agent-level environment variables. Containers are removed after execution with --rm, run with stdin enabled, and use /home/node/workspace as the working directory.
Most entrypoints start as root so they can prepare runtime directories or fix container-local ownership, then drop to the node user before running the CLI. Entrypoints also mark Git directories as safe, install the gh wrapper when present, and emit diagnostics that are captured with the task logs.
Existing-account credential and launcher paths must be absolute host paths. Shell shortcuts such as ~ and $HOME are not expanded by launcher configuration. Direct-login accounts instead save a portable ~/.propr/agent-credentials/<agent-id>/… path that ProPR maps to its managed host root automatically.
Timeouts And Loop Limits
Timeouts prevent runaway jobs and make failures visible in task state. Defaults differ by agent:
| Agent | Timeout variable | Default | Loop variable | Default |
|---|---|---|---|---|
| Claude Code | CLAUDE_TIMEOUT_MS | 86400000 (24 hours) | CLAUDE_MAX_TURNS | 1000 |
| Codex | CODEX_TIMEOUT_MS | 86400000 (24 hours) | Not used | N/A |
| Antigravity | ANTIGRAVITY_TIMEOUT_MS | 86400000 (24 hours) | Not used | N/A |
| OpenCode | OPENCODE_TIMEOUT_MS | 86400000 (24 hours) | Not used | N/A |
| Mistral Vibe | VIBE_TIMEOUT_MS | 86400000 (24 hours) | VIBE_MAX_TURNS | 1000 |
These task-execution defaults are shared across all coding agents and match the shipped .env.example. Planner keyword extraction and semantic relevance scoring default to 60 minutes per call and can be adjusted with CONTEXT_ANALYSIS_TIMEOUT_MS.
When an implementation run reaches its execution timeout or maximum turn limit, ProPR preserves any workspace changes produced before the interruption. If changes exist, it commits and pushes them, opens the issue PR or updates the existing follow-up PR, and marks the result as potentially incomplete with the agent's last available summary and explicit remaining-work guidance. Other execution errors still fail normally, and an interrupted run with no changes has nothing to publish.
When tuning these values, consider repository size, task complexity, provider rate limits, worker concurrency, and host CPU and memory. Increase timeouts only after checking task and worker logs; a timeout may indicate missing context, provider slowness, a task that should be split, or an agent loop.
Security Boundary
The runtime should preserve these boundaries:
- Keep git finalization outside the agent.
- Mount only the workspace, the shared git directory, and required credential directories.
- Avoid further host filesystem mounts. The shared git directory already exposes every cloned repository to the agent, so separate repositories with different trust levels onto separate stacks.
- Keep credential directories scoped to the deployment user.
- Monitor container CPU, memory, and duration.
- Treat
--dangerously-*CLI flags as acceptable only because Docker is the outer isolation boundary.
Agent envVars redaction
Agent envVars values are treated as secrets at every administrative output boundary. GET/POST /api/config/agents, propr agent list/add (text and --json) and the MCP agent tools return only the variable names; each value is the fixed marker [REDACTED] (or the field is omitted), never a prefix, length, hash or encoding of the real value. Agent containers still receive the stored values. When a client saves the agent list back, a [REDACTED] value keeps the stored value for that variable on the same agent id; a new value replaces it, and a removed key deletes it. A marker with no stored value is rejected with 400.
Network Egress
Containers run on Docker's default bridge network with --security-opt no-new-privileges and --cap-add CHOWN, so outbound network access is unrestricted in the default open mode. The .propr/setup.sh hook runs under that same Docker privilege boundary and cannot use sudo to install system packages.
In restricted mode (instance setting agent_network_mode, or network.mode in .propr/workflow.yml), the Docker executor starts a per-container allowlist proxy in the worker process on a Unix socket under PROPR_EGRESS_SOCKET_DIR, replaces the container's network (whatever docker run named, or the default bridge) with --network none, mounts the socket directory read-only at /run/propr-egress, and sets HTTP_PROXY/HTTPS_PROXY, NO_PROXY and Git's http.proxy. A bridge started by the container wrapper exposes the socket as 127.0.0.1:3128 before setup hooks and the agent run. The proxy resolves DNS on the worker and refuses hosts outside the allowlist with 403, and chains allowed connections through the worker's own HTTPS_PROXY/HTTP_PROXY when set; it closes when the container's docker run exits. Native goal sessions, which spawn docker run directly, get the same proxy for the life of that process. No privileged flag or extra capability is used. See Restricted network mode.
Provider connectivity failures in open mode usually come from the host network, DNS, proxy settings, provider availability, or an external firewall. In restricted mode, check the task timeline's Restricted Network event for denied hosts first.
Monitoring And Debugging
Useful signals:
- Task logs in the Web UI
- Worker logs with correlation IDs
- Container exit code
- Agent stdout and stderr
- Session or conversation IDs when available
- Duration, timeout state, token usage, and usage-limit state
For direct Docker inspection:
docker ps
docker logs <container>
docker inspect <container>
Common Issues
Authentication Issues
For a direct-login account, check that the managed credential root is mounted and that the agent's generated path is still ~/.propr/agent-credentials/<agent-id>/…. For reused host credentials, check that the CLI is authenticated and the expected directory is mounted into the agent's container path. For example, Claude Code expects its selected directory at /home/node/.claude, while Codex expects its selected directory at /home/node/.codex.
Docker Permission Issues
Check that the deployment user can access Docker and that the launcher or worker can start sibling containers. If a container can start but cannot edit the worktree, inspect bind-mount ownership and the entrypoint diagnostics.
Network Issues
In the default open mode egress is unrestricted: check the host network, DNS, proxy configuration, external firewall rules, and provider status. In restricted mode, the task timeline's Restricted Network event lists every denied host; add a needed host to network.allow in .propr/workflow.yml or to the instance agent_network_allow setting. A container log line ProPR restricted network: egress proxy socket ... is missing means the Docker daemon cannot see the worker's PROPR_EGRESS_SOCKET_DIR; mount it at the same path, or set HOST_PROPR_EGRESS_SOCKET_DIR to the Docker host path.
Timeout Issues
Check worker logs, task logs, provider latency, and model routing before increasing timeout values. Persistent timeouts often mean the prompt is too broad, context is missing, or the provider is slow or rate limited.
Agent-Specific Configuration
Claude Code
Claude Code uses Dockerfile.agent, scripts/claude-entrypoint.sh, and the propr/agent image. The host credential directory is configured with CLAUDE_CONFIG_PATH or the agent config path and is mounted at /home/node/.claude.
Common settings:
AGENT_DOCKER_IMAGE=propr/agent:latest
CLAUDE_CONFIG_PATH=/home/your-user/.claude
CLAUDE_MAX_TURNS=1000
CLAUDE_TIMEOUT_MS=86400000
The entrypoint checks for /home/node/.claude/.credentials.json, creates expected Claude subdirectories such as todos, projects, shell-snapshots, and statsig, and prepares /home/node/.claude/projects/home-node-workspace for the mounted workspace.
For implementation tasks, the worker invokes Claude Code with the prompt on stdin:
claude -p - --no-session-persistence [--model <id>] --max-turns N --output-format stream-json --verbose --dangerously-skip-permissions
--max-turns comes from CLAUDE_MAX_TURNS. The worker captures Claude's stream JSON output, session ID, conversation log, and token usage when available.
Codex
Codex uses Dockerfile.agent, scripts/codex-entrypoint.sh, and the propr/agent image. The host credential directory is configured with the agent config path, commonly from HOST_CODEX_DIR, and is mounted at /home/node/.codex.
Common settings:
HOST_CODEX_DIR=/home/your-user/.codex
CODEX_TIMEOUT_MS=86400000
CODEX_STREAM_TRANSPORT=websocket
CODEX_STREAM_IDLE_TIMEOUT_MS=1800000
CODEX_STREAM_MAX_RETRIES=5
The entrypoint checks for /home/node/.codex/config.toml, prepares sessions and rules, and avoids recursively changing bind-mounted workspace ownership. Codex runs as:
codex exec --ephemeral --json --dangerously-bypass-approvals-and-sandbox --config features.multi_agent=false --skip-git-repo-check --cd /home/node/workspace -
When a model is selected, ProPR adds --model <id>. By default, ProPR selects a WebSocket-capable OpenAI provider with a 30-minute stream idle timeout so long, quiet turns are not pinned to a single HTTP response body. Set CODEX_STREAM_TRANSPORT=sse when WebSockets are unavailable or CODEX_STREAM_TRANSPORT=inherit to preserve a custom provider from the mounted Codex configuration. Codex emits NDJSON events that ProPR parses into logs, result text, session metadata, and token usage; reconnect notices remain visible without making a later successful turn fail.
Antigravity
Antigravity uses Dockerfile.agent, scripts/antigravity-entrypoint.sh, and the propr/agent image. The runtime resolves ANTIGRAVITY_CONFIG_PATH or the agent config path and mounts the selected host directory at /home/node/.gemini. If the configured path ends in .antigravity and a sibling .gemini directory exists, ProPR uses that .gemini directory for credentials.
Common settings:
HOST_ANTIGRAVITY_DIR=/home/your-user/.gemini
ANTIGRAVITY_CONFIG_PATH=/home/your-user/.gemini
ANTIGRAVITY_TIMEOUT_MS=86400000
The entrypoint prepares Antigravity runtime directories under the mounted config path and looks for auth, OAuth, credential, or token files. The agent CLI is agy; ProPR passes the selected model with --model <id> after translating ProPR model IDs into Antigravity CLI model IDs.
OpenCode
OpenCode uses Dockerfile.agent, scripts/opencode-entrypoint.sh, and the propr/agent image. The primary config mount is commonly HOST_OPENCODE_XDG_DIR=/home/your-user/.config/opencode, mounted at /home/node/.config/opencode.
Common settings:
HOST_OPENCODE_XDG_DIR=/home/your-user/.config/opencode
HOST_OPENCODE_DATA_DIR=/home/your-user/.local/share/opencode
OPENCODE_TIMEOUT_MS=86400000
AGENT_DOCKER_IMAGE=propr/agent:latest
The entrypoint sets OPENCODE_CONFIG_DIR=/home/node/.config/opencode and prepares XDG data and state directories. OpenCode runs in JSON mode through the OpenCode adapter (scripts/opencode-run.sh with --format json). ProPR passes the selected model with --model <id> and parses OpenCode responses back into the shared agent result shape.
Host Setup
Install OpenCode on the host and initialize the directories ProPR can mount:
curl -fsSL https://opencode.ai/install | bash
# or: npm install -g opencode-ai
mkdir -p ~/.config/opencode ~/.local/share/opencode
opencode --version
opencode auth login
OpenCode's config location is ~/.config/opencode; configure OpenCode agents with that path. The built-in free models run without provider login — operators only need credentials for OpenCode Go or any other authenticated provider they configure.
Auth Data
OpenCode stores provider auth in ~/.local/share/opencode/auth.json. When HOST_OPENCODE_DATA_DIR is set in the worker environment, ProPR mounts that host directory into OpenCode agent containers at /home/node/.local/share/opencode, read-write so the CLI can refresh auth metadata. When it is unset, ProPR infers the matching host data path for default config paths like /home/your-user/.config/opencode and mounts it when the directory exists.
Without either data mount, make credentials available another way:
- Pass provider API keys as agent
envVars. - Copy
auth.jsonunder the mounted config tree and pointXDG_DATA_HOMEat it in the agentenvVars(XDG_DATA_HOME=/home/node/.config/opencode/xdg-data). Re-sync the file after changing providers or refreshing OpenCode auth:
mkdir -p ~/.config/opencode/xdg-data/opencode && cp ~/.local/share/opencode/auth.json ~/.config/opencode/xdg-data/opencode/auth.json
By default the container receives XDG_CONFIG_HOME=/home/node/.config and XDG_DATA_HOME=/home/node/.local/share; the envVars override applies only for copied file-based auth. Authentication failures usually mean the configured config path does not point at the host's initialized OpenCode directory, HOST_OPENCODE_DATA_DIR/XDG_DATA_HOME does not point at mounted auth data, or the selected provider API key is missing or expired.
Model-ID Translation
ProPR catalog IDs for OpenCode carry the opencode- prefix, for example opencode-big-pickle. ProPR converts these back to OpenCode's native provider/model syntax at execution time (opencode-big-pickle becomes opencode/big-pickle) and strips only the internal opencode: routing prefix, so provider-qualified model IDs remain intact. The OpenCode model list is dynamic: run opencode models on the host after changing auth providers, then register any desired authenticated provider IDs (for example opencode-openai/gpt-5.5) on the agent's supported models. ProPR keeps only the built-in free OpenCode models as defaults and does not add authenticated provider models automatically. See Agents and Models for the catalog and label formats.
Mistral Vibe
Mistral Vibe uses Dockerfile.agent, scripts/vibe-entrypoint.sh, and the propr/agent image. The host config directory is configured with VIBE_CONFIG_PATH or the agent config path, commonly from HOST_VIBE_DIR, and is mounted at /home/node/.vibe when usable.
Common settings:
HOST_VIBE_DIR=/home/your-user/.vibe
VIBE_CONFIG_PATH=/home/your-user/.vibe
VIBE_TIMEOUT_MS=86400000
VIBE_MAX_TURNS=1000
VIBE_ANALYSIS_TIMEOUT_MS=1800000
MISTRAL_API_KEY=...
Vibe can use either a valid Vibe config directory or MISTRAL_API_KEY. The entrypoint copies config into a per-run runtime home, sets HOME and VIBE_HOME to that runtime directory, loads .env defaults from the Vibe home, and sets VIBE_ACTIVE_MODEL when ProPR selects a model.
Implementation prompts are written to a temporary prompt file and passed through the Vibe prompt-file runner so the prompt does not need to appear directly in process arguments. Analysis runs can use read-only config mode and a shorter VIBE_ANALYSIS_TIMEOUT_MS.