- 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]should use numeric versions only. -
Root
[workspace.dependencies]should 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:
- Avoid
unsafeunless strictly required and documented.
- Avoid
- 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 when appropriate, 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. - Never hold
std::sync::Mutexorparking_lot::Mutexguards across.await. - Use
tokio::sync::Mutexonly when a lock must be held across.await. - Use
tokio::task::spawn_blockingfor CPU-bound work and blocking I/O. - Avoid massive volumes of tiny Tokio tasks; batch work or use bounded worker patterns.
- 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 frequently called methods, especially across crate boundaries. - Mark cold error paths with
#[cold]and#[inline(never)]when it improves hot-path instruction locality.
- Do not block async tasks.
- 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.
After each feature or bug fix, run:
just format
just lint
just testIf any command fails, report the failure and do not claim completion.
- Unit tests: colocate with implementation (
#[cfg(test)]). - 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.