Thanks for considering a contribution! This document covers how to build, test, and land changes.
- Quick loop
- Repository layout
- Development environment
- Filing issues
- Pull request workflow
- Coding standards
- Testing
- Commit messages
- Adding a detector
- Adding a subcommand
- License of contributions
git clone https://github.com/bootintel/cli.git
cd cli
cargo build --release --features tui
cargo test --features tui
./target/release/bootintel demo # runs against the embedded sampleIf you see 0 warnings and test result: ok, you're set up.
crates/detectors/ # pure regex detector library, no I/O, one dep (regex)
crates/cli/ # the `bootintel` binary — clap CLI, subcommands, TUI, HTTP client
samples/ # 31 boot-log samples used by the corpus_smoke test suite
packaging/ # install.sh, Homebrew formula, Docker (via /Dockerfile), Nix (/flake.nix)
.github/workflows/ # CI, release, action-selftest
.github/actions/ # reusable GH Action wrapper (bootintel-scan)
- Rust: MSRV is declared in
Cargo.toml(workspace.package.rust-version). CI builds against it to make sure the pin is honest.rustup toolchain install <that-version>if you don't have it already. - Linux only:
libudev-devfor theserialportcrate.sudo apt-get install libudev-devon Debian/Ubuntu. - Optional:
dockerfor the container build,nixfor the flake, a serial adapter orsocatPTY pair for interactiveterm/analyzetesting.
Search existing issues before opening a new one. Include:
bootintel versionoutput (or the exact commit if you're onmain).- Your OS + terminal + shell.
- A minimal reproduction. For scan-related bugs, a boot log excerpt (or link to one of the samples in
samples/). - What you expected vs. what happened.
Security issues go to hello@bootintel.com — see SECURITY.md.
- Fork the repo (or if you have write access, branch directly).
- Create a topic branch:
git checkout -b fix-thingorfeat-thing. - Make focused commits — one logical change per commit, not "wip" / "more" / "typo".
- Run the checks locally:
cargo fmt --all --check cargo clippy --features tui --all-targets -- -D warnings cargo test --features tui - Push + open a PR against
main. - CI runs the same checks plus builds on Linux / macOS / Windows plus MSRV. If CI is red, fix and push — don't force-push mid-review unless you're rebasing on a request.
We aim to respond to PRs within a week. If a PR sits waiting on us for more than that, ping in the PR thread — sometimes life happens.
- Code that stays consistent with the rest of the file (naming, imports, error handling).
- New behavior is tested. New detectors get positive + negative unit tests. New CLI flags get an integration test in
crates/cli/tests/. - No new panics on untrusted input — see SECURITY.md for the trust boundary.
- Docstrings on public items explain why the thing exists, not just what it does.
- No unrelated changes bundled in ("while I was here..." refactors go in separate PRs).
- Formatting:
cargo fmt --all. No opinionated overrides; the tree uses defaults. - Linting:
cargo clippy -- -D warningson default features and--features tui. New clippy warnings block CI. - Error handling:
anyhowat the top level of subcommand entry points;thiserrorfor typed errors in libraries. Wrap errors with actionable context (.with_context(|| format!("opening {}", path.display()))) — CI logs and bug reports thank you. - Panics: avoid
unwrap()/expect()in production paths unless a preceding check makes the invariant true. Comments on any survivingunwrap()should explain why it's infallible. unsafe: currently zero in the workspace. If you needunsafe, discuss in an issue first — we'd rather add a safe helper crate than embed unsafe blocks.- Dependencies: each new dep needs a rationale. Small std-only implementations are preferred over pulling a crate for one line.
- Unit tests live alongside the code (
#[cfg(test)] mod tests). - Integration tests live in
crates/*/tests/*.rs. - Test discipline: deterministic (no wall-clock waits, no filesystem-dependent paths beyond
TempDir), fast (<10s for the full suite), self-contained (no network unless via a hand-rolled localhost mock — seecrates/cli/src/api/client.rstests for the pattern). - Run everything before pushing:
cargo test --features tui cargo test --no-default-features # feature-flag hygiene
Loose convention, not strict:
component: short summary of the change (<= 65 chars)
Longer explanation of *why* this change is being made. What broke,
what the fix is, what edge cases were considered. Aim for someone
running `git blame` in six months to understand the intent without
having to dig through the PR thread.
Fixes: #123 (if applicable)
Component names loosely mirror the tree — cli, detectors, tui, api, docs, ci, packaging.
New detectors live in crates/detectors/src/lib.rs.
- Add the regex as a
static LazyLock<Regex>. - Add a
fn detect_thing(&str) -> Option<Finding>that runs the regex and returns aFinding. - Wire it into
analyze()alongside the existing detectors. - Add unit tests: at least one positive case and one negative-case log excerpt that shouldn't match.
- If the detector should sync with the browser detector library at bootintel.com/tools/fingerprint, coordinate with a maintainer — the browser + CLI detector sets should stay label-aligned.
New subcommands live in crates/cli/src/cmd/<name>.rs.
- Create the file. Copy the shape of a simple existing subcommand (e.g.
demo.rsordetectors.rs). - Register it in
crates/cli/src/main.rs:mod cmd { pub mod newthing; } #[derive(Subcommand)] enum Cmd { // ... Newthing(cmd::newthing::Args), }
- Add integration tests in
crates/cli/tests/. - Update the README subcommand table.
- Update
CHANGELOG.mdunder## [Unreleased] / ### Added.
By submitting a pull request, you agree that your contribution is licensed under Apache-2.0 (the same license as this project). No CLA to sign.