Backend Python
Python services, APIs and workers with checked types, explicit failures, safe boundaries, consistent data, owned async work and evidenced completion. Rule IDs ENV/TYP/ARC/PY/API/DB/IO/TST/OPS; NEED TO blocks on demonstrated violations.
Set this profile
ccpp cpo profile set backend-pythonInside 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 2
Credentials, keys and personal data stay out of files, logs, commands and the conversation.
api09-sensitive-loggingAPI-09 · Logs and prints should not receive secrets, credentials or whole request payloads
ops02-hardcoded-credentialsOPS-02 · The user confirms credential-named values written as literals, or secret environment reads with a literal fallback
Authentication & authorization 2
Who may do what, from roles, privileges and permissions to CSRF, CORS and verified tokens.
api06-csrf-protectionAPI-06 · The user confirms disabling CSRF protection for cookie-authenticated requests (csrf_exempt, middleware removed, insecure CSRF settings)
py06-assert-for-checksPY-06 · Validation and authorization never rely on assert (removed under python -O)
Untrusted input 8
Requests, downloads and tool output are validated before they reach SQL, a shell, eval or a deserializer.
api01-unvalidated-payloadAPI-01 · Request payload fields should go through a validator before domain use, not be read raw
api04-serialized-fieldsAPI-04 · Serializers and forms list the fields they expose instead of "__all__"
api05-mass-assignmentAPI-05 · The user confirms mapping a raw request payload onto persistent objects (unrestricted ** expansion, __dict__ update, setattr loop)
api07-quoted-placeholdersAPI-07 · Bound-value placeholders are never quoted inside SQL text ('%s')
api07-sql-interpolationAPI-07 · The user confirms SQL built by interpolating values or identifiers into the query text
api08-dangerous-sinksAPI-08 · eval/exec, shell=True, os.system, pickle and unsafe YAML loading need a demonstrated trusted input
api08-untrusted-to-sinkAPI-08 · Request data never reaches eval/exec, a shell, or an unsafe deserializer
typ06-cast-untrusted-inputTYP-06 · A cast or annotation on untrusted input is not validation; parse it at runtime
Network & TLS 2
Outbound data, verified certificates, destinations taken from requests and services exposed to others.
api10-request-controlled-targetAPI-10 · The user confirms outbound URLs, file paths or upload names taken from the request without a visible guard
io08-tls-verificationIO-08 · TLS certificate verification stays on in production code (configure trust roots instead)
Weakened checks 3
Suppressions, disabled lint or CI steps and relaxed strictness need a reason or the user's approval.
env06-weakened-checksENV-06 · The user authorizes tooling changes that add ignores or exclusions, lower strictness or thresholds, narrow test selection or drop a check
tst08-reduced-test-coverageTST-08 · The user confirms new skips and expected failures, and removed test functions
typ04-suppressionsTYP-04 · Type and lint suppressions name the diagnostic and justify the exception; no blanket suppression
Type safety 2
No escapes from the type checker (any, unchecked casts, non-null assertions) and explicit contracts.
typ01-public-annotationsTYP-01 · Public production functions should annotate their parameters and return type (None included)
typ03-new-anyTYP-03 · Any and opaque containers should stay at external boundaries and be narrowed before domain use
Error handling 3
Failures are propagated or handled, never swallowed or turned into fake success.
py04-broad-exceptPY-04 · Broad exception catches should be boundary handlers that keep diagnostics and failure semantics
py05-exception-causePY-05 · An exception translated in a handler keeps the original as its cause (raise … from err)
Async & concurrency 4
Owned tasks, awaited promises, preserved cancellation and no blocking on event loops.
io01-blocking-in-asyncIO-01 · Async functions do not call blocking sleep, HTTP, subprocess or socket APIs on the event-loop thread
io02-unawaited-coroutinesIO-02 · A coroutine created by a statement is awaited or handed to a managed task facility
io03-unowned-tasksIO-03 · Background tasks have an owner that keeps a reference, observes failure and cancels them on shutdown
io04-swallowed-cancellationIO-04 · Async code re-raises CancelledError unless it owns the cancelled task
Performance & resource bounds 6
Timeouts, bounded retries and fan-out, reused clients, closed resources, no N+1 queries.
db06-queries-in-loopsDB-06 · Loops should not issue one ORM query per item where batch loading preserves semantics
io05-missing-timeoutsIO-05 · Outbound calls keep a finite effective timeout (requests and urlopen have none by default; timeout=None disables it)
io06-clients-in-loopsIO-06 · HTTP, database and cloud clients are created once and reused, not inside loops
io07-unclosed-resourcesIO-07 · Files, sockets and streamed responses are closed on every path (context manager) or explicitly handed over
io09-unbounded-retriesIO-09 · Retries are bounded (stop condition, backoff); a loop does not retry a failing operation forever
ops05-unbounded-cachesOPS-05 · In-process caches are bounded and owned (no unbounded @cache, no lru_cache on methods)
Architecture & boundaries 2
Declared layers and dependency directions, no import cycles, small modules, explicit dependencies.
arc01-framework-free-domainARC-01 · Modules the project declared framework-independent import no framework, persistence or transport package at runtime
arc08-import-time-effectsARC-08 · Importing a module should not reach the network, write data or start tasks and processes
Language idioms 4
The conventions of the language that keep code predictable for its readers.
py01-mutable-defaultsPY-01 · Parameters never default to a shared mutable object (list, dict, set, deque…)
py07-finally-control-flowPY-07 · No return, break or continue inside finally (it silently discards the pending exception or return)
py09-wildcard-importsPY-09 · Imports name what they use (no wildcard import outside package re-exports)
py10-naive-datetimesPY-10 · Instants are timezone-aware (no utcnow, utcfromtimestamp or argument-less now)
HTTP & APIs 1
Request and response contracts, schemas, status codes, error bodies and published API surfaces.
ops04-error-details-exposedOPS-04 · Error responses expose a stable safe error, not the raw exception or a traceback
Databases & queries 5
Schemas, queries, transactions and the ORM used as intended.
db01-writes-outside-transactionDB-01 · Several ORM writes in one function run inside one transaction (Django autocommit commits each separately)
db02-side-effect-before-commitDB-02 · Side effects that depend on a write (mail, tasks, events, HTTP) are scheduled after commit
db03-db-error-inside-atomicDB-03 · A database error is not caught and swallowed inside the transaction it broke (use an inner savepoint)
db04-uniqueness-precheckDB-04 · Uniqueness under concurrency is a database constraint; an exists() pre-check before create races
db05-lost-updateDB-05 · Read-modify-write of a persisted counter or balance should be atomic (F() expression, lock or version check)
Schema migrations 5
Migrations come from the tool, applied history stays immutable and risky changes are rolled out safely.
db07-model-without-migrationDB-07 · A persisted model change ends the turn with its migration (Django apps with migrations/, Alembic projects)
db08-edit-applied-migrationDB-08 · The user confirms editing a migration that already existed before this session (applied history)
db08-live-models-in-migrationDB-08 · Migrations use historical models (apps.get_model, op.get_bind), not the application's live models
db09-risky-migration-operationsDB-09 · Destructive, locking or non-null migration operations need a rollout plan (locks, batches, old/new code compatibility)
db10-irreversible-migrationDB-10 · Data migrations declare their reverse, or state that they are irreversible and how to recover
Versions & deprecated APIs 1
Code matches the installed version, without removed, renamed or deprecated APIs.
env05-python-versionENV-05 · New syntax and stdlib APIs stay within the oldest Python version the project declares (requires-python)
Configuration 1
Settings read once at a boundary, validated, with units and without unsafe defaults.
ops01-environment-outside-configOPS-01 · Configuration is read from the environment and validated at one boundary, not across the code
Logging & observability 1
Structured logs, bounded metric labels, no debug prints left in production code.
ops03-debug-leftoversOPS-03 · Production modules carry no debugger traps or diagnostic prints (CLIs and entry points may print)
Dependencies & toolchain 3
Packages change through the package manager, lockfiles stay consistent and the project's tools are used.
env03-undeclared-importsENV-03 · A newly imported third-party package should be declared in the project's dependency manifest
env04-lock-not-updatedENV-04 · Changed dependency declarations end the turn with their lock or compiled constraints updated
ops07-import-fallbacksOPS-07 · An ImportError fallback is tied to a supported version or a declared optional dependency, not invented compatibility
Tests 3
Tests assert behavior, stay deterministic and are not removed or skipped silently.
tst03-tautological-assertionsTST-03 · Test assertions compare behavior with an independent expectation, not a value with itself or a constant
tst05-network-in-unit-testsTST-05 · Unit and contract tests do not reach external hosts; live suites are declared separately
tst07-sleeps-in-testsTST-07 · Tests synchronize on events or control the clock instead of sleeping
Completion evidence 5
A turn ends with its checks run and passing; claims of success need proof after the last edit.
py02-placeholder-implementationPY-02 · Production functions implement reachable behavior instead of pass, Ellipsis or a stub-marked constant
tst10-completion-claimsTST-10 · A final message claiming passing checks needs a successful check after Claude's last edit
tst10-evidence-ledgerTST-10 · Records, per session, Claude's edits and the checks (pytest, type checker, linter) that succeeded after them
turn-baselineRecords the work tree when a prompt starts, the baseline of the end-of-turn checks (TYP-02, DB-07, ENV-04)
typ02-new-type-errorsTYP-02 · Claude does not end a turn with type-checker errors it introduced (unresolved imports, syntax, Optional access, unused coroutines included)