With the forge hosting the code, the next piece is a runner that tests it. Celilo deploys its own CI worker — again as a module — so that every push and every pull request checks itself automatically, on hardware in the lab, with no outside CI vendor in the loop. The runner registers with the forge, waits for jobs, and runs the project’s real tests against them.
A runner wired through capabilities
The runner is a separate module from the forge, and the two connect through
Celilo’s capability system: the forge provides a source_forge capability that
mints a short-lived registration token, and the runner consumes it. The token
never gets hand-copied through a UI — it crosses the boundary through Celilo’s own
secrets machinery, which is exactly the cross-module wiring Celilo exists to
demonstrate. Because the runner holds nothing precious, redeploying it is cheap
and lossless.
Light work and heavy work
Not every check needs the same muscle. The runner comes in two profiles. A
light runner handles the fast tier — unit tests, linting, type-checking,
publish dry-runs — and runs on every push. A builder profile carries the heavy
tier: the full end-to-end suite, which spins up a large multi-container topology
and takes the better part of an hour. Gating every commit on that would bring
back exactly the slow iteration CI was meant to remove, so the heavy suite runs
on demand or on a schedule instead.
Contained by design
The runner needs no inbound access at all — it reaches out to the forge for work rather than being reached. That lets it sit in the lowest-trust zone that can still do its job, where its outbound traffic can eventually be locked down to just the destinations it legitimately needs. The box that runs code is treated like the box that runs code.