Thanks for your interest in contributing to Basalt! This document covers everything you need to get started.
- Rust stable (latest)
- Node.js 18+ (for commitlint/husky)
- pnpm
git clone https://github.com/basalt-mc/basalt.git
cd basalt
pnpm install # installs commitlint + husky hooks
cargo build # verify everything compiles
cargo test # run the test suitemake check # fmt + clippy + test (the pre-push checklist)
make coverage # run coverage (must be >= 90%)
make codegen # regenerate protocol packets from minecraft-data
cargo xt codegen # same as above without fmt- Create an issue — describe what you're building or fixing using the templates in
.github/ISSUE_TEMPLATE/ - Create a branch — use the naming convention:
feat/,fix/,refactor/,chore/,docs/,test/ - Implement — write code, tests, and doc comments
- Verify locally — run
make checkandmake coveragebefore pushing - Open a PR — reference the issue with
Closes #N, write a detailed description
We use Conventional Commits enforced by commitlint. Every commit must have a type and a scope:
type(scope): description
Types: feat, fix, refactor, perf, docs, chore, ci, test, bench
Scopes: must be from the allowed list in commitlint.config.js. Common scopes:
- Crate names:
types,derive,protocol,net,server,world,ecs,api,core,command,events,storage,testkit - Plugin names:
chat,block,command,world,lifecycle,movement,physics,item,container,storage - Cross-cutting:
workspace,deps,ci,docs,tooling
Sub-module scopes are also available (e.g., types/varint, net/connection). See commitlint.config.js for the full list.
- 90% minimum coverage — CI rejects anything below this threshold
- Unit tests go in
#[cfg(test)] mod testsat the bottom of each file - Plugin tests use
PluginTestHarnessfrombasalt-testkit - Property-based tests with
proptestfor encode/decode roundtrips
Every public item (function, struct, enum, trait) must have a doc comment. Describe what it does, why it exists, and error cases when relevant.
cargo fmt— enforced in CIcargo clippywith-D warnings— zero warnings allowed- No
unsafeblocks - Keep files under ~400 lines
Plugins depend only on basalt-api. Never import internal crates (basalt-ecs, basalt-core, basalt-world) directly in plugin code.
See CLAUDE.md for a comprehensive architecture guide including:
- Crate dependency graph
- Server threading model
- Event system stages
- Plugin development patterns
- ECS design
Open an issue with the question label, or check existing issues for context on ongoing work.