openswarm-runner
One ephemeral Linux container that executes ONE OpenSwarm workflow run and exits. One Fly Firecracker machine per run, no state kept.
Build
The build context is the repo root, not this directory (the image needs backend/
and backend/requirements.lock):
docker build --platform linux/amd64 -f openswarm-runner/Dockerfile -t openswarm-runner .
Run
The container is told everything it needs by one JSON run spec in OPENSWARM_RUN_SPEC
(or a path in OPENSWARM_RUN_SPEC_FILE). See runner/run_spec.py for the typed shape.
{
"run_id": "cr_01J...",
"workflow": { "id": "wf_1", "title": "Daily digest", "model": "opus-5",
"steps": [{ "text": "summarize my inbox" }] },
"credentials": [
{ "provider": "claude", "auth_type": "oauth",
"access_token": "<already refreshed by the control plane>",
"expires_at": "2026-07-31T20:00:00Z" }
],
"callback": { "url": "https://api.openswarm.com/api/cloud-runs/cr_01J.../report",
"token": "<two-party runner token, not a user credential>" },
"max_run_seconds": 1800
}
Exit codes: 0 ok, 1 runner crash, 2 bad spec, 3 credential expired on arrival,
4 backend never came up, 5 workflow failed, 6 wall-clock cap hit.
The credential rule
A providerConnections[] entry this runner writes never contains a refreshToken.
9Router's refresh dispatcher bails on if (!b || !b.refreshToken) return null, so
omitting the field is what makes the container incapable of rotating the user's grant.
If it ever rotated, the user's laptop would be left replaying a dead token and the
provider would revoke the whole grant family.
Two independent walls enforce it, and a third makes a leak require deleting the code that builds the entry:
ProviderCredentialforbids extra fields, so a spec carryingrefreshTokenfails validation before the backend boots.assert_no_refresh_tokenre-reads the assembled db payload just before the write.router_connectionassembles the entry from a fixed key list, never a passthrough.
All three live in runner/seed/router_credentials.py.
An access token that arrives expired fails the run (exit 3). The runner never refreshes.
Test
PYTHONPATH=.:openswarm-runner backend/.venv/bin/python3 -m pytest openswarm-runner/tests -q
Deploy
Not deployed. fly.toml is written but never applied; read its header first, the app
has to be created onto its own isolated private network by hand before any deploy.