These apply to every task without exception:
- License headers: Use the current year (e.g.,
Copyright (C) 2026 Recidiviz, Inc.) in new Python file headers. Look at recently created files for the correct format. - No test imports in production: Never import from
recidiviz/tests/outside ofrecidiviz/tests/. Test utilities and constants must stay in test code. - No obvious comments: Don't add inline comments that explain things obvious from reading the code, or that are only meaningful in the current conversation context.
- TODO format: Reference GitHub issues as
TODO(#12345)and Linear issues asTODO(OBT-12345)(any Linear team prefix works, e.g.TODO(TN-12345)— use the ticket's own team, don't convert it to OBT). The org has moved to Linear for issue tracking so use Linear ticket number if you have it. UseTODO(XXXX)as a placeholder before filing. This fails lint, forcing the task to be filed before merging. A closed issue doesn't necessarily mean the TODO was addressed. - Data privacy: Never access data from Maine (
US_ME) or California (US_CA). If a query might touch this data, flag it to the user and confirm before running. - US_ID vs US_IX: Idaho uses two state codes (
US_IDandUS_IX) that historically shared the same codebase and data infrastructure. If working in Idaho-related code, confirm with the user which state code applies before proceeding. - Worktree naming: Name worktrees
<us_xx>_<feature_name>(e.g.us_nc_location_metadata), prepending the state code of the state the work relates to. If the work spans multiple states or isn't state-specific, be flexible — just use a descriptive<feature_name>. - GitHub CLI: Use
ghfor all GitHub operations (PRs, issues, etc.) — it has authenticated access to the private repo. - Python style: Follow the Python style rules in
.claude/rules/python-style.md(loaded below) whenever writing or modifying Python. - SQL style: Before writing SQL, or code in any language that generates SQL, read the SQL style rules in
.claude/rules/sql-style.md.
- Use Python 3.11 with uv for dependency management
- First time setup:
./initial_setup.sh - Manual sync:
uv sync --all-extrasormake uv-sync - Run commands with:
uv run <cmd> - Activate environment:
source .venv/bin/activateormake uv-shell - Common tasks available via Makefile:
make help
Tests live in recidiviz/tests/ and mirror the source path. For example,
recidiviz/big_query/big_query_view.py is tested in
recidiviz/tests/big_query/big_query_view.py.
- Run a specific test file:
uv run pytest recidiviz/tests/path/to/test_file.py - Run all tests:
uv run pytest recidiviz(slow — normally handled by CI) - Test configuration in
setup.cfgwith coverage settings
- Lint:
make pylint(runs differential pylint on changed files; requires code to be committed, i.e. HEAD != main) - Type checking:
uv run mypy recidiviz/path/to/changed/file.py(run on specific files; full-repo mypy is slow) - Security checking:
uv run bandit(configured in.bandit) - Auto-formatting:
blackandisortrun automatically via pre-commit hooks
- Build dev image:
make docker-build-dev - Admin panel:
make docker-admin
The BigQuery (BQ) MCP server allows querying actual data. If no BQ MCP server
is configured locally, use the bq CLI.
See the Data privacy rule above — never query ME or CA data.
recidiviz/- Main package with domain-specific modules:admin_panel/- Administrative web interfaceaggregated_metrics/- BQ view generation framework for aggregated metrics viewsairflow/- Apache Airflow logic for orchestration deployed in Google Cloud Composercalculator/- Stores query logic for many (but not all) BQ viewscase_triage/- Case triage and pathways functionalitydocuments/- Document storage and LLM-based extractioningest/- Data ingestion configuration for different states/sourcespersistence/- Database schemas, entities, and data accesspipelines/- Apache Beam data processing pipelines (see Pipelines Documentation)ingest/- Ingest pipelinesactivity/- Activity ingest pipelineidentity/- Identity ingest pipeline
metrics/- Metric computation pipelinessupplemental/- State-specific supplemental dataset pipelines
tools/- Scripts for local, CI, or Cloud Build usevalidation/- Framework for validation and quality checksworkflows/- Workflow orchestration and ETL
- SQLAlchemy for database ORM (version pinned <2.0.0)
- Apache Beam for data processing pipelines
- Flask for web applications with Flask-SQLAlchemy-Session
- Google Cloud Platform integration throughout
- State-specific ingest configurations in
recidiviz/ingest/direct/regions/
- Environment-specific settings managed via
recidiviz/utils/environment.py - Database migrations handled by Alembic
- Pre-commit hooks configured for code quality enforcement
States are abbreviated as US_XX. US_OZ is the playground/demo state — it
has a real region directory and is not a unit-test placeholder. In unit tests,
use the fake codes (US_XX, US_YY, US_WW) when testing generic
functionality.
Make references clickable. In chat, whenever you mention something the user might want to look up — a file, class, function, variable, BQ view, PR, issue, or commit — print it as a markdown link, not bare text, so the user can Cmd-click the link to open it directly.
- Local code:
[name](vscode://file/{absolute path}:{line}). Include line when you know it. Link to the specific class/function definition, not just the file. If the user specifies a different IDE and URL scheme, use that instead. - GitHub: link PR numbers, issue numbers, and commit hashes to their github.com URLs.
- Ingest Process
- Pipelines
- BigQuery Tooling
- Document Extraction
- Task Eligibility Spans
- Deploy Tooling and Versioning
- Research Notebooks
Skills are invocable workflows. Repo-local ones are documented in
.claude/skills/[skill_name]/SKILL.md. Others are installed as plugins from the
shared Recidiviz/claude-skills
marketplace, declared under extraKnownMarketplaces and enabledPlugins in
.claude/settings.json. Either way, available skills are listed in the system
prompt at session start.
The enabledPlugins declaration does not install anything. It only
activates a plugin that is already installed on your machine. Each developer
must install each declared plugin once per machine:
claude plugin install <name>@recidiviz --scope project
If a declared plugin is not installed, its skills and hooks silently do not load. A session-start hook in this repo checks for this and prints the install command for any plugin that is missing.
create-pr and review-pr-comments come from the shared marketplace and are
invoked with a plugin-namespaced name — /create-pr:create-pr, not /create-pr.
To opt out of one locally, set it to false under enabledPlugins in
.claude/settings.local.json. To install other shared skills just for yourself,
run claude plugin install <name>@recidiviz.
Python style conventions that apply whenever writing or modifying Python code in this repository:
- @.claude/rules/python-style.md
Security patterns and anti-patterns that apply to all code in this repository:
- @.claude/rules/security.md
Each developer can maintain a personal local settings file at
.claude/pulse-data-local-settings.md. This file is gitignored and never
checked in. Use it for personal preferences, local paths, or any
machine-specific context you want Claude to have.
- @.claude/pulse-data-local-settings.md