Contributing to Copper
July 31, 2026 · View on GitHub
Thank you for helping build a deterministic, production-ready robotics runtime. Contributions of code, components, documentation, examples, and careful bug reports are all welcome.
Choose Where to Start
| You want to… | Best next step |
|---|---|
| Ask a usage question | Search the documentation or ask on Discord. |
| Report a bug or request a feature | Open the matching issue template. |
| Propose a runtime or architectural change | Start a Discussion before investing in a large implementation. |
| Add a reusable driver, task, bridge, or payload | Read Contributing Components; an independent crate is often the best home. |
| Improve docs or examples | Open a focused pull request and update related wiki/book material when behavior and documentation move together. |
| Report a vulnerability | Follow the private process in SECURITY.md. Do not open a public issue. |
All community participation is governed by our Code of Conduct.
Set Up the Workspace
Copper's minimum supported Rust version is 1.95. Install the latest stable Rust
toolchain with rustup, then install
just and clone your fork:
cargo install just
git clone https://github.com/YOUR_USERNAME/copper-rs.git
cd copper-rs
The Ubuntu development dependencies are documented in
support/docker/Dockerfile.ubuntu. Other
platforms may require equivalent system packages.
One-time tools used by the full PR check
The root justfile is the source of truth. Its checks use cargo-nextest,
typos-cli, taplo-cli, fmtron, and prek:
cargo install --locked cargo-nextest typos-cli taplo-cli fmtron prek
The public API check also pins a nightly toolchain and cargo-public-api version.
Run just api-check; if either is missing, it prints the exact versioned install
command required by the current repository.
Coverage additionally requires cargo-llvm-cov and llvm-tools-preview:
cargo install --locked cargo-llvm-cov
rustup component add llvm-tools-preview --toolchain stable
Contribution Workflow
- Create a branch from
masterusinguser/kind/description, for examplealex/fix/replay-seek. - Make one focused change. Add tests and update documentation or examples where the behavior needs them.
- Run
justfrom the repository root. It formats the workspace, runs lint and API checks, and tests the std andno_stdsurfaces. - Review the complete diff, then commit with a clear message. Conventional Commits are welcome but not required.
- Push your branch and open a pull request to
master. Explain the problem, the chosen approach, and how you verified it.
The pull request template contains the final submission checklist.
Checks
Prefer the root justfile over copying long Cargo command lines:
| Change | Run |
|---|---|
| Most pull requests | just or just pr-check |
| Formatting, typos, and clippy only | just lint |
| Host/runtime behavior across the std feature matrix | just std-ci |
Shared, embedded-facing, or no_std code | just nostd-ci |
| Coverage-sensitive behavior | just coverage |
| Runtime proc-macro expansion | just expand-runtime pkg=<crate> bin=<bin> [features=<features>] |
| SoA derive expansion | just expand-soa |
Linux is the primary full-workspace gate. macOS is also release-blocking, Windows validates a reduced core surface, and embedded coverage is compile-time rather than hardware-in-the-loop. See Supported Platforms for the public platform matrix.
Design Expectations
Copper has a deliberately opinionated architecture. Contributions should preserve these properties:
- Static over dynamic: prefer types, compile-time wiring, and generated code to runtime string lookup or mutable graph topology.
- Realtime paths stay lean: do not add allocations, copies, serialization passes, or latency to the hot path without explicit design agreement.
no_stdis a real target: shared crates, traits, and macros must not assume host-only APIs.- Determinism and replay are product features: runtime changes must preserve unified logging and reproducible replay.
- Use Copper's logs: inspect recorded CopperLists and structured logs before adding ad hoc text instrumentation.
- Keep abstractions understandable: solve the underlying design problem instead of hiding it behind runtime magic or invisible environment variables.
When proc-macro behavior is unclear, use the expansion recipes above. When a runtime
failure already has a .copper log, prefer extraction and resimulation before adding
new instrumentation.
Contributing Components
Reusable components do not always need to live in this monorepo. For a driver, task, bridge, payload, or monitor, the preferred path is usually:
- Publish it as an independent crate or repository so it can evolve on its own release cycle.
- Document its supported targets, configuration, and usage as a standalone Copper component.
- Add it to the Copper Component Catalog.
Open an issue or Discussion first if the component must be maintained in the main workspace or changes a shared Copper interface.
Dependency changes
Keep dependencies minimal and explain why each new dependency is required. Run
cargo shear when changing manifests:
cargo install --locked cargo-shear
cargo shear
If cargo-shear flags a feature-gated or build-time dependency incorrectly, document
the exception next to the affected package:
[package.metadata.cargo-shear]
# Required by build.rs for generated bindings.
ignored = ["some-crate"]
Optional local commit hooks
The repository's prek hooks run file hygiene, formatting, and typo checks:
prek install -f
prek run --all-files
Update .pre-commit-config.yaml if the shared hook configuration needs to change.
Maintainer release branches, versioning, tagging, and backporting are documented in RELEASING.md.