docs/deploy/runners.md

Runners and external workers

Some work outlasts a web request: an hours-long build, a large research job. Vocion hands it to a worker outside the app and keeps control of it.

External workers

Turn on with VOCION_EXTERNAL_WORKERS=1. A worker run is created by the API (POST /api/v1/worker-runs) or by an agent with harness.runsOn: external-worker. A worker claims it, heartbeats, checkpoints and completes or fails it (/api/v1/worker-runs/{id}/claim|heartbeat|checkpoint|complete|fail|cancel). Vocion leases each run, enforces its budget and deadline, records its cost and the workspace version, and reaps runs whose worker went silent.

The engineering runner

The runner builds Software Factory tasks. It claims a queued engineering run, clones the repository, starts the services its tests need, runs headless Claude Code under guard hooks, runs the repository's checks, and opens a pull request — or keeps the work on a draft PR when it stops short. It captures before/after screenshots for visible changes.

  • Image: ghcr.io/vocion/vocion-runner, built from packages/runner. Tags: sha-<core commit> and 5.x on main; 4.x on the 4.x line.
  • Pin it: set VOCION_RUNNER_IMAGE to the sha- tag of the core commit you run (or :5.x). The :main tag is a 4.x alias.
  • Token: VOCION_RUNNER_TOKEN, the same value in the app and the runner. A claim returns a run token scoped to that one workspace; the runner never holds a workspace's own token.
  • Model key: the runner's ANTHROPIC_API_KEY. The repository's code goes to Anthropic.

Where it runs

Declare targets once per installation in VOCION_RUNNERS (JSON) or a file named by VOCION_RUNNERS_FILE:

{ "targets": [
  { "name": "aws-fargate", "kind": "aws-fargate", "region": "us-east-1",
    "cluster": "vocion-runners", "taskDefinition": "vocion-runner",
    "subnets": ["subnet-…"], "securityGroups": ["sg-…"] },
  { "name": "on-box", "kind": "on-box" }
] }
TargetHow
aws-fargateOne Fargate task per run, started when the run is queued. vocion-stack builds it with runners_enabled = true (runner_max_budget_usd 12, runner_wall_clock_minutes 45 by default)
on-boxThe vocion-runner compose service on the app host (profile runner, secrets in runner.env), one run at a time; by default it takes runs that waited 120 s unclaimed

With nothing declared, an installation has the on-box target alone. A repository becomes buildable once its repo record says how: its checks, services, setup, human-owned paths and QA surface.