Thanks for your interest in contributing. This document covers prerequisites, the development loop, and the process for getting changes merged.
- Rust 1.95+ via rustup. The
rust-toolchain.tomlpins the exact version; rustup will install it automatically when you run any cargo command. just— task runner. Install withcargo install justorbrew install just.lefthook— git hooks. Install withbrew install lefthook(macOS/Linux) orscoop install lefthook(Windows).- Chromium — required at runtime by the CDP driver.
plumb-fake://fixture tests run without it; real-URL linting requires a Chromium install.
Plumb uses symlinks (CLAUDE.md → AGENTS.md, .claude/rules → .agents/rules, .claude/skills → .agents/skills). To clone cleanly on Windows:
git config --global core.symlinks trueYou also need Developer Mode enabled or an Administrator shell for git clone to materialize symlinks.
git clone https://github.com/aram-devdocs/plumb
cd plumb
just setup # install hooks, verify toolchain, check Chromium
just check # fmt + clippy, fails on any warning
just test # full test suite via cargo-nextest
just validate # full pre-push mirror — matches CI exactlyjust with no arguments lists every available target.
All commits follow Conventional Commits. The allowed types are:
feat · fix · perf · refactor · docs · test · build · ci · chore · style · revert
Allowed scopes match the crate or area: core, cli, mcp, cdp, config, format, docs, ci, or a rule id like spacing/hard-coded-gap.
The commit-msg hook validates this locally. The pr-title GitHub workflow validates it on every pull request.
Plumb enforces strict quality gates end-to-end. These gates have no opt-out:
cargo fmt --checkmust pass.cargo clippy -- -D warningsmust pass (clippy pedantic + custom deny list).- Every library crate has
#![forbid(unsafe_code)],#![deny(missing_docs)], and deniesunwrap_used/expect_used/print_stdout/print_stderr/dbg_macro/todo/unimplemented. plumb-coreadditionally forbidsstd::time::SystemTime::now/Instant::now(determinism).cargo-denychecks licenses, advisories, and banned crates on every CI run.- Binary size must stay under 25 MiB.
- Output must be deterministic — the
determinismCI job runs a fixture three times and byte-diffs the output. cargo-auditruns daily against the advisory database.
There is no SKIP_VALIDATION env var, no --no-verify support, and no escape hatch in the pre-push hook. If a check fails, fix the cause. If a check is genuinely wrong, open an RFC issue proposing to change it.
Cargo.lockis committed. Never ignore it.[patch.crates-io]is forbidden without an ADR documenting the justification and removal plan.- New direct dependencies require justification in the PR description. Prefer crates that are already in the tree.
cargo-denyblocks GPL, AGPL, and LGPL licenses. Dual-licensed dependencies are fine if the compatible half is MIT, Apache-2.0, BSD, ISC, Unicode, Zlib, or MPL-2.0.
See .agents/rules/rule-engine-patterns.md. The short version:
- Create
crates/plumb-core/src/rules/<category>/<id>.rsimplementingRule. - Register it in
crates/plumb-core/src/rules/mod.rs::register_builtin. - Add a golden snapshot test under
crates/plumb-core/tests/. - Document it at
docs/src/rules/<category>-<id>.md— this is whatplumb explainreads. - Wire
doc_urlin the rule to point athttps://plumb.aramhammoudeh.com/rules/<category>-<id>.
See .agents/rules/mcp-tool-patterns.md. Tools live in crates/plumb-mcp/src/lib.rs under the #[tool_router] impl.
- Fork or branch, make your changes, push.
- Open a PR. The title must follow Conventional Commits.
- Fill out the PR template — especially the Test plan and Breaking change sections.
- CI must be green:
preflight,test(Linux/macOS/Windows),msrv,determinism,deny,size-guard,docs. - One approving review from a
CODEOWNERSentry. - Maintainer merges with Squash and merge. The final commit message must still follow Conventional Commits — release-please depends on it.
Releases are cut by release-please from conventional commits on main. Maintainers only — see docs/adr/0001-bootstrap-conventions.md for details.