Skip to content

Build and test

Changing. Follow: #507

This page gets you to green tests on your machine and explains what CI runs on your pull request. It does not cover how to install Rust or a GPU driver.

Path What is there
crates/ The Rust crates, 122 of them.
tools/ The snapshot update tool, fixtures, the vanilla oracle and benchmarks.
xtask/ The check runner that CI and the local hooks use.
assets/ The version file, reports from the game and local data packs.
docs/ Specifications and design notes. The docs index lists them.
docs-site/ This site.
Terminal window
cargo nextest run -p <crate> # one crate
cargo nextest run --workspace # everything, before a commit
cargo nextest run --profile full # plus the exhaustive sweeps

The runner is cargo-nextest. The repository pins the Rust toolchain in rust-toolchain.toml, and .config/nextest.toml pins the minimum version of the runner. Do not use cargo test, because it ignores .config/nextest.toml and most crates set doctest = false. A Claude Code hook in the repository rejects it.

The tests read the game’s data pack, so every profile first runs a setup script that installs the game’s client jar and unpacks its data pack into your cache directory. You do not download anything by hand, but the first run needs network access to Mojang.

A test name carries a tier prefix such as exhaustive:: or gpu::, and each profile selects tests by that prefix.

Profile What it runs
default Everything except exhaustive::, gpu::, online:: and vanilla_server:: tests.
ci The same filter as default, and it does not stop at the first failure.
ci-hosted The filter of ci, for the test job on a GitHub-hosted machine with four cores. A test may run 5 minutes, and the whole run 30 minutes.
full The default tier plus exhaustive:: and online::. The scheduled CI job uses it.
gpu Only gpu:: tests. They need a machine with a Metal GPU.
vanilla-server Only vanilla_server:: tests. They run through vanilla-server/run.sh.

No test run may take longer than five minutes, except in ci-hosted. A test that is slower belongs in the exhaustive:: tier.

CI and the local hooks call one runner, scripts/hooks/run-checks <trigger>. It builds xtask and runs the checks that belong to the trigger. You can run the same checks yourself before a push:

Terminal window
scripts/hooks/run-checks commit

Each trigger runs a fixed set of checks. Run scripts/hooks/run-checks with no argument to see all triggers.

Trigger Checks
commit, push parity, fmt
lint parity, fmt, keys
clippy clippy
test The tests of the changed crates and their dependents.
portability no-bevy, layers, wasm32, no-std

fmt and clippy run the Cargo commands of the same names. The other checks are specific to mcrs, and the package lists they use are in xtask/src/checks.rs.

Check What it requires
parity A test that claims vanilla behavior must load a fixture the game produced. A claim against a literal gives a warning. Specs and parity explains parity tests.
keys The generated registry key sources must match what the generator writes from the stored reports. Never edit a generated file by hand.
no-bevy 100 packages must build without Bevy.
no-std 9 packages must build for a target without std.
wasm32 11 packages must build for wasm32.
layers The wire and network crates must not link game data, so a proxy or a bot can use them alone.

Rewrite a stale blessed file with MCRS_BLESS

Section titled “Rewrite a stale blessed file with MCRS_BLESS”

Some tests compare a generated file with a checked-in copy, called a blessed file. The baked entity assets and a shader field table are checked this way. When the copy is stale, the test fails and its message names an environment variable. Run the test again with that variable set, and the test rewrites the copy:

Terminal window
MCRS_BLESS=1 cargo nextest run -p <crate>

Read the diff before you commit it. If a blessed file changed and you cannot say why, the bug is in your change and the test was right to fail. The tests that read the variable are in crates/mcrs_minecraft_mesh/src/pack.rs and crates/mcrs_minecraft_entity_model/tests/it/mob_assets.rs.

The workflow .github/workflows/checks.yml runs on every pull request to main and on every push to main. Its first job, changes, reads the file list of the pull request. If every file is under docs/, is a Markdown file in the repository root or is a LICENSE-* file, no other job runs and the check passes. A change to docs-site/ runs the full set.

Which jobs run depends on where the pull request comes from.

Source Jobs
A branch of this repository lint on a GitHub-hosted ubuntu-24.04 machine. One self-hosted job on the project’s own runner runs the clippy, test and portability triggers at the same time.
A fork lint, clippy, test and portability, each on a GitHub-hosted ubuntu-24.04 machine. They start from the build caches that each push to main saves.
A push to main Both sets.

A final job, checks, fails unless every job that applies passed.

On a GitHub-hosted machine the test trigger uses the ci-hosted profile, and Cargo resolves features for the selected packages only. In CI the tests skip every crate that depends on wgpu and everything above it. Those tests run locally only, so run them yourself when you touch the client or the renderer.

A second workflow, docs, warns about pages of this site whose sources changed. Write these docs describes it.

  1. WIP#507 Plans a report of the specification rules that no test checks. ↩

Sources and verification

Verified: 26.4-snapshot-7, 3540f457b, 2026-11-10

Tracking: #507