Skip to content
Select themeSelect language

Run the App build worker

Building an App’s frontend (React, Svelte or a plain source folder) does not happen inside the API process. A separate build worker polls the queue, claims one build at a time, runs vite build, and reports the outcome. This page is how you run it.

On 2026-08-28 a fleet-wide sweep for orphaned containers found one on the stage host that had been running for 58 days under the name stage-app-builder-oneshot. It carried no com.docker.compose.project label, so nothing owned it and nothing would ever have restarted it. It was one decision away from being reaped as garbage.

It was not garbage. It was the build worker, behaving exactly as designed.

Two things made that near-miss possible, and this page closes both:

  1. The name lied. Nothing about oneshot is true of a queue poller.
  2. Its absence is invisible. There is no alarm on “nobody is polling the build queue”. Remove the worker and App builds simply queue forever; nothing fails, nothing pages, and the first symptom is a user reporting that a build “does nothing”.

Run it as a compose service, never as a hand-started docker run. A hand-started container does not survive a host reboot, carries no project label, and is indistinguishable from litter to anyone cleaning up.

services:
supacloud-app-builder:
image: git.blockworx.tech/blockworx/supacloud-agent-unified:node
restart: unless-stopped
environment:
AGENT_TYPE: app_builder
SUPACLOUD_API_URL: https://app.example.com
RUNNER_TOKEN: ${SUPACLOUD_RUNNER_TOKEN}

Name it for what it is. supacloud-app-builder is the canonical name; anything containing oneshot, job, or temp is wrong and will invite deletion.

Variable Required Meaning
AGENT_TYPE yes Must be exactly app_builder. It selects the short-circuit in the runner’s entry point, before the harness-adapter registry is consulted.
SUPACLOUD_API_URL yes Base URL of the SupaCloud API. Trailing slashes are stripped.
RUNNER_TOKEN yes The runner credential. SUPACLOUD_RUNNER_TOKEN is accepted as an alias.
BUILD_POLL_INTERVAL_MS no Milliseconds between polls of an empty queue. Defaults to 5000; a non-numeric or non-positive value falls back to the default rather than failing.
BUILD_ALLOW_POSTINSTALL no Accepts 1 or true. Permits npm postinstall scripts during the build. Leave it unset. It is off by default because a postinstall script is arbitrary code from a dependency tree.

Do not set TASK_ID or TASK_PROMPT. Every other runner mode requires them; this mode is explicitly exempt, because it is not bound to a task. Setting them does no harm but misrepresents the process.

A missing SUPACLOUD_API_URL or RUNNER_TOKEN makes the worker exit immediately with a named error rather than polling silently, so restart: unless-stopped is safe: a misconfigured worker crash-loops visibly instead of pretending to work.

The queue claim is transactional and uses FOR UPDATE SKIP LOCKED, so two workers never claim the same build. Running a second worker is therefore both safe and the simplest defence against the silent-stall failure above: with one worker, its loss stops all builds; with two, the survivor keeps the queue moving.

The worker’s health is not “the container is up” — a poller with a bad token that crash-loops looks up between restarts. Check the queue instead:

  • From the fleet: the container exists, carries a compose project label, and its log shows Starting unified runner in app_builder mode followed by poll activity rather than a repeating startup error.
  • From the product: trigger a build for any App and confirm it leaves the queued state. A build that stays queued while the API is healthy means nothing is claiming it.
Symptom Cause Fix
Builds stay queued forever, API healthy No worker is running, or every worker is crash-looping Check the service is up and read its first log line
Worker exits immediately, SUPACLOUD_API_URL is required Variable unset or empty Set it; note that a trailing slash is stripped, not rejected
Worker exits immediately, RUNNER_TOKEN is required Neither RUNNER_TOKEN nor SUPACLOUD_RUNNER_TOKEN set Set one
Worker polls but never claims Queue is genuinely empty, or the token lacks access Queue a build and watch the log
Container disappeared after a host reboot It was hand-started, not a compose service Deploy it as shown above