- This template targets Rust workspaces only.
bin/contains CLI binary crates.crates/contains reusable library crates.- No frontend/web-framework-specific assumptions.
-
Never manually type dependency versions in
Cargo.toml; usecargo add. -
Add workspace-level dependencies with:
cargo add <crate> --workspace
-
Add sub-crate dependencies with:
cargo add <crate> -p <crate-name> --workspace
-
Root
[workspace.dependencies]must use numeric versions only. -
Root
[workspace.dependencies]must not carry features by default. -
Sub-crates must use
workspace = trueforversion,edition, and shared dependencies.
When introducing new dependencies, prefer these versions unless compatibility requires an upgrade:
clap = "4.5.60"config = "0.15.19"eyre = "0.6.12"serde = "1.0.228"thiserror = "2.0.18"tokio = "1.49.0"tracing = "0.1.44"tracing-subscriber = "0.3.22"tracing-opentelemetry = "0.32.1"opentelemetry = "0.31.0"opentelemetry-otlp = "0.31.0"sqlx = "=0.9.0-alpha.1"utoipa = "5.4.0"utoipa-swagger-ui = "9.0.2"arc-swap = "1.8.2"hpx = "2.3.1"scc = "3.6.5"winnow = "0.7.14"shadow-rs = "1.7.0"ecdysis = "1.0.1"
- HTTP client preference:
hpx(withrustls) overreqwest. - Concurrent map/set preference:
sccoverdashmapandRwLock<HashMap<...>>. - Parsing preference:
winnoworpestover ad-hoc manual parsing. - Read-heavy shared state:
arc-swapoverRwLock. - Forbidden by default:
anyhow,log,reqwest,dashmap.
- Error handling:
- Application layer:
eyre. - Library layer:
thiserror.
- Application layer:
- Database (
sqlx):- Prefer runtime queries (
sqlx::query_as). - DB structs should derive
sqlx::FromRow. - Avoid compile-time
sqlx::query!macros by default.
- Prefer runtime queries (
- Concurrency:
- Prefer lock-free/container-first approaches (
scc,ArcSwap). - Avoid
Arc<Mutex<T>>when better alternatives are available.
- Prefer lock-free/container-first approaches (
- Observability:
- Logging:
tracingonly. - Metrics/traces: OpenTelemetry OTLP gRPC.
- Prometheus should not be the default instrumentation path.
- Logging:
- API docs:
- Generate OpenAPI with
utoipawhen exposing HTTP APIs.
- Generate OpenAPI with
- Configuration:
- Use the
configcrate and external configuration files (prefer TOML).
- Use the
- Binaries:
- Use
ecdysisfor graceful restart/reload flows in daemon/server binaries.
- Use
- Safety:
- Use
unsafeonly when strictly necessary and document the safety invariants.
- Use
- Modularity: Design each crate so it can be used as a standalone library with clear boundaries and minimal hidden coupling.
- Performance: Prefer architectures that support parallelism, memory-mapped I/O for large read-heavy workloads, optimized data structures, and lock-free data types.
- Extensibility: Use traits and generic types to support multiple implementations without invasive refactors.
- Type Safety: Maintain strong static typing across interfaces and internals, with minimal use of dynamic dispatch.
- Avoid allocations in hot paths; prefer references and borrowing to reduce allocation and copy overhead.
- Use
rayonfor CPU-bound parallel processing. - Use
tokioasync/await for I/O-bound concurrency.
- Prefer atomic types (
AtomicUsize,AtomicBool, etc.) with explicitOrderingfor simple shared state. - Use
sccfor highly concurrent maps/sets; avoidArc<RwLock<HashMap<...>>>andArc<Mutex<HashMap<...>>>on hot paths. - Use
mokafor concurrent caches instead of custom LRU implementations. - Prefer
parking_lot::{Mutex, RwLock}overstd::synclocks for synchronous locking. - Release
std::sync::Mutexandparking_lot::Mutexguards before hitting any.awaitpoint. - Use
tokio::sync::Mutexfor locks that span across.awaitpoints. - Use
tokio::task::spawn_blockingfor CPU-bound work and blocking I/O. - Batch work or use bounded worker patterns instead of spawning massive volumes of tiny Tokio tasks.
- Channel selection:
- Async-to-Async:
tokio::sync::mpsc/tokio::sync::broadcast - Sync/MPMC:
crossbeam-channelorflume - Avoid
std::sync::mpsc
- Async-to-Async:
- For binary server applications, configure
tikv-jemallocatorormimalloc. - For trusted internal hash keys, prefer
ahashorrustc-hashover default SipHash-based maps. - Use
compact_strorsmol_strfor small-string-heavy paths. - Prefer
beef::Cowoverstd::borrow::Cowwhen minimizing footprint. - Use
bytes::Bytes/bytes::BytesMutfor network buffers; passBytesinstead of cloningVec<u8>. - For critical serialization hot paths, prefer
rkyvorzerocopy; reserveserde_jsonfor config and non-critical APIs.
- Order struct fields from largest to smallest unless stronger semantic grouping is required.
- Use
#[repr(C)]/#[repr(packed)]only for FFI or fixed protocol layout requirements. - Keep error types compact on hot paths; box large error payloads when needed to reduce
Result<T, E>size. - Prefer typestate-style APIs for compile-time state transitions instead of runtime state checks.
- Keep code clean under
clippy::pedantic,clippy::nursery, andclippy::cargo(allowmissing_errors_docfor non-public APIs when needed). - Use
#[inline]for tiny methods called in hot loops or on every request, especially across crate boundaries. - Mark cold error paths with
#[cold]and#[inline(never)]when it improves hot-path instruction locality.
- Keep async tasks non-blocking; offload CPU-bound work to
spawn_blockingorrayon. - Handle errors explicitly and consistently with the
?operator and concrete error types.
- Incomplete implementations: finish features before submitting.
- Large, sweeping changes: keep changes focused and reviewable.
- Mixing unrelated changes: keep one logical change per commit.
- Use
soldeerfor dependencies; do not use git submodules. - Required commands:
forge soldeer installforge soldeer updateforge buildforge test
When fixing failures, identify root cause first, then apply idiomatic fixes instead of suppressing warnings or patching symptoms.
Use outside-in development for behavior changes:
- Git Restrictions: NEVER use
git worktree. All code modifications MUST be made directly on the current branch in the existing working directory. - start with a failing Gherkin scenario under
features/, - drive implementation with failing crate-local unit tests and
proptestproperties in the affected crate, - keep
proptestin the normalcargo testloop instead of creating a separate property-test command, - treat
cargo-fuzzas conditional planning work rather than baseline template setup, - keep
cucumber-rssteps thin and route business rules through shared Rust crates.
After each feature or bug fix, run:
just format
just lint
just test
just bdd
just test-allIf any command fails, report the failure and do not claim completion.
- BDD scenarios: place Gherkin features under
features/and keep the runner in crate-leveltests/withcucumber-rs. - Use BDD to define acceptance behavior first, then use crate-local unit tests and
proptestproperties for the inner TDD loop. - Unit tests: colocate with implementation (
#[cfg(test)]). - Prefer example-based unit tests for named business cases and edge cases, and reserve
proptestfor invariants that should hold across many generated inputs. - Property tests: colocate
proptestcoverage with the crate logic it exercises so it runs through the ordinarycargo testpath. - Benchmarks: only plan or add Criterion when the scope includes an explicit latency SLA, throughput target, or known hot path in a specific crate.
- Benchmark workflow: when benchmarking is justified, add Criterion only in the affected crate instead of pre-seeding benchmark scaffolding across the workspace.
- Fuzz tests: only plan or add
cargo-fuzzwhen a crate parses hostile input, implements protocols, decodes binary formats, or contains meaningfulunsafecode. - Fuzz workflow: when fuzzing is justified, generate the standard layout in the affected crate with
cargo fuzz init, then run targets withcargo fuzz run <target>instead of pre-seeding afuzz/directory in every starter. - For
/pb-planwork, mark benchmarking asconditionalorN/Aunless the scope explicitly includes a performance requirement or hot path, and mark fuzzing asconditionalorN/Aunless the scope explicitly includes parser-like, protocol, binary-decoding, orunsafe-heavy code. - Integration tests: place in crate-level
tests/. - Add tests for behavioral changes and public API changes.
- Documentation, comments, and commit messages must be English only.