How to Contribute
We accept code, docs, bug reports, and feedback from anyone willing to file them clearly. This page covers the mechanics: how to get a change in, what we look for in review, and what to expect after you open a PR.
See Communication for non-code contributions (reporting issues, feedback, getting help).
See RFC process for larger changes that need design discussion before implementation.
Before you start
For anything larger than a typo fix:
- Check the issue tracker. Someone may already be working on it or have filed a related discussion.
- Read
AGENTS.md. The repo’s rootAGENTS.mdis the canonical source of convention: risk tiers, PR discipline, anti-patterns, and review standards live there. - Use the Architecture and contribution map for anything that touches architecture, config, security, workflow, governance, CI, release behavior, or AI-assisted contribution policy.
- Pick a branch. PRs target
master. Fork the repo and branch from there; there’s no develop/integration branch to go through.
The flow
fork → branch → commit → push → open PR → review → merge (squash)
The key checkpoints:
- PR template:
.github/pull_request_template.md. Fill it out. The summary, validation evidence, and compatibility sections are non-negotiable. - CI: runs on every PR.
ci.ymlis the composite gate; all legs must pass. - Labels: maintainers use labels to route review depth. You do not need to know every label family before opening a PR. If labels look obviously wrong and you cannot edit them, flag the mismatch in a comment; maintainers or reviewers with label permissions can correct obvious mismatches directly.
- Review routing: make the scope, linked issues, validation, and risk/rollback context clear enough that reviewers can choose the right review path quickly.
- Review: maintainers review. Findings use the PR review taxonomy: 🔴 blocking, 🟡 warning, 🔵 suggestion, 🟢 praise, and ✅ resolved. Address blockers; warnings should get a response; suggestions are optional.
Code style
cargo fmtclean (checked in CI)cargo clippy -D warningsclean (checked in CI)- No unused production code: delete it, wire it into behavior, or track a follow-up issue. Do not silence it with underscore prefixes or
#[allow(dead_code)]; reserve underscore names for required but intentionally unused API, trait, or callback parameters. - Error handling:
anyhow::Resultat binary boundaries, typed errors in library crates. Nounwrap()/expect()in production code paths: propagate with?or document the invariant that makes panic impossible. - Minimal dependencies: every dep adds to binary size; weigh the trade before adding one
- Trait-first: define the trait in
zeroclaw-api, then implement in the right edge crate - Security by default: allowlists, not blocklists. New external surface defaults closed
- Inline unit tests:
#[cfg(test)] mod tests {}at the bottom of the file or a siblingtests.rs - Don’t commit secrets, personal data, or real-user identities: the Privacy & PII discipline page is the merge gate
Testing
- Unit tests co-located with the code (
mod tests) - Integration tests in
tests/and crate-local unit tests: run viacargo nextest run --locked --workspace --exclude zeroclaw-desktop - Feature-gated code needs feature-gated tests
- Don’t mock the database for tests that exercise schema or SQL: integration tests must hit a real SQLite
For the full five-level taxonomy (unit / component / integration / system / live), shared mock infrastructure, and JSON trace fixture format, see Testing.
Docs changes
- Prose changes go in
docs/book/src/**/*.md(this mdBook) - Rustdoc (
///) changes update the API reference automatically on deploy - Reference pages (
docs/book/src/reference/cli.md,config.md) are generated; don’t hand-edit. Runcargo mdbook refsand commit the output - Localisation: English markdown is the source of truth. Routine English docs PRs may omit broad generated
.pochurn; use the standard PR-body note in Building the docs locally. - Translation-cache PRs, release translation passes, and new locales should run
cargo mdbook sync, commit the resulting.pofiles, and validate them withcargo mdbook check
Publishing blog or website metadata
When you publish a blog post or otherwise update the public blog metadata, update the hand-maintained feed timestamps in the same PR:
web/public/blog/rss.xml: set<lastBuildDate>to the latest post publish time in RFC 2822 / GMT formatweb/public/blog/atom.xml: set<updated>to the latest post publish time in ISO 8601 UTC formatweb/public/sitemap.xml: set the/blogentry’s<lastmod>to the latest publish date
Keep feed discovery environment-local:
web/index.htmlshould keep/blog/rss.xml,/blog/atom.xml, and/sitemap.xmlas root-relative linksweb/public/sitemap.xmlshould list the human-facing/blogpage, not the XML feed files
Commit messages
Conventional Commits:
feat(providers): add support for DeepSeek reasoning mode
fix(channels/matrix): prevent duplicate device sessions after verify
docs(getting-started): add YOLO-mode quick-start
refactor(runtime): split agent loop into steps
chore: bump tokio to 1.43
AI-assisted collaboration is welcome, but do not add bot/AI attribution trailers or generated tool footers to PR bodies or commit-message tails. Human Co-authored-by: trailers remain appropriate for incorporated contributor work when they follow the superseding and privacy rules. See FND-005 (Contribution Culture) for the full norm.
Pull requests
Title mirrors the squash commit:
feat(scope): short description
Body uses the PR template. The validation-evidence section is required: paste the checks that match the change. For docs-only PRs, use scripts/ci/docs_quality_gate.sh and scripts/ci/docs_links_gate.sh or explain why link checking had no added links to inspect. For Rust/code PRs, include cargo fmt --check, cargo clippy, cargo test, plus whatever manual verification you did. “It works on my machine” is not evidence.
Risk labels:
risk: low: rollback is a revert; no user action neededrisk: medium: users may need to update config / env / CLI usage; rollback plan requiredrisk: high: security-critical, schema changes, breaking behaviour. Rollback plan, feature flag, and observable failure symptoms required
After the PR
Merge strategy: squash-merge with the full commit history preserved in the body. See .claude/skills/squash-merge/SKILL.md for the exact format: TL;DR: PR title + (#number) as the subject, bullet list of original commits as the body.
Release: changes land on master; master does not auto-release. A maintainer bumps the version and tags vX.Y.Z when a release ships. You’ll see your PR in the CHANGELOG.
Areas that want help
| Area | Where to start |
|---|---|
| New channel | crates/zeroclaw-channels/: copy an existing channel of similar shape |
| New provider | crates/zeroclaw-providers/: compatible.rs covers most OpenAI-like ones |
| Docs | docs/book/src/: anything marked outdated or missing |
| Translations | cargo fluent fill --locale <code>: see Maintainers → Docs & Translations |
| Hardware | crates/zeroclaw-hardware/: new board support, new sensor drivers |
Code of conduct
Don’t be a jerk. Disagree on ideas; not people. Accept that maintainers will close things they don’t want to own, usually with an explanation, occasionally without. If a close feels unjustified, ask; if the ask goes nowhere, move on.
See also
- RFC process: for anything bigger than a patch
- Architecture and contribution map: which architecture, foundation, and workflow docs to read first
- Communication: how to reach the team
- Maintainers → Overview: what maintainers do day-to-day