CI runners that appear,
run, and disappear.
Every job gets a fresh Firecracker microVM with its own kernel, restored from a snapshot in 49ms and deleted when the job ends. Run pull requests from forks, dependabot bumps, and coding agents without ever handing them a persistent machine.
A malicious test meets a dedicated kernel.
CI executes whatever the PR author wrote — and on a persistent runner, so does their exploit. A PandaStack job runs inside a microVM behind hardware virtualization: the worst a hostile test can do is trash a VM that was about to be deleted anyway.
| PandaStack microVM job | persistent self-hosted runner | |
|---|---|---|
| Kernel | dedicated per job | shared with every job that ran before |
| Escape blast radius | one throwaway VM | the runner host — and its secrets |
| State between jobs | none — fresh snapshot every time | leftover caches, daemons, dotfiles |
| Idle cost | $0 — nothing runs between pushes | a warm machine on the clock 24/7 |
| Cleanup | delete at job end; TTL reaper as backstop | hygiene scripts and hope |
Same snapshot in, throwaway VM out.
Every job restores the same baked template snapshot, so the runner a flaky test saw yesterday is bit-for-bit the runner it sees today. Bake your toolchain into the template and jobs skip setup entirely — they start at the interesting part.
No dirty runners, no leaked runners
“Works on the runner” flakes come from state a previous job left behind. Here there is no previous job: create, copy the repo in, run the suite, read the logs, delete. Your API token lives in CI secrets like any other credential.
Create each sandbox with a TTL, and even a pipeline that dies mid-job can't leak a runner — the reaper collects it when the clock runs out.
# PANDASTACK_API_KEY lives in CI secrets
set -euo pipefail
sandbox_id=$(pandastack -o json sandbox create \
--template base --ttl 1h | jq -r '.id')
pandastack sandbox cp ./repo.tar.gz \
"$sandbox_id:/workspace/repo.tar.gz"
pandastack sandbox exec "$sandbox_id" -- bash -lc \
'cd /workspace && tar -xzf repo.tar.gz && cd repo && ./ci.sh'
pandastack sandbox logs "$sandbox_id" --no-follow --stream both
pandastack sandbox delete "$sandbox_id"Matrix builds without a runner pool.
A 49ms boot is faster than waiting in a pool's queue, so there's nothing to pre-provision: create one microVM per matrix entry at job start, run every shard in parallel on its own kernel, and let the fleet vanish when the pipeline goes green.
No pool to keep warm
Runners are created on demand and deleted at job end. Between pushes your CI fleet is zero machines — and bills accordingly.
One microVM per shard
Fan a test matrix out as parallel sandboxes. Shards can't contend for a shared runner's CPU, and one shard's crash can't poison another's environment.
Burst CPU, metered honestly
Every first-party template bakes 8 vCPUs of burst capacity, and CPU is billed by active CPU-seconds actually used — headroom costs nothing while a job waits on I/O.
One primitive, your whole CI fleet.
This solution is a usage pattern over the platform's sandbox primitive — the same 49ms microVMs that power agent sessions, driven from your CI provider's shell step.
Ship on the millisecond cloud.
Free tier with $5.40/mo usage credit. No card. Apache-2.0.