Imp: running one CI job in one microVM
Format: 20-minute technical walkthrough. Truth boundary: the player below is a source-backed reconstruction with observed run metadata. It is not a live control plane and it sends no commands to GitHub, Kubernetes, or Unraid.
The decision — 0–2 minutes
How can a CI job keep Kubernetes for desired state while receiving a stronger execution boundary than a container?
Imp uses Kubernetes for the control plane. The job itself runs in a Firecracker microVM with a separate guest kernel. The trade-off is lifecycle complexity: credentials, handoff, cleanup, and warm capacity must all remain safe.
Ownership and architecture — 2–5 minutes
flowchart LR
k8s[Kubernetes desired state] --> operator[Imp operator]
operator --> vm[ImpVM record]
vm --> agent[Node agent Pod]
agent --> fc[Firecracker process]
fc --> guest[Guest Linux runner]
guest --> github[GitHub Actions]Plain explanation: the operator decides how many VMs are needed. Imp selects an eligible Linux node. The node agent starts Firecracker. GitHub selects a matching runner only after that runner registers.
Credentials and execution boundaries — 5–8 minutes
The long-lived GitHub App key remains with the operator. The operator mints a one-time runner setup, stores it in a Secret owned by the individual ImpVM, and the node agent hands it to the guest over VSOCK as an environment variable. The browser demo never contains that Secret, its data, a JIT payload, a token, a private key, or raw logs.
A JIT configuration proves only that GitHub issued setup data. It does not prove registration or job assignment. A final job match belongs to GitHub's runner-group and label rules.
Recorded walkthrough — 8–14 minutes
LOCAL TERMINAL PLAYBACK
Imp BSA walkthrough — source-backed reconstruction
Source-backed walkthrough. Paused at the beginning.
1. Demand and identity. Frame 1 of 4. Paused.
SOURCE-BACKED RECONSTRUCTION — NOT A LIVE RECORDING
When this player is focused, Space plays or pauses; Left and Right Arrow seek one frame. Seeking and chapter navigation pause playback.
Chapter evidence
| Chapter | What to notice | What this proves | Provenance |
|---|---|---|---|
| 1. Demand and identity | Capacity and GitHub identity are distinct | The controller can request one-time setup without exposing the App key to a VM | source-backed manifest |
| 2. VM and VSOCK | github-runner-nvksj reached Ready=True | One observed VM boot, plus the source-backed VSOCK handoff design | still |
| 3. Assignment and execution | GitHub assigns after registration | Job 102581785413 ran on imp-runner-1788975945509078350 in omni-runner | still |
| 4. Completion and cleanup | Exit, Secret removal, deregistration are separate facts | The observed runner exited 0; its one-time Secret was removed and registration disappeared | still |
| 5. Replenishment | Warm capacity does not require deletion | After 90 seconds, the pool retained one warm VM at minIdle=1 | still |
Observed live provenance: capture date 2026-09-09; release commit ab7b5532810b29207fe914841467bdf69b09ff02; workflow 34354436248, job 102581785413; runner-layer digest is recorded in Demonstration Evidence. The local assets are sanitized stills and transcript fallback, not a terminal capture.
Failure semantics and trade-offs — 14–18 minutes
| Boundary | Current behavior | Important limit |
|---|---|---|
| JIT mint or Secret write fails | The controller removes the unconfigured VM instead of leaving it to boot | No JIT Secret means no runner setup is attached |
| Guest handoff becomes ambiguous | The launcher refuses replay | Avoids reusing a one-time setup or creating two runners |
| Firecracker exits | The agent owns local runtime stop handling | Object finalization is not proof that runtime cleanup already happened |
| Runner completes | The pool controller removes terminal VMs | A warm VM may remain when minIdle needs capacity |
For organisation-scoped pools, the current polling method reports zero queue depth. Do not infer that organisation polling caused a scale-up. Use an externally written demand signal or pre-warmed minIdle capacity instead.
Verdict and discussion — 18–20 minutes
Imp makes the strong boundary possible by separating decisions: Kubernetes stores desired state, Imp coordinates capacity and placement, the node agent owns local VM lifecycle, and GitHub owns final job matching. The live evidence proves one harmless end-to-end run. It does not prove VM deletion or replacement, every failure recovery path, or a general production SLO.
