Runner Service Infrastructure#
The runner (formerly sandbox-agent) is a Node.js/TypeScript sidecar service that executes agent workloads inside isolated sandboxes. It lives at services/runner/ (renamed from services/agent/ in PR #4968) and exposes an HTTP API on port 8765. The Python services container calls the runner over the Docker network for all sandboxed execution.
The service was first wired into the dev compose stack in PR #4776 and had its CI pipeline and GHCR publication established in PR #4804.
Architecture#
The runner is a sidecar to the services container. services routes all agent execution requests to http://runner:8765 (configured via AGENTA_RUNNER_INTERNAL_URL) and depends on the runner being healthy before it starts .
ββββββββββββββββββββββββββ http://runner:8765
β services (Python API) β βββββββββββββββββββββββββββΊ runner (Node.js / TS)
ββββββββββββββββββββββββββ β
βββ local sandbox provider
βββ daytona cloud sandbox
Key design choices:
- Intentionally isolated env: The runner receives no
env_filefrom the main stack. It only gets its own port, auth token, Pi credentials, and Daytona API keys β never application-layer secrets . - Elevated Linux capabilities: Durable session workspaces use geesefs (FUSE) for S3-backed mounts. The runner container therefore requires
SYS_ADMINcapability,/dev/fusedevice access, andapparmor:unconfined. - Token auth:
AGENTA_RUNNER_TOKENmust be set and shared betweenservicesandrunner. The runner defaults to loopback (127.0.0.1) but binds to0.0.0.0in compose so the sidecar is reachable cross-container . - Sandbox providers:
AGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERSandAGENTA_RUNNER_DEFAULT_SANDBOX_PROVIDERcontrol which execution backends are active (default:localin dev) .
Docker Compose Configuration#
Dev (EE) β hosting/docker-compose/ee/docker-compose.dev.yml#
The runner service :
- Image:
agenta-ee-dev-runner:latest, built fromservices/runnerusingdocker/Dockerfile.dev - Command: rebuilds the Pi extension (
node scripts/build-extension.mjs), then launchestsx src/server.ts - Volumes:
services/runner/src:/app/srcβ live-reload sourceservices/runner/skills:/app/skillsβ agent harness skills~/.pi/agent:/pi-agent:rwβ read-write Pi OAuth token (persists refreshes back to host)
- Health check: polls
http://127.0.0.1:8765/healthvia Nodefetch, 20 s start period, 10 s interval, 12 retries - Runtime:
cap_add: [SYS_ADMIN], device/dev/fuse,apparmor:unconfined
The services container passes AGENTA_RUNNER_INTERNAL_URL=http://runner:8765 and depends on runner: condition: service_healthy .
Production / GH (OSS) β hosting/docker-compose/oss/docker-compose.gh.yml#
The snapshot of the OSS GH compose in this knowledge base predates the runner's addition . PR #4804 added AGENTA_SANDBOX_AGENT_IMAGE_NAME / AGENTA_SANDBOX_AGENT_IMAGE_TAG env-file hooks for configuring the runner image in production . PR #4968 subsequently wired the runner sidecar into all deployment surfaces β EE, OSS gh/gh.ssl, Helm, and Railway β completing non-dev coverage .
GHCR Publication & CI#
PR #4804 added two GitHub Actions jobs for the runner :
Build & publish (.github/workflows/42-railway-build.yml):
- Builds a multi-arch image (amd64 + arm64) from
services/runner - Dockerfile:
services/runner/docker/Dockerfile - Published to
ghcr.io/agenta-ai/agenta-sandbox-agent(now renamed toagenta-runnerfollowing PR #4968)
Unit tests (.github/workflows/12-check-unit-tests.yml):
- Job:
run-services-node-unit-tests - Runs
pnpm run typecheck(TypeScript) andpnpm run test:unit(vitest) - Publishes JUnit results from
services/runner/test-results/junit.xml
Note on distributed images: Published images do not bundle Claude Code. Claude is installed at runtime from Anthropic. Self-hosted operators who want Daytona sandboxes pre-loaded with the Pi CLI can build a custom snapshot using
services/runner/sandbox-images/daytona/build_snapshot.pyβ this must be run in their own Daytona account .
Key Environment Variables#
| Variable | Description | Default (dev) |
|---|---|---|
AGENTA_RUNNER_PORT | Port the runner binds to | 8765 |
AGENTA_RUNNER_HOST | Bind address | 0.0.0.0 (compose) |
AGENTA_RUNNER_TOKEN | Shared auth token (required) | β |
AGENTA_RUNNER_INTERNAL_URL | How services reaches the runner | http://runner:8765 |
AGENTA_RUNNER_ENABLED_SANDBOX_PROVIDERS | Comma-list of active providers | local |
AGENTA_RUNNER_DEFAULT_SANDBOX_PROVIDER | Default provider for new sessions | local |
AGENTA_RUNNER_DAYTONA_API_KEY | Daytona cloud credentials | β |
AGENTA_RUNNER_DAYTONA_API_URL | Daytona API endpoint | β |
AGENTA_RUNNER_DAYTONA_SNAPSHOT | Daytona snapshot name | β |
AGENTA_API_INTERNAL_URL | API URL reachable from the runner container | http://api:8000 |
Variables were previously prefixed AGENTA_AGENT_RUNNER_*; renamed to AGENTA_RUNNER_* in PR #4968.
Primary Sources#
| Source | Description |
|---|---|
services/runner/ | Runner service root (TypeScript/Node.js) |
services/runner/docker/Dockerfile | Production image |
services/runner/src/server.ts | HTTP server entry point |
hosting/docker-compose/ee/docker-compose.dev.yml | EE dev compose β runner service block |
hosting/docker-compose/oss/docker-compose.gh.yml | OSS GH production compose |
| PR #4776 | Initial compose wiring of the sidecar |
| PR #4804 | CI build, GHCR publish, self-host docs |
| PR #4968 | Rename to runner, non-dev wiring, OIDC store |