Starforge — Overview & Build Flow¶
Starforge is a BuildService port inside Starbase Worker, not a separate binary. It abstracts build execution so the build backend can be swapped without changing core logic.
§16.1 Decision Rationale¶
Starform does not run its own build infrastructure at launch. Running a multi-tenant BuildKit fleet with rootless isolation, cache tuning, and incident response is 3–4 months of upfront engineering plus ~10–20% of one engineer's ongoing time — a cost that pre-seed capital is better deployed elsewhere (egress differentiation, Layers, observability, billing). Builds are also the most visible reliability surface of a PaaS: every customer sees every build, and early rough edges damage trust disproportionately.
Starforge's MVP adapter uses Depot SaaS — a remote BuildKit service with a programmatic API designed for "build on behalf of customers" use cases. Fly.io, Hathora, and other platforms run on this pattern. Depot handles the compute, cache, and infrastructure; Starform handles the integration and the customer experience layered on top.
The BuildService port abstraction keeps this swappable. When Depot spend exceeds ~$3–5k/month, or
when a specific unmet requirement emerges (non-US data residency, custom frontends, GPU builds), a
second adapter (adapter/buildkit/) can be added without touching core logic.
§16.2 MVP Flow¶
flowchart TB
classDef built fill:#3434DC22,stroke:#3434DC,color:#5B5EE8;
classDef third fill:transparent,stroke:#808080,color:#808080;
classDef store stroke-dasharray:4 3,stroke:#808080;
PUSH["Git push<br/>GitHub webhook"]:::third
API["Starbase API<br/>enqueue build job"]:::built
PICK["Starbase Worker<br/>picks up job · clones source · inspects repo"]:::built
DECIDE{"Dockerfile at<br/>repo root?"}
RAILPACK["Railpack library<br/>detects framework · generates LLB"]:::built
SUBMIT["Starforge adapter → Depot API<br/>per-workspace project"]:::built
DPATH["Dockerfile path<br/>BuildService.CreateBuild · Dockerfile frontend"]:::built
RPATH["Railpack path<br/>BuildKitService · raw LLB submission"]:::built
DEPOT["Depot<br/>ephemeral BuildKit · workspace-scoped cache"]:::third
REG[("DO Container Registry")]:::store
LOGS["Worker streams build logs<br/>Depot → ClickHouse"]:::built
POLL["Worker polls build status → Postgres<br/>on success: update desired state w/ new image SHA"]:::built
TICK["Next Shuttle tick<br/>picks up new image · deploys"]:::third
PUSH --> API --> PICK --> DECIDE
DECIDE -- "yes" --> SUBMIT
DECIDE -- "no" --> RAILPACK --> SUBMIT
SUBMIT --> DPATH
SUBMIT --> RPATH
DPATH --> DEPOT
RPATH --> DEPOT
DEPOT --> REG
DEPOT --> LOGS --> POLL --> TICK
Dockerfile goes straight to BuildService.CreateBuild; otherwise Railpack detects the framework and emits LLB submitted via BuildKitService. Both share one per-workspace Depot project, push to the registry, stream logs to ClickHouse, and end at a Shuttle tick. Brand-blue boxes are Starform-built; gray are third-party; dashed is a data store.Cross-references
The BuildService port contract → §16.3 · the
Dockerfile-vs-Railpack frontend strategy → §16.5 ·
log streaming to ClickHouse → §16.6 · the Git push +
webhook entry point → §16.11 · the build state machine →
§16.12 · the Worker binary that runs this →
Starbase §14 · the desired state a finished build
updates → Foundations §32.