Thanks for your interest in improving Busbar. This document covers how to build, test, and submit changes.
After tagging, run tests/migration-corpus/refresh.sh so the new release's config.yaml joins the
corpus. crates/busbar/tests/migration_corpus.rs then asserts, on every CI run, that a config from
that version still migrates to whatever the current shape is.
The point is that the guarantee grows automatically: an operator on any released version can run
busbar --migrate-config and get something that boots. See
tests/migration-corpus/README.md for why it holds real shipped files rather than fixtures.
- Be respectful and constructive in all project spaces.
- By contributing, you agree your contributions are licensed under the project's Apache-2.0 license.
- Security issues go through SECURITY.md, not public issues.
Busbar is a single Rust binary. You need a recent stable toolchain
(rustup recommended).
cargo build # debug build
cargo test # run tests
cargo clippy --all-targets -- -D warnings # lints must be clean
cargo fmt --all # format before committingRun locally against the shipped example config (two YAML files; keys are supplied
via the env vars named in config.yaml):
export BUSBAR_CLIENT_TOKEN=dev-token
export ANTHROPIC_KEY=sk-ant-... # any provider key referenced by config.yaml
BUSBAR_PROVIDERS=./providers.yaml BUSBAR_CONFIG=./config.yaml cargo run
curl -s localhost:8080/healthz
curl -s -H "Authorization: Bearer $BUSBAR_CLIENT_TOKEN" localhost:8080/stats | jqSee docs/configuration.md for the full config reference.
cargo fmt --all— code must be rustfmt-clean.cargo clippy --all-targets -- -D warnings— no warnings.cargo build && cargo test— green.- Add or update tests for any behavior change. The circuit-breaker disposition logic in particular should be covered by tests, not just inspection.
- No
_ =>catch-all arms in disposition/breakermatchstatements — the exhaustive match is how the compiler enforces that every failure mode is handled. This is a project invariant. scripts/structure-lint.sh— green. Beyond code layout it enforces the remediation contract's choke-point registry.- Update documentation when you change behavior or config.
Read docs/testing.md § The remediation contract before fixing a bug. In short:
- A finding with a sibling is not a bug — it is a missing choke point. If the same mistake is possible at a second call site, fix the class, not the instance.
- The fix is the choke point + ONE class-level test, not N patched instances with N tests.
- A repeat sibling means the class was never fixed: the previous remediation patched an instance instead of the class.
- A defect test must be contract-derived, RED-demonstrated, or
cross-checked by an independent oracle — a
assert_eq!(actual, <inline constant>)that restates the implementation guards nothing.
Your changeset should name the choke point it attaches to, its one class-level
test, and the RED-before note (RED at <sha>: <failure line>).
- Keep commits focused; squash noisy WIP commits before opening the PR.
- Write a clear PR description: what changed, why, and how it was verified.
- Reference any related issue.
- Stage files by name; avoid sweeping
git add -Athat pulls in unrelated changes.
The circuit breaker — the upstream-vs-client failure taxonomy — is the core of the project; changes there deserve extra care and review. A backend is ejected for upstream faults but never for client-supplied 4xx.
Open a discussion or issue. We're happy to help you get oriented.