Contributing · 10. Good first contributions

There are zero open issues on this repository, the good first issue label is applied to nothing, and blank issues are disabled. This chapter exists to replace the on-ramp that is missing. Below are ten candidates derived from the tree itself, ranked by how much tribal knowledge each needs. The first three were pre-declared by the maintainers in code comments; they are not guesses about what would be welcome.

This is a how-to. Pick one, read the linked evidence, open a discussion or issue saying you are taking it, then follow chapter 7.

10.1 The state of the on-ramp, plainly

FactVerified how
Zero open issuesgh issue list --repo CueCrux/Crux --state open returns empty
The good first issue label exists but nothing carries itThe label is defined, colour #7057ff, description "Good for newcomers". Applied count: zero
Blank issues are disabled.github/ISSUE_TEMPLATE/config.yml sets blank_issues_enabled: false. You must use the bug or feature template, or a discussion
Two issue templates exist.github/ISSUE_TEMPLATE/bug_report.yml and feature_request.yml
Security issues are routed away from GitHub entirelySECURITY.md:5. See 8.6

A public repository with a contributor track and no issues has no on-ramp. That is a content problem, not a documentation problem, and it is the single biggest obstacle an outside contributor faces here. The list below is the workaround.

Two things make the situation better than it sounds. First, required_approving_review_count is 0 and the gate is the eleven automated checks, so a correct, green pull request is not waiting on anyone's attention to be mergeable. (It does wait once: a fork PR needs a maintainer to approve its first workflow run before any check starts, §5.0. Run the checks locally first.) Second, the codebase is unusually heavy on rationale comments that name the incident, PR number or plan behind a decision, so the tree tells you what the maintainers already want done. Six of the ten items below are literally the maintainers writing down a follow-up they did not get to.

10.2 The three the maintainers pre-declared in code comments

These are the safest first pull requests in the repository. In each case a maintainer wrote the follow-up into a comment next to the code.

1. Raise the corecrux-memory coverage floor from 93 to 95

The evidence. ci.yml:442 says it outright: "corecrux-memory's historical 95% target was never actually enforced; it is 93.5% today, so the enforced floor is 93 with 95 as the ratchet target." docs/testing-and-coverage.md:146 goes further and names it "the first such opportunity".

What to do. Add tests to crates/corecrux-memory until the crate's region coverage reaches 95%, confirm the number in the Coverage job log, then bump the corecrux-memory:93 pair at ci.yml:446 to corecrux-memory:95.

Why it is a good first PR. Self-contained, measurable, and the maintainers have already declared it wanted. Reproduce the CI measurement locally with the command in 5.8.

Size. Medium. The tests are the work; the config change is one line.

2. Promote cargo semver-checks from advisory to enforcing

The evidence. semver.yml:34, verbatim: "Promote to enforcing (fail in the else-branch) after a clean run history." The comment above it explains the whole design, Semver Compatibility is a required check, so a hard failure would wedge every PR, and the current form writes violations to the job summary with a warning annotation while staying green.

What to do. Change the else-branch at semver.yml:41 to exit non-zero, keeping the job-summary output.

Why it is a good first PR. A small, precisely specified diff that closes a real gap, today a required check cannot fail, which readers of the required-check list over-trust (5.2).

Size. Tiny diff. But it needs maintainer sign-off on the run history first, the comment conditions the promotion on a clean history, and only a maintainer can see that. Open the discussion before the PR.

3. Fold the Linux cross legs into the SLSA provenance subjects

The evidence. release.yml:281, verbatim: the musl and aarch64-gnu legs "are cosign-signed per-artifact like every other file but are intentionally NOT wired into these SLSA subjects yet: combine-hashes hard-fails if any leg's block is empty, so coupling the newer, build-only cross legs in would let one cross-leg flake break provenance for the whole release. Fold them in once the cross legs prove stable (add job outputs + two more base64 -d lines below)."

What to do. Exactly what the parenthesis says: add the two job outputs and two more base64 -d lines in combine-hashes.

Why it is a good first PR. The maintainer has specified the diff down to the line count. It measurably improves supply-chain coverage, two more release artefacts gain SLSA provenance.

Size. Small. Needs maintainer agreement that the cross legs have proved stable, same as item 2.

10.3 Seven more, derived from the tree

4. Add tests to corecruxd/src/http/events.rs, infra.rs and policy.rs

The evidence. docs/testing-and-coverage.md:110 names all three: they are "still at 0%; they are gated (not excluded), so they are visible debt and natural next targets, not hidden."

Why it is a good first PR. The debt is explicitly flagged; the files are gated so your progress shows up in the Coverage job; and there are hundreds of examples to copy in crates/corecruxd/src/http/tests.rs.

Size. Medium, and easily split into three separate PRs.

5. Burn down mutation survivors in corecrux-storage

The evidence. .github/mutants-baseline.txt is 755 lines, of which 524 are corecrux-storage.

What to do. The recipe is documented at docs/testing-and-coverage.md:135: write a test that kills the survivor, confirm with cargo mutants --file <file> -p corecrux-storage --timeout 120, then delete its line from the baseline.

Why it is a good first PR. Each killed survivor is one test plus one deleted baseline line. You can do exactly one and it is still a complete, valuable contribution. See 4.8.

Size. Small per survivor. Genuinely unbounded if you enjoy it.

6. Update the stale numbers in docs/testing-and-coverage.md

The evidence. 4.1 of this set. The document's headline and per-crate table are a 2026-06-18 snapshot: 4,489 tests, corecruxd 1,537, corecruxctl 933, crux-mcp 622. Measured 2026-07-27: 5,969, and 2,244 / 1,043 / 769.

What to do. Re-measure with grep -rE "#\[(tokio::)?test\]" crates --include="*.rs" | wc -l, plus a per-crate breakdown, and update the document. Date the snapshot.

Why it is a good first PR. Trivial, high-visibility, and requires no build at all.

Size. Tiny.

7. Fix the protoc claim in four documents

The evidence. 1.1. crates/corecrux-proto/build.rs:9 uses protoc-bin-vendored and sets PROTOC itself. The claim that protoc is required appears at CONTRIBUTING.md:18, README.md:89, README.md:386 and docs/getting-started.md:98.

Why it is a good first PR. The current text sends every newcomer to install a package they do not need, on their very first interaction with the project. Four one-line edits.

Size. Tiny. High value per character changed.

8. Fix the broken README.md#quickstart anchor

The evidence. docs/getting-started.md:99 links [README Quickstart](../README.md#quickstart). The README has no "Quickstart" heading; the heading is "Up and running in 60 seconds" at README.md:58, so the anchor is #up-and-running-in-60-seconds.

Size. One line.

If you take this one, consider taking the other stale-document fixes with it: the workspace version at docs/agent/repo-manifest.yaml:10 and AGENTS.md:56 still says 0.5.37 against a real 0.5.52; docs/self-hosted-runner.md:3 says 26 crates against a real 28; docs/self-hosted-runner.md:45 quotes a CI step name and error string that no longer exist (5.10); and .github/merge-queue-ruleset.README.md:70 omits two of the eleven required checks. Each is one line; together they are one coherent "fix stale contributor docs" PR.

9. Add a CI check that config.example.env covers every CORECRUXD_* in config.rs

The evidence. 3.4 and 6.3. No such check exists. Every reference to config.example.env from code or scripts asserts only that the file exists and is copied into a release tarball. Measured: config.rs has about 150 environment lookups; config.example.env documents about 98 distinct names.

What to do. Write scripts/check-config-example-coverage.sh in the same style as the existing scripts/check-*.sh gates, offline, no toolchain, ::error:: output, extracting CORECRUXD_* string literals from config.rs and asserting each appears in config.example.env. Wire it into the Lint job. Seed an allowlist for any deliberate omissions rather than fixing all 50 in the same PR.

Why it is a good first PR. Scoped, mirrors an existing pattern exactly, and permanently closes a hole where a flag can ship undocumented.

Size. Medium. Read 5.4 before touching a workflow.

10. Add a CHANGELOG heading gate to the release path

The evidence. 9.7. CHANGELOG.md:8 states "if you tag a release, you write its entry", but the newest released heading is [0.5.38] while the workspace is 0.5.52, fourteen versions with no entry, and no CI gate to notice.

What to do. Extend .github/workflows/version-sync.yml, which already runs on v* tags and already compares the tag to the workspace version, so that it also requires a ## [X.Y.Z] heading in CHANGELOG.md matching the tag.

Why it is a good first PR. Small, well-scoped, and it makes a rule the project already believes in self-enforcing. Note that version-sync.yml is not a required check and has no merge_group trigger; it fires on tags, so this does not touch the merge-queue invariant.

Size. Small.

10.4 What is not a good first contribution

Being explicit about this saves you a wasted weekend.

Not thisWhy
The 33 TODO and FIXME comments in crates/Most are flag-enable gates in crates/corecruxd/src/http/provenance.rs, credit metering, key hardening, reserve-credits-before-persist, a global that is unbounded and un-rotated, resolving a tenant from token claims, plus an envelope item in crates/crux-mcp/src/tools/memory.rs. They need context you do not have. The one exception is crates/corecruxd/src/http/observations.rs, promoting a counter to a scraped Prometheus metric, which is a reasonable second PR
Reorganising proto/ into per-package subdirectoriesbuf.yml:16 marks buf lint continue-on-error purely because of the flat layout, so it looks like a tidy win. It is wire-format-sensitive. Flag it as "ask first" and expect a long conversation
Anything on the "Ask first" listChanging a default port, changing receipt formats or seal material, touching anything under corecrux-receipts, -segment or -storage that an invariant names, or adding a new on-disk artifact type. AGENTS.md:70
"Fixing" the pedantic clippy allowsThe roughly 30 allows at Cargo.toml:146 are deliberate
Making the crux-session golden tests passThey are permanently #[ignore]d on a private sibling checkout path that does not exist for you. 4.10
Moving the six M*-REPORT.md files out of the repository rootReasonable and probably wanted; they are internal artefacts in a public repository's front door, but it is a maintainer's call about their own history. Ask first
Any GPU or CUDA workThis repository is CPU-only by architecture decision docs/adr/003-cpu-only-crux-daemon.md, and the boundary is enforced by scripts/assert-daemon-release-boundary.sh. It is on the "Never" list

10.5 How to claim one

There is no assignment mechanism, because there are no issues.

  1. Open an issue using the bug or feature template, or start a discussion, naming which item you are taking and your rough plan.
  2. For items 2 and 3, wait for maintainer agreement before writing the code, both are conditioned on judgements only a maintainer can make.
  3. Everything else: go ahead. Fork, branch, and follow chapter 7.
  4. Run 5.11 before you push. Nobody is required to review your PR, so the checks are what stands between you and main.

If you are a maintainer reading this: applying the existing good first issue label to even three of the items above would do more for this repository's contributor track than any documentation change, including this one.

Sources