- This template targets Rust workspaces only.
bin/contains CLI binary crates.crates/contains reusable library crates.- No frontend/web-framework-specific assumptions.
- Maximize parallelism by dispatching subagents aggressively and consuming tokens freely to complete tasks faster.
- NEVER execute
cargocommands in parallel. Rust's cargo uses strict file locks on thetarget/directory. - ALWAYS run
cargo check,cargo build, orcargo testsequentially. Wait for one to finish before starting the next. - When fixing errors, execute the file
Write/Edittool FIRST, wait for it to succeed, and only THEN runcargocommands to verify. Do not parallelize file edits with cargo builds.
- Ensure
.cargo/config.tomlcontains:This wraps[build] rustc-wrapper = "kache"
rustcwith kache to cache compilation artifacts and significantly speed up incremental builds.
-
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 crates unless compatibility requires a different choice:
clap, config, eyre, proptest, serde, thiserror, tokio, tracing, tracing-subscriber,
tracing-opentelemetry, opentelemetry, opentelemetry-otlp, sqlx, utoipa, utoipa-swagger-ui,
arc-swap, hpx, scc, winnow, shadow-rs, ecdysis
Always use the latest stable version available on crates.io. Run cargo add <crate> --workspace to add dependencies — this automatically resolves to the latest version.
- 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 as many subagents and as much token budget as needed to complete tasks efficiently. Parallelize independent work aggressively and maximize context utilization. Spawn subagents for independent research, code exploration, and implementation tasks to reduce latency and improve throughput.
Use test-driven 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. - 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, - after the inner loop is green, run
just mutation(cargo-mutants) and fix any surviving mutants.
After each feature or bug fix, run:
just format
just lint
just test
just mutationIf any command fails, report the failure and do not claim completion.
- Unit tests: colocate with implementation (
#[cfg(test)]). - Use
cargo testas the TDD inner loop; write a failing test first, then implement the smallest change that makes it pass. - 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. - Cover boundary conditions (empty inputs, zero values, maximum sizes) with explicit assertions.
- Mutation testing: run
just mutation(cargo-mutants) and fix any surviving mutants to keep the mutation score high. - 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.