Contributing to Cabin
July 3, 2026 ยท View on GitHub
Thanks for your interest in contributing to Cabin. This document covers local setup, required
checks, and PR workflow. The canonical crate-boundary, scope, and ownership rules live in
docs/architecture.md; do not duplicate them here.
Prerequisites
- A recent stable Rust toolchain.
rustfmtandclippycomponents installed.taplofor TOML formatting.- For end-to-end build coverage: Ninja 1.10+, a C++ compiler (
g++,clang++, orc++), and a C compiler (gcc,clang, orcc) for tests that exercise.csources.
The unit tests in every crate, plus the resolution / lockfile integration tests, do not require Ninja or C/C++ compilers. The CLI build integration tests fail when those tools are missing, so install them before running the full suite.
Setup
git clone https://github.com/cabinpkg/cabin.git
cd cabin
cargo build --workspace
Required checks
cargo fmt --all --verbose -- --check
taplo fmt --check
typos
cargo clippy --workspace --all-targets --all-features --locked --verbose -- -D warnings
RUSTFLAGS="-D warnings" cargo check --workspace --all-targets --locked --verbose
RUSTFLAGS="-D warnings" cargo test --workspace --all-targets --all-features --locked --verbose -- --show-output
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --all-features --no-deps --locked --verbose
# Conventional-commit lint of the commits this branch adds.
# Mirrors CI's @commitlint/config-conventional gate; every commit header
# must be a valid conventional commit and stay <= 100 chars.
npx --yes --package @commitlint/cli --package @commitlint/config-conventional \
commitlint --extends @commitlint/config-conventional --from origin/main --to HEAD --verbose
The Rust CI workflow runs the Rust commands above and treats warnings as errors; a separate CI job
runs the commitlint command above against the PR's commits. Mirror the flags verbatim when
running locally, including:
--all-featureson bothcargo clippyandcargo doc- cabin gates several modules behind features, and dropping the flag hides lints and broken intra-doc links that CI still fires on;- the trailing
-- -D warningsoncargo clippy(theclippy::pedanticgroup is denied workspace-wide via[workspace.lints]in the rootCargo.toml, so it no longer needs a command-line flag); - the
RUSTFLAGS="-D warnings"environment variable oncargo check/cargo test, which holds the macOS- and Windows-specificcfgcode to the same warning-free bar the Linux-onlyclippyjob enforces for everything else (CI sets it for every job; Cargo caps lints for registry dependencies, so only the workspace crates are held to it); - the
RUSTDOCFLAGS="-D warnings"environment variable oncargo doc, so broken or redundant docs links fail locally rather than only in CI; --locked, which pins the resolution to the committedCargo.lock. Reviewers will reject PRs that silently bump transitive dependency versions.
The repository's typos.toml pins the project locale to American English; do not modify it
(including adding new extend-words entries) unless a reviewer explicitly asks for the change. If
typos flags a spelling, fix the offending occurrence instead of allowlisting it.
The separate CI workflow also runs workflow linting and commit-message linting. Commit subjects are
validated with commitlint against @commitlint/config-conventional, so every subject must follow
Conventional Commits (<type>(<scope>)?: <subject>,
lower-case subject, <= 100 characters). Body and footer lines, if present, must also stay <= 100
characters per line.
The test suite includes external-tool smoke tests for ninja, clang-format, run-clang-tidy, and
pkg-config. Those tests fail when the real tools are missing, so install them to run the suite.
The pkg-config and run-clang-tidy smoke tests are #[ignore]d on Windows, where those tools are
unavailable.
Code style
- Idiomatic Rust. Prefer simple, direct code over clever abstractions.
- Follow the diagnostic and crate-boundary rules in
docs/architecture.md. - Avoid
unwrap()/expect()outside of tests except where invariants are obvious and locally proven. - Public APIs stay small. Add a doc comment when the reason a type or function exists is not obvious from its signature.
- Tests live next to the code they exercise. CLI integration tests live in
crates/cabin/tests/cli.rsand exercise the compiledcabinbinary viaassert_cmd. The user-facing example projects underexamples/are exercised bycrates/cabin/tests/cabin_examples.rsusing the same pattern. When adding or changing tests, follow the test portability rules incrates/AGENTS.md(env isolation via the sharedcabin()helper, tool-availability gating, and no host-specific absolute paths).
Architectural rules
Read docs/architecture.md before changing crate boundaries, command
ownership, scope, diagnostics, generated formats, or build / registry / resolver behavior. When in
doubt, the architecture document wins.
Pull requests
- Keep PRs focused. One change per PR is easier to review and to revert.
- Add tests for behavior changes. New workspace, resolver, or build logic should land with unit
tests in the owning crate plus a CLI integration test in
crates/cabin/tests/cli.rs. - Update documentation when architecture or behavior changes. Update the relevant
docs/page. If you move code across crates, updatedocs/architecture.mdand the relevantAGENTS.mdrouting file. - Update the website when user-facing positioning changes. Copy on
website/(taglines, supported languages, supported platforms, top-level command surface, package-page install snippet) does not auto-regenerate from the Rust crates. A change that adjusts what Cabin is, what it builds, or how a user installs / declares / publishes a package must updatewebsite/in the same PR. SeeAGENTS.mdandwebsite/AGENTS.mdfor the docs/website checklist.
If you are unsure whether something belongs to the current scope, open an issue first or ask in the PR description rather than implementing it.