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, testing 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 testing section is required: explain how the change was checked, and paste the checks that match the change. The reviewer-run A/B recipe under How you can test is only needed when manual verification adds useful signal; mark it N/A for docs-only, pure-refactor, or trivial changes without a meaningful reviewer test path. 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, use the evidence that matches the changed surface: required CI checks, focused crate or regression tests, manual smoke, or full workspace checks when broad coverage proves something narrower evidence would miss. Fresh required CI is enough when it covers the changed surface; extra local Cargo is not required just to duplicate the same head, target, and feature set. Add more evidence when the PR depends on a known CI coverage gap: platform-specific tests, cross-platform lint, desktop app coverage, release target builds, stale CI, or unavailable CI. “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