Backend Rust
Rust services, APIs and workers (Tokio, axum, tower, SQLx) with declared boundaries, explicit failures, owned async work, bounded resources, safe inputs and evidenced completion. Rule IDs ARC/TYP/ERR/ASY/API/DB/OPS/QLT; NEED TO blocks on demonstrated violations.
Set this profile
ccpp cpo profile set backend-rustInside Claude Code, prefix the command with ! to run it in the session. Downloading a profile needs a Builder or Team plan; listing them does not.
Policies
63 policies, grouped by what they guard.
Secrets & private data 4
Credentials, keys and personal data stay out of files, logs, commands and the conversation.
rs-ops05-sensitive-loggingOPS-05 · Secrets and credentials do not reach logs, spans or Debug output (no logged secrets, no derived Debug on secret fields, instrument skips them)
rs-ops10-hardcoded-credentialsOPS-10 · The user confirms credential-named values written as literals or used as fallbacks for secret environment reads
rs-typ07-derived-config-defaultsTYP-07 · Settings types holding credentials or connection strings do not derive Default (an empty secret is not a configuration)
rs-typ07-fabricated-defaultsTYP-07 · Default implementations do not fabricate credentials, connection strings or identities
Authentication & authorization 2
Who may do what, from roles, privileges and permissions to CSRF, CORS and verified tokens.
rs-api04-unverified-tokensAPI-04 · Tokens are verified before they authenticate (no disabled signature or expiry validation, no insecure decode)
rs-api05-routes-after-auth-layerAPI-05 · Routes added after an authentication layer in an axum Router chain are intentionally unprotected
Untrusted input 2
Requests, downloads and tool output are validated before they reach SQL, a shell, eval or a deserializer.
rs-api07-client-controlled-fieldsAPI-07 · Request payload types do not let clients set server-owned fields (roles, ownership, tenant, verification state)
rs-db01-sql-formattingDB-01/DB-02 · The user confirms SQL text built with format!, concatenation or QueryBuilder::push of non-literal values
Network & TLS 1
Outbound data, verified certificates, destinations taken from requests and services exposed to others.
rs-ops09-tls-verificationOPS-09 · Outbound TLS keeps certificate and hostname verification (no danger_accept_invalid_*, no custom no-op verifier)
Weakened checks 3
Suppressions, disabled lint or CI steps and relaxed strictness need a reason or the user's approval.
rs-qlt06-blanket-suppressionsQLT-06 · No blanket or crate-wide lint suppression (allow(warnings), clippy::all, unsafe_code, inner
rs-qlt06-unexplained-allowsQLT-06/QLT-08 · Item-level lint suppressions name their reason (#[expect(lint, reason = "…")]), dead code included
rs-qlt10-weakened-checksQLT-10 · The user authorizes lint, test or CI configuration changes that allow lints, skip checks or ignore failures
Type safety 5
No escapes from the type checker (any, unchecked casts, non-null assertions) and explicit contracts.
rs-qlt06-unsafe-without-safetyQLT-06 · unsafe blocks, unsafe impls and unsafe fns state their safety obligation (// SAFETY:,
rs-typ02-optional-requiredTYP-02 · A function that needs a value takes it, instead of an Option it silently ignores when None
rs-typ03-boolean-modesTYP-03 · Functions do not take several boolean flags that encode modes; use an enum or a configuration type
rs-typ05-borrowed-owned-containersTYP-05 · Read-only parameters borrow slices, str or Path, not &Vec, &String, &PathBuf or &Box
rs-typ06-cloning-gettersTYP-06 · Getters return a borrow instead of cloning an owned field on every call
Error handling 8
Failures are propagated or handled, never swallowed or turned into fake success.
rs-err01-panics-in-handlersERR-01 · Request handlers return failures instead of panicking (unwrap, expect, panic!) on request-derived values
rs-err01-unwrap-on-inputERR-01 · Parsing, decoding and conversions of external data outside startup return errors instead of unwrap/expect
rs-err02-discarded-okERR-02 · A fallible result is not erased with a bare `.ok();` statement
rs-err02-discarded-results-typedERR-02 · A Result or future bound to `let _` is a justified discard (type from rust-analyzer)
rs-err03-failure-as-successERR-03 · A catch-all Err arm does not report success with an empty, default or true value
rs-err03-silent-fallbacksERR-03 · Errors replaced by a default value (unwrap_or_else(|_| …), .ok().unwrap_or…, Err(_) => default) are a specified fallback
rs-err04-error-text-branchingERR-04 · Callers branch on typed error variants, not on the text of an error's Display
rs-err06-fallible-middlewareERR-06 · Fallible tower middleware (timeout, load_shed, buffer) is paired with an error handler that turns its errors into responses
Async & concurrency 6
Owned tasks, awaited promises, preserved cancellation and no blocking on event loops.
rs-asy01-blocking-in-asyncASY-01 · Async code does not call blocking sleep, file, socket, process or block_on APIs on executor workers
rs-asy03-guard-across-awaitASY-03 · A synchronous lock guard (std or parking_lot) is released before the next .await in the same scope
rs-asy04-async-mutex-without-awaitASY-04 · An async mutex guard that never spans an .await should be a short synchronous critical section
rs-asy07-detached-tasksASY-07 · A spawned task has a lifecycle owner that observes its result and stops it on shutdown (no dropped JoinHandle)
rs-asy08-cancellation-safetyASY-08 · select! branches and timeouts do not cancel operations that are not cancellation-safe (partial reads/writes, commits, executes)
rs-asy09-blocking-timeoutsASY-09 · A timeout or select! around spawn_blocking accounts for the blocking work that keeps running
Performance & resource bounds 7
Timeouts, bounded retries and fan-out, reused clients, closed resources, no N+1 queries.
rs-asy05-unbounded-queuesASY-05 · The user confirms unbounded channels, which need a demonstrated finite producer and an overload policy
rs-asy06-unbounded-fan-outASY-06 · Tasks and futures created per item of a loop or iterator have an admission limit (semaphore, buffer_unordered, JoinSet cap)
rs-asy11-unbounded-retriesASY-11 · Retry loops have a bound (attempts or elapsed budget), a delay, and stop on terminal errors
rs-db05-pools-per-requestDB-05 · Pools and HTTP/database clients are built at startup and shared, not per request or per loop iteration
rs-db06-unbounded-fetch-allDB-06 · fetch_all over a SELECT has a result bound (LIMIT, a key filter, pagination)
rs-db09-queries-in-loopsDB-09 · Request-driven loops do not issue one database query per item (N+1); batch or join instead
rs-ops03-client-timeoutsOPS-03 · Outbound HTTP clients have a deadline (reqwest/ureq builders with timeout, no bare Client::new or reqwest::get)
Architecture & boundaries 2
Declared layers and dependency directions, no import cycles, small modules, explicit dependencies.
rs-arc01-dependency-mapARC-01 · use paths and Cargo dependencies respect the project's declared dependency map (off until dependencyRules is set)
rs-arc02-io-in-domainARC-02 · Designated domain components do not reach transport, persistence, filesystem or environment APIs (off until domainPaths is set)
HTTP & APIs 3
Request and response contracts, schemas, status codes, error bodies and published API surfaces.
rs-api03-body-limitsAPI-03 · The user confirms removing or bypassing request body limits (DefaultBodyLimit::disable, to_bytes with usize::MAX, unlimited payload configs)
rs-asy10-graceful-shutdownASY-10 · A server stops admission and drains in-flight work on shutdown (axum/hyper serve with graceful shutdown)
rs-err05-error-details-exposedERR-05 · Internal failures map to stable public errors; 500 responses do not carry the error's text or Debug output
Databases & queries 3
Schemas, queries, transactions and the ORM used as intended.
rs-db03-writes-outside-transactionDB-03 · Several writes in one operation run in one transaction and report success after commit
rs-db04-uncommitted-transactionsDB-04 · A transaction that is begun is committed (or deliberately rolled back or handed on), never silently dropped on success
rs-db07-remote-io-in-transactionDB-07 · Outbound network calls do not run while a transaction holds a pooled connection
Schema migrations 2
Migrations come from the tool, applied history stays immutable and risky changes are rolled out safely.
rs-db08-edit-applied-migrationDB-08 · The user confirms editing a migration that already existed before this session (applied history)
rs-db08-schema-without-migrationDB-08 · A change to persisted Rust models (Diesel table!, SeaORM entities, FromRow/Queryable structs) ends the turn with a new migration
Configuration 3
Settings read once at a boundary, validated, with units and without unsafe defaults.
rs-ops01-config-fallbacksOPS-01 · Environment reads do not fall back to a default for required settings (unwrap_or, unwrap_or_default, unwrap_or_else)
rs-ops01-environment-outside-configOPS-01 · Configuration is read from the environment and validated once into typed settings, not across the code
rs-ops02-unitless-durationsOPS-02 · Time settings in configuration types carry a unit (Duration, or an explicit _ms/_secs suffix)
Logging & observability 2
Structured logs, bounded metric labels, no debug prints left in production code.
rs-ops04-unstructured-logsOPS-04 · Production code logs through tracing with structured fields, not println!/eprintln! or values interpolated into the message
rs-ops06-unbounded-metric-labelsOPS-06 · Metric labels have a bounded value set (no user/request IDs, raw paths or error text as labels)
Dependencies & toolchain 1
Packages change through the package manager, lockfiles stay consistent and the project's tools are used.
rs-arc08-dependency-changesARC-08 · New Cargo dependencies and features name their capability, enable only needed features and pin git sources
Tests 4
Tests assert behavior, stay deterministic and are not removed or skipped silently.
rs-qlt01-test-assertionsQLT-01 · Tests check an outcome (assert, expected error, unwrap of the result under test), not just run code
rs-qlt03-test-timingQLT-03 · Tests control time and synchronization instead of sleeping on the real clock
rs-qlt10-reduced-testsQLT-10 · The user confirms new
rs-qlt10-snapshot-updatesQLT-10 · The user confirms changes to existing approved snapshots (insta .snap files)
Completion evidence 5
A turn ends with its checks run and passing; claims of success need proof after the last edit.
rs-qlt05-placeholdersQLT-05 · Production code ships no todo!(), unimplemented!() or dbg!() placeholders
rs-qlt07-completion-claimsQLT-07 · A final message claiming a passing build, lint or tests needs a successful cargo run after Claude's last edit
rs-qlt07-evidence-ledgerQLT-07 · Records, per session, Claude's edits and the cargo build, lint or test runs that succeeded after them
rs-qlt07-new-compile-errorsQLT-07 · Claude does not end a turn with compiler errors it introduced in Rust sources or their dependents (rust-analyzer)
rs-turn-baselineRecords the work tree when a prompt starts, the baseline of the end-of-turn checks (QLT-07, DB-08)