Welcome to BitNet-rs! We appreciate your interest in contributing to our high-performance 1-bit neural network quantization and inference library for Rust.
Active development now happens in
EffortlessMetrics/bitnet-rs-swarm.
This repository is the release and publish repository for BitNet-rs.
Open normal feature, hardware-lane, performance, diagnostic, refactor, and
proof-tooling work in bitnet-rs-swarm.
PRs accepted here are limited to:
- release promotion PRs from
bitnet-rs-swarm; - versioning, changelog, packaging, signing, and publish changes;
- emergency security or release-blocking hotfixes;
- documentation corrections needed for released artifacts.
Do not open new feature or hardware-lane PRs in this repository. Useful open development PRs should keep their identity when feasible and move only after a content-aware handoff; age, branch distance, and old-stack status are not close reasons.
-
Fork and Clone
git clone https://github.com/your-username/bitnet-rs-swarm.git cd bitnet-rs-swarm -
Setup Development Environment
# Install Rust (MSRV defined in rust-toolchain.toml) rustup update stable # Install development tools cargo install cargo-nextest cargo-mutants # Install ripgrep (required for pre-commit hooks) # macOS: brew install ripgrep # Ubuntu: sudo apt-get install ripgrep # Windows: choco install ripgrep # Or visit: https://github.com/BurntSushi/ripgrep # Enable pre-commit hooks (run once after cloning) git config core.hooksPath .githooks
-
Run Tests
# Quick test with CPU features cargo test --locked --workspace --no-default-features --features cpu # CI-equivalent local smoke test ./ci/local.sh
BitNet-rs uses local pre-commit hooks to catch quality issues before they reach CI.
The hooks are enabled automatically if you followed the setup instructions above. If not:
git config core.hooksPath .githooks- ripgrep (
rgcommand) is required for pattern matching- Install via your package manager (see setup instructions)
- Hooks will fail gracefully with instructions if
rgis not found
The pre-commit hook enforces two critical quality gates:
All ignored tests must include a justification. Valid patterns:
// ✅ Attribute style
#[ignore = "Blocked by Issue #254 - shape mismatch"]
fn test_something() { ... }
// ✅ Inline comment
#[ignore] // Slow: QK256 scalar kernels (~0.1 tok/s)
fn test_slow_operation() { ... }
// ✅ Preceding comment (within 2 lines)
// Blocked by Issue #254 - shape mismatch in layer-norm
#[ignore]
fn test_layer_norm() { ... }
// ❌ Bare ignore (rejected by hook)
#[ignore]
fn test_something() { ... }Valid justification patterns:
Blocked by Issue #NNNIssue #NNN(shorthand)Slow: <reason>TODO: <reason>FIXME: <reason>
Tests that modify environment variables must use the EnvGuard pattern:
// ❌ Raw mutation (rejected by hook)
#[test]
fn test_deterministic() {
unsafe {
std::env::set_var("BITNET_DETERMINISTIC", "1");
}
// ...
}
// ✅ EnvGuard pattern (accepted)
use serial_test::serial;
use tests::support::env_guard::EnvGuard;
#[test]
#[serial(bitnet_env)] // Ensures serial execution
fn test_deterministic() {
let _guard = EnvGuard::new("BITNET_DETERMINISTIC");
_guard.set("1");
// Test code - env automatically restored on drop
}Why: Raw std::env::set_var is unsafe and can cause race conditions in parallel test execution. The EnvGuard pattern ensures:
- Thread-safe mutations via global mutex
- Process-safe execution via
#[serial(bitnet_env)] - Automatic restoration of original values on scope exit
Hook is slow:
- Ensure ripgrep is installed (hooks check patterns in ~15k files)
- Check disk I/O if repo is on network storage
False positives:
- Review the hook output - it shows which file/line failed
- Ensure your code follows the patterns above
- Check
docs/development/test-suite.mdfor more examples
Bypass hooks temporarily (emergency only):
git commit --no-verifyThe pre-commit hooks use the same validation scripts as CI:
.githooks/pre-commit→scripts/lib/ignore_check.sh- CI guards →
scripts/lib/ignore_check.sh
This ensures local validation exactly matches CI, preventing surprise failures.
-
Create Feature Branch
git checkout -b feature/your-feature-name
-
Follow TDD Approach
- Write tests first
- Implement minimal code to pass tests
- Refactor with safety
See ROADMAP.md for the project's current direction and priorities.
- Use xtask Commands
# Download test models cargo run --locked --no-default-features -p xtask -- download-model # Verify implementation cargo run --locked --no-default-features -p xtask -- verify --model models/test.gguf # Cross-validate against C++ reference cargo run --locked --no-default-features -p xtask -- crossval
New internal developer workflows belong in xtask. bitnet-task exists only as a compatibility facade for migrated scripts/*.sh entrypoints, so only add to it when preserving an existing shell contract during migration.
- MSRV: See
rust-toolchain.tomlfor the pinned toolchain version (Rust 2024 edition) - Features: Always specify
--no-default-features --features cpu|gpu - Safety: Minimize
unsafecode; document all usage - Performance: Target >99% quantization accuracy
- Testing: Maintain 100% test coverage for critical paths
- Quantization: Support I2S, TL1, TL2, and IQ2_S formats
- GPU Support: CUDA kernels with CPU fallback
- GGUF Compatibility: Maintain compatibility with upstream formats
- Cross-validation: All changes must pass C++ reference comparison
- API Documentation: All public APIs must have comprehensive rustdoc
- Examples: Include working examples for new features
- Performance: Document performance characteristics and benchmarks
- Migration: Update migration guides for breaking changes
-
Unit Tests
cargo test --locked --workspace --no-default-features --features cpu -
Integration Tests (CPU golden path)
cargo test --locked -p bitnet-inference --test cpu_golden_path --no-default-features --features cpu -
Cross-validation Tests
export BITNET_GGUF="models/test.gguf" cargo test --locked --package crossval --no-default-features --features cpu
-
Property Tests
cargo test --locked property_ --no-default-features --features cpu -
Mutation Tests (CI only)
cargo mutants --package bitnet-quantization
BitNet-rs uses a 3-layer fixture architecture for testing neural network operations, quantization algorithms, and model loading:
-
Inline Fixtures — Hardcoded test data in the test file
- Use for: Trivial constants, magic numbers, simple shapes
- Example:
let vocab_size = 32000;
-
Generated Fixtures — Programmatic test data from seed functions
- Use for: Randomized tensors, quantization roundtrip tests, property-based testing
- Example:
helpers::lcg_random(seed)for deterministic random data - Available generators:
lcg_random(seed)— Deterministic LCG PRNG for numeric datagenerate_gguf_fixture(config)— Minimal GGUF files for tokenizer/model testscreate_test_gguf_with_i2s(name, shape, data, type)— I2S quantized tensor fixtures
-
File-Based Fixtures — External test data loaded from disk
- Use for: Full GGUF models, real tokenizer files, reference data
- Example:
models/test.gguf(gated byBITNET_GGUFenv var; not committed to repo)
Deterministic Random Data (LCG PRNG):
use helpers::lcg_random;
#[test]
fn test_quantization_roundtrip() {
let seed = 42;
let input: Vec<f32> = (0..1024).map(|_| lcg_random(seed) as f32).collect();
// Quantize → Dequantize → Validate
let quantized = quantize_i2s(&input);
let dequantized = dequantize_i2s(&quantized);
assert!(calculate_correlation(&input, &dequantized) > 0.99);
}GGUF Model Fixtures:
use fixtures::gguf_fixtures::{generate_gguf_fixture, GgufFixtureConfig};
#[test]
fn test_tokenizer_auto_discovery() {
let temp_dir = TempDir::new().unwrap();
let model_path = temp_dir.path().join("test.gguf");
generate_gguf_fixture(&model_path, &GgufFixtureConfig {
model_type: "llama".to_string(),
vocab_size: 128256,
has_embedded_tokenizer: true,
tokenizer_type: Some("hf".to_string()),
corrupted: false,
}).unwrap();
// Test tokenizer discovery logic
let tokenizer = load_tokenizer(&model_path).unwrap();
assert_eq!(tokenizer.vocab_size(), 128256);
}I2S Quantized Tensor Fixtures:
#[test]
fn test_qk256_flavor_detection() {
// Generate QK256 quantized tensor (256-elem blocks, separate scales)
let rows = 4;
let cols = 256;
let data = vec![0u8; rows * cols / 4 + rows * 2]; // 2-bit packed + scales
let file = create_test_gguf_with_i2s("test.weight", &[rows, cols], data, 26);
// Validate flavor detection
let result = load_gguf_full(file.path(), Device::Cpu).unwrap();
assert!(result.i2s_qk256.contains_key("test.weight"));
}# Run all tests (includes fixture-based tests)
cargo test --locked --workspace --no-default-features --features cpu
# Run specific fixture tests
cargo test --locked -p bitnet-models test_qk256_flavor_detection --no-default-features --features cpu
cargo test --locked -p bitnet-tokenizers test_gguf_fixture --no-default-features --features cpu
# Skip slow fixture-heavy tests (e.g., full model loading)
BITNET_SKIP_SLOW_TESTS=1 cargo test --locked --workspace --no-default-features --features cpuStep-by-step guide:
-
Identify fixture requirements — What test data do you need?
- Simple constants? → Use inline fixtures
- Randomized tensors? → Use generated fixtures with seeded PRNG
- Full models? → Use file-based fixtures or
generate_gguf_fixture
-
Choose appropriate layer
// Inline: trivial constants let embedding_dim = 512; // Generated: seeded random data let weights = helpers::generate_random_tensor(42, shape); // File-based: real model artifacts let model = load_gguf("tests/fixtures/gguf/llama3-128k.gguf");
-
Add generator function if needed (for new fixture types)
// In crates/bitnet-models/tests/helpers/qk256_fixtures.rs pub fn generate_qk256_4x256(seed: u64) -> Vec<u8> { // Generate deterministic QK256 quantized tensor let mut rng = lcg_random(seed); let rows = 4; let cols = 256; let data_size = rows * cols / 4 + rows * 2; // 2-bit packed + scales (0..data_size).map(|_| (rng() % 256) as u8).collect() }
-
Write test using fixture
#[test] fn test_new_quantization_format() { let data = helpers::generate_qk256_4x256(42); let quantized = QuantizedTensor::from_bytes(&data); assert_eq!(quantized.shape(), &[4, 256]); }
-
Document fixture purpose — Add rustdoc comments
/// Generate QK256 quantized tensor with deterministic seed /// /// # Format /// - 4 rows × 256 columns (1024 elements) /// - 2-bit packed representation (256 bytes) /// - Separate FP16 scales (8 bytes) /// /// # Seed /// Use consistent seeds for reproducibility: /// - `42` — Default test seed /// - `1337` — Edge case seed (extreme values) pub fn generate_qk256_4x256(seed: u64) -> Vec<u8> { /* ... */ }
Best practices:
- Use seeded generators for reproducible randomness (never
rand::thread_rng()) - Keep inline fixtures minimal and well-commented
- Prefer generated fixtures over hardcoded binary blobs
- Use file-based fixtures sparingly (increases repo size)
- Document fixture format and seed meanings in rustdoc
See also:
tests/helpers/issue_261_test_helpers.rs— Quantization accuracy helperscrates/bitnet-tokenizers/tests/fixtures/gguf_fixtures.rs— GGUF fixture generatorcrates/bitnet-models/tests/qk256_dual_flavor_tests.rs— I2S fixture examples
# Requires CUDA toolkit
cargo test --locked --workspace --no-default-features --features gpuBitNet-rs uses environment variables for runtime configuration (e.g., BITNET_STRICT_MODE, BITNET_DETERMINISTIC, BITNET_GGUF). Tests that mutate environment variables must use EnvGuard and serial execution to prevent flaky tests and race conditions.
Why This Matters: Environment variables are process-global state. Without isolation, parallel tests can interfere with each other:
- Test A sets
BITNET_STRICT_MODE=1→ Test B unexpectedly sees strict mode enabled - Test C clears
BITNET_GGUF→ Test D's model path is lost - Non-deterministic failures occur depending on test execution order
Using EnvGuard for Safe Environment Mutations:
use tests::support::env_guard::EnvGuard;
use serial_test::serial;
#[test]
#[serial(bitnet_env)] // Prevents parallel execution with other env-mutating tests
fn test_strict_mode_validation() {
// EnvGuard automatically restores original env state on drop
let guard = EnvGuard::new("BITNET_STRICT_MODE");
guard.set("1");
// Test code that depends on BITNET_STRICT_MODE=1
let result = validate_model("models/test.gguf");
assert!(result.is_err(), "Expected strict mode to fail on warnings");
// guard drops here → BITNET_STRICT_MODE restored to original value
}
#[test]
#[serial(bitnet_env)] // Same serial group ensures sequential execution
fn test_model_path_override() {
let guard = EnvGuard::new("BITNET_GGUF");
guard.set("/tmp/test.gguf");
// Test code that uses BITNET_GGUF env var
assert_eq!(get_model_path(), Some("/tmp/test.gguf".into()));
}Best Practices:
- Always use
#[serial(bitnet_env)]on tests that callEnvGuard::new()or directly mutate environment variables - Group related env tests under the same serial tag (e.g.,
bitnet_env) to prevent cross-contamination - Document env dependencies in test rustdoc comments (e.g.,
/// Requires BITNET_STRICT_MODE to be unset) - Avoid direct
std::env::set_var— useEnvGuardinstead for automatic cleanup - Run env tests sequentially in CI to ensure reproducibility (nextest already handles this via
#[serial])
See also:
tests/support/env_guard.rs— EnvGuard implementationcrates/bitnet-common/tests/issue_260_strict_mode_tests.rs— EnvGuard usage examplescrates/bitnet-models/tests/loader_strict_mode.rs— Serial env testing patterns
BitNet-rs provides Git hooks that enforce quality standards locally before commits reach CI:
# Enable pre-commit hooks
git config core.hooksPath .githooksWhat the hooks check:
- ✅ #[ignore] Annotation Hygiene: Ensures all
#[ignore]attributes include a reason ⚠️ Environment Mutation Safety: Warns about rawstd::env::set_var()calls (should use EnvGuard)
See: .githooks/README.md for full documentation
Pre-commit hooks catch issues early in your local workflow:
- Faster feedback than waiting for CI (seconds vs minutes)
- Prevents accidental commits of bare
#[ignore]markers - Enforces EnvGuard pattern for environment mutations
- Saves CI resources by catching issues before push
Note: You can temporarily bypass hooks with git commit --no-verify, but CI will still enforce these checks.
BitNet-rs enforces strict CI hygiene and supply chain security to prevent supply chain attacks and ensure reproducible builds:
GitHub Actions Supply Chain:
- All workflow actions must be SHA-pinned (not floating tags like
@v3) - Automated weekly repin workflow (
repin-actions.yml) updates pins while maintaining security - CI blocks PRs that introduce floating action references via the Guards gate
Dependency Determinism:
- All
cargo/crossinvocations use--locked(77+ invocations across workflows) - Ensures reproducible builds by enforcing exact dependency versions from
Cargo.lock - CI blocks PRs that add non-locked cargo/cross commands via the Guards gate
MSRV Enforcement:
- Minimum Supported Rust Version (MSRV): Defined in
rust-toolchain.toml(Rust 2024 edition) - All workflows must use
rust-toolchain.tomlfor MSRV consistency - CI blocks PRs that hardcode toolchain versions outside
rust-toolchain.toml
Runner Pinning:
- Default runners are pinned to
ubuntu-22.04for single-platform deterministic CI lanes - Intentional
ubuntu-latestusage is allowed for:- Security scanning workflows (e.g.,
security.yml) - should track latest tools - Coverage tracking workflows (e.g.,
coverage.yml) - benefits from latest tooling - Compatibility smoke testing (e.g.,
compatibility.yml) - explicitly tests across versions
- Security scanning workflows (e.g.,
- When adding new workflows: Default to
ubuntu-22.04for reproducibility. Ifubuntu-latestis required, justify in PR and add an inline comment explaining why.
Receipt Workflow Hygiene:
- Receipt verification builds must exclude Python/WASM bindings (
--exclude bitnet-py --exclude bitnet-wasm) - Required in both CPU and GPU build lanes to prevent libpython and WASM linker dependencies
- CI blocks PRs that remove these excludes from
verify-receipts.ymlvia the Guards gate - Keeps receipt verification hermetic and reproducible across CI environments
Violations will fail the required "Guards" check and block merge. See .github/workflows/guards.yml for detailed enforcement rules.
Recommended: One-command preflight check
# Run all guards checks with clear output (fail-fast)
make guards # or make preflightThis single command checks:
- ✅ Floating action refs (no @v1, @main, @stable, @latest)
- ✅ 40-hex SHA pins (external actions must use full commit SHA)
- ✅ MSRV consistency (must match rust-toolchain.toml)
- ✅ cargo/cross --locked flags (all build/test/run/bench/clippy)
- ✅ Receipt workflow excludes (bitnet-py/bitnet-wasm in CPU+GPU lanes)
Other helpers:
-
Add
--lockedto workflow commands safely (handlescargo run … -- …):scripts/fix-locked.sh .github/workflows/*.yml -
Validate CODEOWNERS team slugs (requires
ghauth):scripts/check-codeowners-teams.sh
-
Run guards locally (individual checks, for debugging):
# Check for floating action refs (no @v1, @main, @stable, @latest) rg --glob '!guards.yml' 'uses:.*@v[0-9]|uses:.*@(main|stable|latest)' .github/workflows || echo "OK: pinned" # Check for 40-hex SHA pins (external actions must use full commit SHA) rg --glob '!guards.yml' '^\s*uses:\s*(?!\./)[^ @]+/[^ @]+@(?![0-9a-f]{40}\b)' .github/workflows || echo "OK: 40-hex" # Check MSRV consistency (must match rust-toolchain.toml) rg --glob '!guards.yml' 'toolchain:\s*"?1\.90\.0"?|rust-version\s*=\s*"1\.90\.0"|\"RUST_VERSION\"\s*:\s*\"1\.90\.0\"' .github/workflows || echo "OK: MSRV" # Check cargo/cross --locked everywhere rg --glob '*.yml' --glob '!guards.yml' 'cargo (build|test|run|bench|clippy)' .github/workflows | grep -v -- '--locked' || echo "OK: locked"
Before submitting a PR, ensure:
- Run local guards check -
make guardspasses locally before push - Actions are SHA-pinned - No floating tags (@v3, @main, @stable, @latest); all external actions must use 40-hex commit SHAs
- Cargo/cross commands use
--locked- Allcargo/cross build/test/run/bench/clippyinclude--locked - MSRV compliance - Toolchain version must match
rust-toolchain.toml, no hardcoded versions in workflows - Guards check is green - CI will automatically validate these requirements (but catch issues early with
make guards)
-
Enable Pre-commit Hooks (first time only)
git config core.hooksPath .githooks
-
Run Local Preflight Guards (Recommended - CI alignment check)
# Quick preflight: Check CI guards (floating refs, MSRV, --locked flags) make guards # or make preflight
This verifies:
- ✅ All GitHub Actions are SHA-pinned (no floating @v3, @main, etc.)
- ✅ All action pins use 40-hex commit SHAs (immutable)
- ✅ MSRV: 1.93.0 — see
rust-toolchain.toml) - ✅ All cargo/cross commands use
--lockedflags
Why run this locally? Catches CI blockers before push, saving CI minutes and iteration time.
-
Run Local Quality Gates (Recommended - full validation)
# CI-equivalent local smoke: fmt → clippy → build → test (core pkgs) ./ci/local.shOr run individual checks:
-
Format and Lint
cargo fmt --all cargo clippy --locked --all-targets --all-features -- -D warnings
-
Run Full Test Suite
cargo nextest run --locked --workspace --no-default-features --features cpu # Or with cargo test cargo test --locked --workspace --no-default-features --features cpu
-
Verify Inference Receipt (if you have ci/inference.json)
# Verify CPU receipt cargo run --locked --no-default-features -p xtask -- verify-receipt --path ci/inference.json # Verify GPU receipt (requires GPU kernels) cargo run --locked --no-default-features -p xtask -- verify-receipt --path ci/inference.json --require-gpu-kernels
-
Update Documentation
cargo doc --locked --workspace --no-default-features --features cpu --no-deps
-
Cross-validate Changes (optional, for inference changes)
cargo run --locked --no-default-features -p xtask -- full-crossval
- Title: Use conventional commits format (
feat:,fix:,docs:) - Description: Include what, why, and testing performed
- Tests: All new code must include tests
- Documentation: Update relevant documentation
- Backwards Compatibility: Document any breaking changes
- Automated Checks: All CI checks must pass
- Code Review: At least one maintainer approval required
- Cross-validation: Must pass accuracy validation
- Performance: No significant performance regressions
BitNet-rs uses a label-gated CI system to optimize CI resource usage. By default, only fast core checks run on every PR:
- Build & Test (ubuntu-latest, ~5 minutes)
- Clippy (linting)
- Documentation (doc generation)
- CI Core Success (aggregate gate)
Optional label-triggered workflows run heavier validation on-demand. Add these labels to your PR to trigger additional checks:
| Label | Workflow | Description | Typical Runtime |
|---|---|---|---|
gpu |
GPU Tests | CUDA kernel validation (requires GPU runner) | ~10-15 min |
quant |
Quantization Matrix CI | Build & test quantization features (I2S, TL1, TL2, IQ2_S) | ~15-20 min |
crossval |
Cross-Validation Determinism | Compare Rust vs C++ reference implementation | ~20-30 min |
perf |
Performance Regression Gate | Benchmark validation against baselines | ~20-30 min |
integration |
Integration Tests | Full integration test suite | ~15-25 min |
receipts |
Receipt Verification | Verify inference receipt quality gates | ~10-15 min |
coverage |
Code Coverage | Generate coverage report (70% threshold) | ~10-15 min |
stress |
TL LUT Stress Tests | Deterministic stress tests for table lookup kernels | ~30-45 min |
When to use labels:
gpu: Required for GPU kernel changes, CUDA optimizations, or device selection logicquant: Required for quantization algorithm changes (I2S, TL1, TL2, IQ2_S)crossval: Recommended for inference engine changes, ensures parity with C++ referenceperf: Required for performance-critical changes, prevents regressionsintegration: Recommended for multi-crate changes, end-to-end validationreceipts: Required for receipt schema changes, kernel ID validationcoverage: Optional, useful for tracking test coverage improvementsstress: Optional, validates deterministic behavior under heavy load
Example workflow:
# 1. Create PR (core checks run automatically)
gh pr create --title "feat: optimize QK256 dequantization" --body "..."
# 2. Add labels to trigger optional checks
gh pr edit 123 --add-label quant,perf,crossval
# 3. CI runs: core + quantization + performance + cross-validation
# 4. Remove labels after validation (optional, to save CI minutes on subsequent pushes)
gh pr edit 123 --remove-label quant,perf,crossvalCI Configuration Notes:
- Timeouts: All jobs have appropriate timeouts (15-60 minutes) to prevent hangs
- Continue-on-error: Some jobs (like
coverage,crossval) are informational during stabilization - Branch protection: Only the 4 core checks are required; optional jobs are skipped by default
- Workflow dispatch: Most label-gated workflows can also be triggered manually via GitHub Actions UI
See also: .github/workflows/ for individual workflow definitions and trigger conditions.
Important: BitNet-rs uses path filters in GitHub Actions workflows to prevent unnecessary CI runs and keep costs low. When adding or modifying CI configuration files, you must ensure the appropriate workflows are triggered—otherwise PRs can hang waiting for required checks that never start.
Path filters determine which workflows run based on what files changed in a PR:
- ci-core.yml: Required for all PR merges. Runs only when specific paths change (Rust code, config files, CI workflows)
- coverage.yml: Label-gated. Runs on
mainpush and PRs labeledcoverageorfull-ci - Other workflows: Scoped to their domain (GPU, quantization, fuzz, etc.)
If your PR changes a file but the workflow that validates those changes has a path filter that doesn't include that file, the workflow won't run—and if it's a required check, your PR will hang waiting for it.
When adding a new workflow or CI config file, update both:
-
ci-core.yml path filters — Include if the file affects Rust compilation, test execution, or core verification:
- ✅ Workflow files (
.github/workflows/*.yml) → Add toci-core.ymlpaths - ✅ Config files that affect verification (
codecov.yml,.rustfmt.toml, etc.) → Add toci-core.ymlpaths - ✅ Rust source code, Cargo.toml, etc. → Already included
- ❌ Docs-only changes → Use existing doc workflow filters instead
- ✅ Workflow files (
-
Any new workflow's path filters — If you create a new workflow, define its path filters to avoid running on unrelated changes
If you create a new workflow file (e.g., quality-gates.yml) that validates CI configuration:
name: Quality Gates
on:
pull_request:
branches: [ main ]
paths:
- '.github/workflows/**' # Run when any workflow changes
- 'codecov.yml' # Run when coverage config changes
- '.rustfmt.toml' # Run when formatter config changesThen add this workflow file to ci-core.yml path filters (if it's a required check):
paths:
- '.github/workflows/ci-core.yml'
- '.github/workflows/quality-gates.yml' # ← Add new workflow hereIf your PR shows this error on GitHub:
- ✓ 4 required checks passed
- ✗ 1 required check not yet reported
Likely cause: A required workflow (usually ci-core) has path filters that don't match your changed files.
Solution:
- Check what you changed (files in the PR)
- Look at the required workflow's path filters in
.github/workflows/ci-core.yml - If your changed files aren't in the path filters, add them
- Commit and push the updated workflow file
- The workflow should now trigger and complete
Example PR flow:
# 1. Change codecov.yml (CI config)
# 2. Push PR → ci-core doesn't run (codecov.yml not in path filters)
# 3. PR hangs: "4 of 5 required checks"
# 4. Update ci-core.yml to include codecov.yml in paths
# 5. Push update → ci-core now triggers
# 6. After ci-core passes, PR mergesSee also:
- CI Cost and Verification Policy — Design rationale for path filters and CI lanes
.github/workflows/ci-core.yml— Current path filter definitions (search for "paths:")
If you're contributing GPU backend code (kernels, new backends, device selection), see the dedicated GPU guides:
- GPU Contributor Guide — Step-by-step guides for adding kernels and backends, testing without hardware, and GPU code style conventions
- GPU Development Workflow — Branch naming, PR templates, CI pipeline, review checklists, and performance regression detection
Quick start for GPU contributors:
# Build and test without GPU hardware
cargo build --locked --no-default-features --features cpu
cargo nextest run --locked --workspace --no-default-features --features cpu
# Build with GPU support (requires CUDA toolkit)
cargo build --locked --no-default-features --features gpu
# Test GPU code paths without hardware
BITNET_GPU_FAKE=1 cargo test --locked -p bitnet-kernels --no-default-features --features gpuGPU branches use the intel-gpu/<feature-name> naming convention. Add the gpu label
to your PR to trigger GPU-specific CI checks on self-hosted runners.
bitnet: Main library with unified public APIbitnet-quantization: Quantization algorithms (I2S, TL1, TL2)bitnet-kernels: High-performance SIMD/CUDA kernelsbitnet-inference: Inference engine with streamingbitnet-models: Model loading (GGUF, SafeTensors)bitnet-tokenizers: Universal tokenizer with GGUF integration
- Zero-Copy: Minimize allocations and copies
- Device-Aware: Automatic GPU/CPU selection
- Type Safety: Leverage Rust's type system for correctness
- Performance: Target high-performance computing workloads
- Compatibility: Maintain API stability and GGUF compatibility
- Documentation: docs/ directory with comprehensive guides
- Examples: examples/ directory with working code
- Issues: GitHub Issues for bug reports and feature requests
- Discussions: GitHub Discussions for questions and ideas
By contributing to BitNet-rs, you agree that your contributions will be licensed under the same terms as the project (MIT OR Apache-2.0).
Please read and follow our Code of Conduct.
Thank you for contributing to BitNet-rs! Your contributions help advance high-performance neural network inference in Rust.