Step 1: Issue Selection
The single biggest predictor of whether your Capstone ships is the issue you pick
in the first few days. Pick something too large and you will still be tracing
KVM_RUN exits in week three. Pick something already half-fixed and you will burn
days before a maintainer points it out. Pick something you cannot reproduce and you
have nothing to build on.
A good Capstone issue is real (open, maintainer-acknowledged), tractable
(fixable in a focused diff, not a redesign), reproducible (you can make it fail
on demand), and matched to your level (it lives in a subsystem you traced in
Levels 1–9). This step is how you find one with gh, score it, and claim it
without stepping on anyone.
Goal
Leave this step with one issue number you can defend as the right choice, a public claim comment, a written scope estimate, and a feature branch. Everything downstream assumes the issue is well-chosen; an hour of selection discipline saves a week of thrash.
Where the Issues Live
Everything is on GitHub, and you will drive it from the terminal with gh — never
trust a cached screenshot of the issue list, because the label vocabulary and the
open set drift. Authenticate first (gh auth status), then:
REPO=firecracker-microvm/firecracker
# The whole open issue list, newest first.
gh issue list --repo $REPO --state open --limit 50
# Scoped, approachable work — start here.
gh issue list --repo $REPO --label "good first issue" --state open
# Confirmed defects with observable wrong behavior — the best Capstone fuel.
gh issue list --repo $REPO --label "Type: Bug" --state open --limit 50
# See the live label vocabulary (it changes; do not hard-code it from this page).
gh label list --repo $REPO --limit 100 | rg -i "bug|enhancement|good first|status|priority|kani"
Note: Firecracker's label scheme uses prefixed labels like
Type: Bug,Type: Enhancement,Status: Awaiting review,Priority: ..., plusgood first issue,Kani(formal verification), andRoadmap: ...(verify the exact strings withgh label liston your day — they evolve). Match on what the list actually returns, not on what this guide remembers.
The label subset that matters for a Capstone:
| Label (verify exact string) | What it means for you |
|---|---|
good first issue | A maintainer scoped it to be approachable. Start here. |
Type: Bug | A defect with observable wrong behavior. Best Capstone fuel. |
Type: Enhancement | A feature request. Small, well-specified ones are fine; large ones are not. |
Status: Awaiting review | On an issue, often means a maintainer wants discussion/PRs. |
Kani | A formal-verification (model-checking) task. Excellent if you did the relevant Level work; a steep first Capstone otherwise. |
Roadmap: ... | Large planned features. Avoid for a Capstone. |
What Makes an Issue Tractable
Score a candidate against these before you claim it. The sweet spot is a Type: Bug (ideally also good first issue) where a maintainer has already written "this
is wrong because X; the fix is probably around SomeStruct::some_fn." That comment
is gold — a pre-validated root-cause hypothesis you get to confirm and implement.
| Signal | Good | Bad |
|---|---|---|
| Blast radius | 1–3 files in one module (vmm/src/devices/..., vmm/src/vmm_config/..., the API server) | Spans vmm, firecracker, jailer, and a rust-vmm dep |
| Surface | A wrong value, a missing API validation, an off-by-one in a virtqueue, a bad error message, a flaky test | "Add PCI hotplug," "rework the device manager" |
| Reproducibility | A curl/config-file sequence or a pytest makes it fail every time | "Sometimes under 20x oversubscription in production" |
| Agreement | A maintainer confirmed it is a bug and hinted at the fix site | Open question whether it is even a bug |
| Attack surface | Fix shrinks or holds surface; no new syscalls, no new device | Adds an emulated device or widens the seccomp allow-list |
| BWC exposure | No API contract or snapshot-format change, or a clearly versioned one | Changes the snapshot layout or a REST field with no compatibility story |
| Test reachability | You can name the pytest in tests/integration_tests/ that would assert the fix | "Only reproduces on a specific host CPU at scale" |
Categories that age well as Capstones
- An API validation gap. A field on
/machine-config,/drives/{id},/network-interfaces/{id}, or/balloonaccepts a value it should reject, and the failure surfaces deep in the builder or a device instead of at the edge with a clear 400. Fix lives nearrpc_interface.rs/vmm_config/validation. Small, user-visible, testable. See the API server deep dive and Stage 4. - An error-message / diagnostics defect. Firecracker returns the wrong error variant, or a message omits the field an operator needs. Low blast radius, genuinely appreciated. See Level 8 Lab 3 and Stage 3.
- A virtio edge case. A block or net device mishandles a specific descriptor
chain, a zero-length write, a feature-negotiation corner, or a rate-limiter
boundary. Contained in one
devices/virtio/<dev>/module. See the virtqueues deep dive and Stage 7. - A flaky integration test rooted in a real race. A
tests/test that fails ~1 in N because of a missing wait or a genuine ordering bug in the VMM. Both are good — be honest in your root-cause doc about which it is. See Level 5 Lab 4 and Stage 9. - A snapshot-compatibility nit. A field added without a version bump, or a
device's
Persiststate that doesn't round-trip. Deeper, extremely instructive. See the snapshotting deep dive and Stage 8. Pick this only if you did the Level 9 snapshot lab.
Categories to avoid for a first Capstone
- Anything
Roadmap: ..., or a feature that adds a device or widens the attack surface — "QEMU has it" is not an argument here, and the bar is high. Read the minimal-device-model philosophy to understand why. - New REST endpoints, new snapshot fields, new seccomp syscalls — each carries a compatibility or security story that is its own multi-week skill.
- Pure performance issues with no correctness component ("make boot faster"). Proving no regression across architectures is a discipline of its own — see Stage 10.
- Anything where two maintainers disagree in-thread about whether to fix it. You do not want to land in the middle of that as your first contribution.
Check It Is Not Already Taken
Before you invest a day reproducing, spend five minutes confirming nobody is on it
— with gh, not by eyeballing the web page:
REPO=firecracker-microvm/firecracker
N=<issue-number>
# Read the full thread, including assignees and the latest comments.
gh issue view $N --repo $REPO --comments
# Is there already a PR referencing it? (PRs that say "Fixes #N" link automatically,
# but search the body/title too, since not everyone uses the keyword.)
gh pr list --repo $REPO --state open --search "$N in:title,body"
gh pr list --repo $REPO --state all --search "$N in:title,body" --limit 20
Then judge:
- Assignee / "I'll take this". If someone is assigned or recently said they're working on it, move on.
- An open PR. If a non-stale PR references the issue, the work is taken.
- A stale PR. Months of silence, author gone? You may comment offering to pick it up — but say so explicitly and wait for a maintainer's nod.
- The date. A
good first issueopened two days ago may have three people circling silently. An issue open for months with a maintainer "PRs welcome" is much safer.
Match It to Your Level
This is the part the OpenSearch capstone can't teach you — Firecracker bugs are stratified by subsystem, and the issue roadmap's 12 stages map directly to the Levels you completed. Pick an issue whose subsystem you have already traced:
| If the issue is about… | You should have done… | Deep dive to reopen |
|---|---|---|
| API field validation / error variants | Level 3, Level 8 | API server |
| Threading / channel / event loop | Level 3 | VMM threading model |
| vCPU run loop, CPUID/MSR, a VM-exit edge | Level 4 | vCPU run loop & VM exits |
| Boot / cmdline / guest memory layout | Level 6 | The boot sequence |
| virtio block/net/vsock/balloon/rng | Level 7 | virtqueues, virtio-block |
| seccomp / jailer | Level 9 | seccomp filtering, the jailer |
snapshot / Persist / UFFD | Level 9 | snapshotting |
If the issue lives in a subsystem you have not traced, that is not the Capstone — it is a reason to go do that Level first, or to pick a different issue. The Capstone tests applying what you know, not learning a subsystem cold under time pressure.
Claim It
Firecracker does not require formal assignment to start, but claiming politely
prevents duplicate work and signals seriousness. Comment via gh:
gh issue comment $N --repo $REPO --body "I'd like to work on this. Plan: reproduce \
it deterministically with a config-file boot (or a failing pytest in \
tests/integration_tests/), trace through <subsystem>, and open a PR with an \
integration test. Anything I should know about the intended fix direction or any \
snapshot/API-compatibility constraints before I start?"
That comment claims the issue, shows you already have a plan, names the subsystem (proving you read the code), and explicitly invites a maintainer to redirect you before you spend days. It also surfaces the two questions Firecracker reviewers care most about up front: compatibility and attack surface.
Warning: Do not comment "Can I work on this?" and then vanish for a week. That locks an issue in social limbo and annoys maintainers more than anything else. If you claim it, start within a day or two — or un-claim it.
See design-via-github for how to read a thread for the maintainers' real intent.
Scope Estimation and Reproducibility Pre-Check
Write a one-paragraph scope estimate for yourself before you commit, and save it
to capstone-work/scope.md. Answer:
- How many files do I expect to touch? Grep the symbols named in the issue —
do not trust the issue's own file references, locate them yourself:
If the answer is "dozens across crates," reconsider.rg -n "the_function_or_struct_from_the_issue" src/ - Is there an API or snapshot contract change? If yes, there is a compatibility
story (a versioned field, a
Persistmigration). Fine for week two; not ideal for the first thing you touch. See compatibility. - Does it touch the attack surface? A new syscall means a
resources/seccomp/change with a security argument. Budget extra and read seccomp-filtering. - Can I name the test that proves the fix? If you cannot imagine the pytest assertion, you do not understand the bug yet. Keep reading the thread and the code.
Then do a 30-minute reproducibility smoke test now (the full job is Step 2):
# Build current main once, so the smoke test is honest.
tools/devtool build
# If the issue is API/boot-shaped, start FC and try the exact curl/config from the issue.
# If it is internals-shaped, find the nearest test and try to make an assertion fail:
rg -n "<Component>" tests/integration_tests/
If you cannot make it misbehave in 30 minutes, note that. A bug you cannot
reproduce in week one is a bug you may never reproduce — and an irreproducible
Capstone is a dead Capstone. If the issue says "only on Firecracker v1.X with these
settings," check out that tag (git checkout v1.X.0) and try exactly that.
Selection Rubric
Score your candidate out of 10 before committing. Pick one that scores ≥ 7.
| Criterion | 0 | 1 | 2 |
|---|---|---|---|
| Maintainer confirmed it is a real bug/task | Untriaged, unclear | Some discussion | Confirmed + fix hint |
| Blast radius | Many modules / cross-crate | 2–4 files, one module | 1–2 files, one component |
| Reproducibility | Can't make it fail | Fails sometimes | Deterministic repro in reach |
| Compatibility / attack-surface risk | New device / syscall / snapshot field, no plan | Versioned contract change | No contract or surface change |
| Test reachability + level match | Can't imagine the test / unknown subsystem | Integration test only | Clear pytest + a subsystem you traced |
A 9–10 is a near-ideal first Capstone. A 7–8 is solid and slightly stretchy. Below
7, keep looking — gh issue list is long and a better candidate is usually one
search away.
Deliverable for Step 1
-
A chosen issue number
#N, scoring ≥ 7 on the rubric. -
A claim comment posted via
gh issue commentwith a brief plan naming the subsystem and asking about compatibility/attack surface. -
A one-paragraph scope estimate in
capstone-work/scope.md. - A 30-minute reproducibility smoke-test result noted (did it misbehave?).
-
A feature branch off
main:git checkout -b fix/issue-N-short-description.
Rubric Hooks
This step feeds Reproduction (your smoke test is the seed of the deterministic repro) and Communication (the claim comment is the first thing a maintainer sees of you). A vague claim or an unverified "it should be reproducible" caps both dimensions. See the evaluation rubric.
Validation / Self-check
Before advancing to Step 2:
- You can state, in one sentence, the wrong behavior the issue describes — not the desired behavior, the wrong one.
- You confirmed with
ghthat no open or recent PR already fixes it. - You posted a claim comment and ideally got a maintainer acknowledgement.
- You grepped the symbols named in the issue and the touch count is small.
- You can name the subsystem and the matching Level/deep dive.
- Your scope estimate honestly fits a 2–3 week budget with no contract/surface change you can't handle.
- You have a feature branch checked out and
capstone-work/ready.
Then go to Step 2: Reproduction.