See docs/guide.md for the user-facing handler/client API
and the README for the workspace layout.
- Rust 1.88+ (MSRV; the codebase uses let-chains).
protocv27+ — the test and example protos use editions syntax (edition = "2023"). Ubuntu's aptprotobuf-compiler(v21) is too old; install from the protobuf releases page or viaarduino/setup-protocin CI.task generate:alland theconnectrpc-buildconsumers need it.buf— used to drive regeneration of the checked-in code (thebuf.gen.yamlfiles invoke locally-built plugins).task(go-task) — the repo's command runner.task --listshows everything.
Keep each change to ≤ 250 lines net (additions minus deletions,
excluding test files and */generated/*) wherever possible. If a task
naturally exceeds that, split it into focused, self-contained PRs or
commits.
Every change must include unit tests. Target ≥ 80% line coverage for
new code. Reaching 100% is not required when the remaining paths would
require artificial tests, but coverage gaps must be intentional and
justified. Tests live in #[cfg(test)] modules colocated with the code
they test; the tests/streaming crate is the in-workspace e2e consumer
of connectrpc-build.
- Run
task lintandtask testbefore every commit (ortask cito also run docs, minimal-features, and the multiservice example). - Public API items require doc comments (
///); include# Errors/# Panicssections where applicable. - Every
unsafeblock requires a// SAFETY:comment explaining the invariant. - Avoid
.unwrap()outside tests and provably-safe paths. #[inline]only with full-path profiling evidence.
All code generation uses quote! blocks rather than string manipulation;
prettyplease formats the final TokenStream into readable Rust source.
The pipeline mirrors buffa's: accumulate TokenStream → syn::parse2 →
prettyplease::unparse.
Key rules:
- Regular
//comments are not tokens and are silently dropped byquote!. Only doc comments (///→#[doc = "..."]) survive. - Identifiers must go through
format_ident!(orIdent::new_rawfor Rust keywords). Never interpolate raw strings as identifiers. - Type paths resolved from the descriptor context use
rust_path_to_tokens(which wrapssyn::parse_str::<syn::Path>). - Generated code uses fully-qualified paths everywhere
(
::connectrpc::...,::buffa::...) — nousestatements at module scope. This lets multiple generated files beinclude!d into the same Rust module without E0252 collisions.
The Connect protocol conformance suite runs against both server and
client implementations. task conformance:download fetches the runner;
task conformance:build builds the binaries.
| Suite | Task | Tests |
|---|---|---|
| Server default (all protocols) | task conformance:test |
3600 |
| Server Connect-only | task conformance:test-connect-only |
1192 |
| Server Connect+TLS | task conformance:test-connect-tls |
2396 |
| Client Connect | task conformance:test-client-connect-only |
2580 |
| Client gRPC | task conformance:test-client-grpc-only |
1454 |
| Client gRPC-Web | task conformance:test-client-grpc-web-only |
2838 |
A healthy run ends with N passed, 0 failed. CI runs the server-default
and the three client suites.
Five directories contain checked-in buf generate output and must be
regenerated whenever connectrpc-codegen output changes (or the buffa
dependency is bumped):
conformance/src/generated/examples/eliza/src/generated/examples/multiservice/src/generated/benches/rpc/src/generated/connectrpc-health/src/generated/
Regenerate all of them with:
task generate:allThis rebuilds protoc-gen-connect-rust (and the sibling buffa plugins
from ../buffa) in release mode, then runs buf generate in each
directory. CI runs a separate generated-code check that fails when these
checked-in files are stale.
To test combined speculative changes across both repos:
task buffa:link # writes .cargo/config.toml pointing at ../buffa
task buffa:unlink # removes the override; reverts to crates.io / [patch]The override is gitignored and never reaches CI or cargo publish.
GitHub Actions CI (.github/workflows/ci.yml) runs on every push to
main and on all pull requests. Jobs:
- Check —
cargo check --workspace --all-features --all-targetswithRUSTFLAGS=-Dwarnings - Test —
cargo test --workspace - Clippy — workspace, all targets,
-D warnings, on a pinned toolchain (currently 1.95) so new-stable lints don't break CI unannounced - Format —
cargo +nightly-2026-02-27 fmt --check. Nightly is required becauseformat_generated_files = falseinrustfmt.tomlis a nightly-only option; the date is pinned because rustfmt output drifts across releases. Use the same dated nightly locally (rustup toolchain install nightly-2026-02-27 -c rustfmt); bump it together with thefmtjob in.github/workflows/ci.yml - Check generated code — runs
task generate:alland verifies the checked-in generated directories have no diff - Documentation —
cargo docwith broken-intra-doc-links denied - MSRV (1.88) —
cargo checkon the pinned minimum toolchain - Examples — builds and runs the example crates
- Minimal features —
cargo check -p connectrpc --no-default-features - Wasm —
wasm32-unknown-unknownbuild of the client example - Conformance (server) / Conformance (client) — full suites