From Beginner to Advanced Issues
This roadmap is a deliberately ordered ladder of Firecracker contributions. Each rung trains
one skill, depends on the rung below it, and ends at a concrete, review-ready Pull Request
on github.com/firecracker-microvm/firecracker. Skipping rungs is the most common reason
strong engineers stall here: a virtqueue fix without the virtio transport in your head turns
into a months-long PR thread, and a snapshot-compat change without the Persist/versioning
reflexes turns into a restore that silently corrupts a customer's microVM state. The stages
exist so you climb in the order the codebase rewards.
Firecracker is single-vendor governed: a dedicated AWS team owns it, there is no separate
foundation, no JIRA, no CLA. The source of truth is GitHub — issues and Pull Requests. Every
commit carries a DCO sign-off (git commit -s, the Signed-off-by: line), new functionality
needs an integration test, and merging needs two maintainer approvals. CI is GitHub
Actions plus Buildkite; the local pre-flight is tools/devtool checkstyle and
tools/devtool checkbuild --all. If you are arriving from a JIRA project, drop the patch-file
muscle memory: the unit of work is a branch on your fork and a PR against main.
The stages are calibrated to the Firecracker main branch (v1.16 era; swagger 1.17.0-dev —
verify on your branch). The codebase recently went through a large refactor that merged most
crates into a single vmm crate, so almost everything you read lives under src/vmm/src/. Where a
stage names a module it uses the current top-level shape you will see in a checkout:
src/vmm/ the core VMM library — machine model, vCPU/KVM state, ALL device emulation,
snapshots, mmds, rate limiting, seccomp install, logging. The big crate.
src/firecracker/ the firecracker binary + the HTTP API server (src/firecracker/src/api_server/)
src/jailer/ the jailer binary (chroot/cgroups/namespaces/priv-drop, then exec firecracker)
src/seccompiler/ JSON seccomp filter -> BPF compiler (baked into the binary at build time)
src/cpu-template-helper/, src/snapshot-editor/, src/rebase-snap/, src/acpi-tables/, src/utils/
tests/ the pytest integration harness (the primary suite; NOT raw cargo test)
resources/ seccomp JSON (resources/seccomp/), guest kernel configs (resources/guest_configs/)
tools/ devtool — the Docker-based build/test/style driver
docs/ getting-started, jailer, seccomp, snapshotting/, prod-host-setup, ...
Note: Code moves between branches and the refactor is recent. This roadmap never cites line numbers and rarely cites exact paths without an
rg/findto locate the thing on your checkout. When you see a struct or function named, run the command next to it. A contributor who trusts a memorized line number is already wrong.
The Twelve Stages
The ladder runs from changes a reviewer will barely have to think about (docs, a missing test) to changes that can hold a release (regressions, CVE-class fixes). The left half is about the contribution mechanics and the request/config path; the right half is about the correctness-critical core — the vCPU, the devices, snapshots, security — where a bug can crash a guest, leak across a tenant boundary, or corrupt restored state.
| # | Stage | Target skill | Prereq level | Primary subsystem | Typical PR size |
|---|---|---|---|---|---|
| 1 | Docs & tests | GitHub flow, DCO, CHANGELOG, devtool | none | docs/, comments, unit tests | 1–40 lines |
| 2 | Build, tooling & logging | devtool, clippy/fmt, log messages, CI | 1–2 | tools/, logger/, build scripts | 5–80 lines |
| 3 | Error messages & diagnostics | Rust error enums, thiserror, context | 2–3 | *Error enums across vmm | 20–150 lines + test |
| 4 | API & config validation | request parsing, vmm_config bounds checks | 3 | vmm_config/, rpc_interface.rs | 30–250 lines + test |
| 5 | Device configuration | block/net/vsock/balloon config, rate limiter, MMDS | 3, 7 | vmm_config/, rate_limiter/, mmds/ | 40–300 lines + test |
| 6 | vCPU & KVM | run loop, VcpuExit, ioctls, CPUID/MSR | 4 | vstate/vcpu/, cpu_config/, arch/ | 40–400 lines + test |
| 7 | Virtio devices | virtqueues, feature negotiation, I/O correctness | 7 | devices/virtio/ | 50–500 lines + test |
| 8 | Snapshot compatibility | Persist, MicrovmState versioning, restore | 9 | persist.rs, snapshot/, device Persist impls | small code, long thread |
| 9 | Flaky tests | pytest harness, races, timing, tests.seed | 5 | tests/, *_test.rs | 20–150 lines |
| 10 | Performance | boot time, mem overhead, io_engine, perf CI | 9 | hot paths in vmm, tests/integration_tests/performance/ | 30–300 lines + numbers |
| 11 | Security & seccomp | seccomp filters, jailer, attack surface | 9 | resources/seccomp/, seccomp.rs, jailer/ | small code, security review |
| 12 | Release-blocking | regression triage, release policy, CVE handling | maintainer | whole-project | varies |
Stages 6–8, 10, and 11 share a prerequisite band rather than a strict order: once you have the vCPU run loop and the virtio transport in your head (Levels 4 and 7), you can branch into KVM edge cases, virtqueue bugs, snapshot versioning, performance, or seccomp depending on the issue in front of you. Stage 9 (flaky tests) sits off to the side — it needs the pytest harness fluency of Level 5 but not the deep subsystem knowledge, so many contributors interleave de-flaking work with everything else.
How Firecracker labels map to stages
Firecracker issues are labelled on GitHub. There is no component tree; a combination of type, status, priority, and a few special labels does the same job. Every stage's issue search is built from these. The exact strings drift across releases — verify the current set on the tracker rather than memorizing them:
# List the live labels (names + descriptions). Run this before trusting any label string below.
gh label list --repo firecracker-microvm/firecracker --limit 100
| Label (verify on the tracker) | Meaning | Which stages use it |
|---|---|---|
good first issue | curated, small, mentor-friendly | 1, 2 |
Type: Bug | incorrect behaviour | 3–12 |
Type: Enhancement | new behaviour / improvement | 2, 4, 5, 10 |
Type: Documentation | docs / comments / help text | 1 |
Type: Performance | latency, throughput, memory overhead | 10 |
Status: ... (e.g. Awaiting review, Parked) | lifecycle state | scope by these |
Priority: ... (High/Medium/Low) | maintainer-assigned urgency | 12 weighs these |
Kani | formal-verification (model-checking) work | advanced; vstate/virtio proofs |
Roadmap: ... | tracked larger initiatives | read, don't blindly patch |
The canonical search, reused (with different labels) in every stage:
# Open, unassigned, recently touched — paste the equivalent into the GitHub search box too.
gh issue list --repo firecracker-microvm/firecracker \
--state open --label "good first issue" --search "no:assignee sort:updated-desc" --limit 30
no:assignee is the single most useful filter: it skips issues someone is already working. Each
stage also gives at least one fallback rg to find a candidate in the source when labels return
nothing — because in a single-vendor project, many real bugs are filed by the team without a tidy
good first issue tag.
How to use this roadmap
Pick a stage honestly
Find your rung by asking what is the largest change you have shipped to Firecracker:
- Never landed a Firecracker PR → start at Stage 1.
- Landed a docs PR but never touched Rust in
src/vmm/→ Stage 2. - Comfortable reading
vmmbut never traced an API request to aVmmAction→ Stage 3–4. - Read the vCPU run loop once and were confused → Stage 6 after redoing Level 4.
- Could draw the virtio split-virtqueue from memory → Stage 7+.
- Already a maintainer-track contributor → Stages 10–12 for sharpening.
Do not jump rungs to chase a "cool" bug. An unhandled VcpuExit looks self-contained and isn't —
the fix lands on the run-loop dispatch you have never instrumented and a KVM contract you have never
read (Stage 6 prerequisite work). The roadmap rewards small surface area arrived at honestly.
One concern per PR, one CHANGELOG line per release
Firecracker reviewers reject mixed-concern PRs reflexively. One logical change per commit, each
commit passing tests on its own. User-visible changes add a one-line entry to CHANGELOG.md
under the unreleased heading. If you cannot name your change in one line, it is doing too much —
split it and file a follow-up issue.
Always start with git log and git blame
Before touching a file, find who cares about it and how it last changed:
git log --oneline -n 8 -- src/vmm/src/devices/virtio/block/
git blame -L 1,60 src/vmm/src/devices/virtio/block/device.rs # who last touched this region
The blame output tells you which maintainer owns the area — useful context when you write the PR description, and a fast way to find the test that guards the code (the same commit usually added it).
Read the workflow once, then never re-explain it
Every stage from 2 onward assumes the Stage 1 mechanics: fork → branch → DCO sign-off → CHANGELOG
entry (if user-visible) → tools/devtool fmt → tools/devtool checkstyle →
tools/devtool checkbuild --all → PR → read CI → respond to review.
Stage 1 drills all of it. Later stages spend their words on code.
Open a discussion before you write code (Stage 4 and up)
For anything touching the device model, the vCPU, snapshots, or security, comment on the issue with a three-sentence plan before the diff:
I see <symptom> at <module> (rg below). My read is <cause>. I plan to <fix>, with an
integration/unit test in <test file>. Anything I'm missing before I open a PR?
In a single-vendor project the maintainers know the unstated invariants — the minimal-device-model philosophy, the snapshot wire format, the seccomp allow-list rationale. Three sentences first saves weeks. This matters more here than in most projects because "QEMU has it" is explicitly not an argument: added surface area faces a high bar.
Time investment per stage
Calibrated against a contributor who has the repo checked out, can run tools/devtool build and
tools/devtool test, and has opened at least one PR:
| Stage | First PR | Becoming fluent (≈5 PRs merged) |
|---|---|---|
| 1 | half a day | 1 week |
| 2 | 1 day | 2 weeks |
| 3 | 1–2 days | 3–4 weeks |
| 4 | 2–4 days | 1–2 months |
| 5 | 3–6 days | 2–3 months |
| 6 | 1–2 weeks | 3–6 months |
| 7 | 2–4 weeks | 6 months |
| 8 | 2–4 weeks (compat review) | 6+ months |
| 9 | 1–3 days per flake | ongoing |
| 10 | weeks (bench-bound) | maintainer-level skill |
| 11 | weeks (security review) | maintainer-level skill |
| 12 | maintainer responsibility | n/a |
What to read alongside this roadmap
What this roadmap is not
It is not a tutorial on Firecracker itself. The deep dives cover the
architecture; the labs from Level 1 onward cover hands-on code reading. The
roadmap assumes you can already build from source, run tools/devtool test, and boot a microVM by
hand from your own build. If you cannot, the prerequisite is Level 1.
It is not a generic open-source guide either. CONTRIBUTING.md, docs/, and the PR template in the
repo cover account setup, the DCO mechanics, and the test commands; the roadmap assumes you read them
once. And it is not a roadmap to maintainership — that path the AWS team manages (see
the maintainer mindset). The roadmap teaches the skills
that, applied consistently, make maintainership a realistic outcome. Landing PRs is necessary, not
sufficient.
How the stages interlock
Each stage builds vocabulary the next stage uses without re-explaining:
- Stage 1 teaches the PR artifact: fork, DCO, CHANGELOG, devtool. Every later stage assumes it.
- Stage 2 teaches the build/style gates and Firecracker's logging idioms. Stage 3 builds on the logging discipline with the rule that every error carries actionable context.
- Stage 3 teaches the
*Errorenums and how a failure surfaces to the API caller. Stage 4 follows the request earlier — into request parsing andvmm_configvalidation, before a bad value ever reaches a device. - Stage 4 teaches config validation in the abstract. Stage 5 applies it to the real devices: block, net, vsock, balloon, the rate limiter, MMDS — and starts touching device internals.
- Stage 6 teaches the vCPU/KVM layer beneath every device. Stage 7 teaches the virtio device model that rides on top of it. These two are the correctness-critical heart of the VMM.
- Stage 8 teaches snapshot/restore and the
Persisttrait — which requires understanding the device state from Stages 5–7 and the versioning discipline that makes a saved microVM restorable on a different binary. - Stage 9 teaches deterministic testing. Stage 10 uses that determinism as the baseline for stable benchmarks. Stage 11 treats every change as an attack-surface change. Stage 12 weighs all of it when deciding whether an issue blocks a release or merely waits for the next one.
Skipping a stage means skipping a vocabulary. Reviewers will notice.
Now turn to Stage 1.