Skip to content

Commands Cheatsheet

Taskfile.yaml only keeps targets that compose multiple commands, inject environment variables, or encode a non-obvious default. Everything else is a direct call into a third-party CLI — listed below so a forker can run the underlying command without learning a Task target that merely renamed it.

All uv run commands assume you are at the repo root.

Linting + formatting

uv run ruff check .                  # lint
uv run ruff check . --fix            # lint + auto-fix
uv run ruff format .                 # format in place
uv run ruff format --check .         # format check (no write)
uv run mypy . --ignore-missing-imports

task ci composes all four gates plus pytest + secret scan.

Testing

uv run pytest                        # full suite
uv run pytest -m unit                # unit tests only
uv run pytest -m integration         # integration tests
uv run pytest -m e2e                 # end-to-end tests
uv run pytest --cov=. --cov-report=html

Test markers are defined in pyproject.toml under [tool.pytest.ini_options].

Agent evaluations

task eval:agent

This runs the deterministic DeepEval suite at tests/evals/test_birding_trip_copilot_deepeval.py. The target opts out of DeepEval telemetry, keeps the cache under the ignored .cache/ tree, disables browser opening, and sets PYTEST_ADDOPTS=--no-cov so the focused eval run is not affected by the repository-wide coverage gate. It uses a fake model client and makes no live Cloudflare request.

Opt in to one live credential/model check with:

task smoke:cloudflare-ai

The smoke command uses only @cf/zai-org/glm-5.2 and never prints Cloudflare credentials.

Rufous local birding app

task app:dev           # FastAPI :8000 + Vite :5173 with hot reload
task app:check         # typecheck + tests + build + configured bundle audit
task app:audit-bundle  # audit an existing build for configured names and values
task app               # build and serve the complete app at http://127.0.0.1:8000

Both launch paths bind to loopback. Run task verify first to populate the local warehouse. Rufous uses an original local rust-orange/teal field-device theme with no remote fonts or theme assets. The Trip Planner remains at /; the read-only Arizona Birds catalog is available at /birds, with direct modeled profiles at /birds/{species_code}. Native browser history supports direct reload, back, and forward without a routing dependency. Catalog search, species/hybrid filtering, and 24-row pagination operate entirely on the bounded 706-row API snapshot; profile pages use only persisted modeled facts and public Arizona locations, with no request-time discovery or mutation. A public modeled location whose name includes (private) is shown with an access-restriction warning; eBird's modeled privacy flag, not the display-name suffix, governs observation privacy. The private local collection UI is available at /my-birds with Life List, Observations, and Watches surfaces. Species profiles expose only explicit observation and watch mutations. Watch centers are per-watch Arizona selections; the browser stores no global home location, and none of these controls evaluate matches or trigger weather, model, calendar, or SMTP work.

Catalog photo/call metadata is populated only by an explicit local batch. Inspection is read-only and performs no discovery:

uv run --no-sync python scripts/catalog_media.py --inspect

Before apply, check Xeno-canto readiness without printing the credential value:

uv run --no-sync python scripts/catalog_media.py --check-prerequisites
# {"xeno_canto_api_key_configured": true}

Apply and refresh fail before creating tables or rows when XENO_CANTO_API_KEY is absent. After independent review, run one bounded sequential checkpoint while the API, Quack, and SQLMesh writers are stopped:

uv run --no-sync python scripts/catalog_media.py --apply --batch-size 25
uv run --no-sync python scripts/catalog_media.py --refresh --batch-size 25

Apply resumes missing exact identities; refresh resumes one explicit refresh campaign. Neither command stores media bytes. Catalog GETs never invoke these commands or media providers and return typed unavailable metadata until enrichment is complete.

The local personal-collection API stores runtime-owned tables in birding_personal inside the same DuckDB file. It exposes observation CRUD at /api/observations, the derived /api/life-list, per-species /api/watches, and /api/birds/{species_code}/collection-state. Observation deletion requires confirm=true; life-list membership is never an independent stored flag. Collection reads are network-free, and collection mutations do not evaluate watches or call weather, models, calendar, or SMTP.

Each current bird profile links to /birds/{species_code}/find. Target planning requires an Arizona origin, 1–300-mile radius, local start, and 1–1440-minute duration. POST /api/target-plans ranks at most ten exact-species valid, reviewed, non-private public eBird locations with Haversine distance, then calls Open-Meteo and the sole strict-schema GLM 5.2 model before atomically persisting the result. GET /api/target-plans and GET /api/target-plans/{id} replay only persisted facts without network access or writes. Direct result routes use /target-plans/{id}. Target plans never read personal collection state or change the existing Trip Planner.

The shared full-refresh path evaluates active watches only after all source loads and SQLMesh transformation succeed and release warehouse ownership. Evaluation uses exact species/submission identity, the watch activation boundary, a 48-hour freshness window, reviewed valid non-private public locations, and the per-watch 1–300-mile radius. It persists deterministic decisions, at most ten ranked public clusters, the earliest sunrise-centered two-hour morning, optional strict-schema GLM 5.2 emphasis, and stable-UID event intent in birding_alerts. The GLM prompt contains only target identity, the confirmed public destination and derived distance, morning, weather, caveats, and fact grounding—never the personal watch-center name or coordinates. Model/weather failure degrades to explicit persisted facts; it does not select an alternate model or send SMTP. Cancellation handoffs become a cancel intent only for the same accepted, unexpired watch activation. GET /api/watch-evaluations, GET /api/watch-reports, and GET /api/watch-reports/{id} replay bounded local state without network access or writes.

Every sendable REQUEST/CANCEL event intent now atomically creates one canonical birding_alerts.alert_outbox row keyed by stable UID, sequence, and method. Only exact pending_request/REQUEST and pending_cancel/CANCEL pairs qualify; event/report species, watch activation, windows, horizon, and coherent public location identity/metadata must match before enqueue. Pre-release intent tables are transactionally rebuilt with explicit source-report/location linkage, and an unrecoverable sendable row fails rather than being guessed. Persisted payload JSON contains only validated calendar facts and its SHA-256; organizer, recipient, SMTP configuration, MIME bytes, and full message bodies are never stored. Pure builders add organizer/attendee only in memory and produce RFC 5545/5546 calendar plus deterministic multipart calendar MIME. Atomic claims, pre-send lease recovery, post-send delivery_unknown, supersession, terminal suppression, append-only safe attempt facts, and 90-day payload cleanup are local state mechanics only. No command in this slice opens an SMTP socket, schedules a retry, or sends email; transport and operator actions remain the next ticket.

Trip Planner eBird evidence is independently constrained in its SQLMesh view and Python lookup to valid, reviewed, non-private rows. To inspect or remediate saved plans created before that boundary, stop the API and refresh writers and run:

uv run --no-sync python scripts/remediate_trip_planner_ebird_privacy.py --inspect
uv run --no-sync python scripts/remediate_trip_planner_ebird_privacy.py --apply

The inspect command is read-only and emits aggregate counts only. Apply performs no source, weather, model, or media call; it atomically removes every complete saved-plan aggregate joined by authoritative eBird source-record identity to an ineligible row. It fails closed when an identity cannot be verified and is safe to rerun.

The browser calls /api/*; only the Python process can access DuckDB or Cloudflare credentials. After any standalone build, the copy-pasteable task app:audit-bundle command checks the compiled files for all configured Cloudflare variable names and non-empty local values without printing secrets.

Location autocomplete calls Open-Meteo geocoding through the local Python API; the browser never calls the upstream service directly. Search results and manual coordinates are restricted with a compact official US Census TIGERweb-derived Arizona polygon because the current bird evidence is Arizona-scoped. A missing negative longitude such as 34.54,112.50 is rejected before weather, evidence, model, or persistence work; valid Arizona coordinates such as 34.54,-112.50 remain available when geocoding is unavailable. Selected location identity and all completed plan artifacts persist in the single local data/databox.duckdb warehouse.

GBIF planner evidence is conformed to the eBird-first species dimension by an authority-free scientific-name key, so available common names lead result cards while the scientific name remains visible underneath. Open-Meteo measurements are reloaded from the persisted trip-plan evidence payload and displayed in both US customary and metric units; the browser does not refetch or ask the model to convert weather values.

Xeno-canto metadata, URLs, recordist attribution, and licenses are reloaded from persisted DuckDB evidence. The API exposes a separate typed media projection and activates source/audio URLs only for exact HTTPS Xeno-canto hosts, matching recording IDs, and expected /{id} or /{id}/download paths. The React app uses native audio controls with preload="none" and no autoplay. Audio bytes stream directly from Xeno-canto only after user interaction; Rufous does not proxy, download, cache, or store audio.

Existing persisted recommendations are enriched only by an explicit local maintenance command. Stop source refresh and the local API writer first, inspect the bounded target set, then apply once:

task media:backfill -- --dry-run
task media:backfill -- --apply

Dry-run opens data/databox.duckdb read-only and performs no discovery. Apply uses DuckDB's single-writer transaction and the same validated GBIF/Xeno-canto selector used for new plans. It inserts only missing photo/call JSON metadata, including durable unavailable results; a one-time compatibility repair replaces only exact media_backfill_v2_ GBIF rows having the defective unavailable status and caveat from before the reviewed HTTP-license and United States of America normalization fix. It does not invoke the model, alter plan content, or download/proxy media bytes. Re-running apply is a no-op after every recommendation has one current photo and one call result. --database-path may target a test copy; it does not create a missing database.

Bird alert delivery operations

Bird-alert email is never sent by app startup, GET requests, watch changes, or tests. These explicit commands use generic SMTP and print bounded states only—never host, port, identities, certificate paths, or credentials.

# Validate loopback, exact public-certificate trust, STARTTLS hostname
# verification, and Bridge-generated authentication without sending.
uv run --no-sync python scripts/verify_bird_alert_smtp.py --preflight

# Deliver at most one due persisted outbox row.
uv run --no-sync python scripts/deliver_bird_alerts.py

# Bounded live verification; each kind is durably limited to one attempt.
uv run --no-sync python scripts/verify_bird_alert_smtp.py --test-email
uv run --no-sync python scripts/verify_bird_alert_smtp.py --test-invitation

My Birds → Alert Delivery shows safe local status and only state-derived actions. Active ambiguous results can be marked not delivered and retried with a greater sequence; suppressed/inactive ambiguous results can only be terminally marked not delivered, without retry, or marked delivered so Rufous enqueues a coherent cancellation. Ambiguous results are never automatically resent. SMTP acceptance means accepted by the local Bridge, not proof of inbox receipt or calendar rendering. Resolved history expires after 90 days; unresolved ambiguous rows remain until reconciliation.

SQLMesh

Run from transforms/main/ — SQLMesh picks up config.py there. Logs land in .logs/sqlmesh/ via the local transforms/main/logs symlink (gitignored; created by task install).

cd transforms/main
uv run sqlmesh plan --auto-apply     # plan + apply changes
uv run sqlmesh run                   # run scheduled models
uv run sqlmesh test                  # run SQLMesh unit tests
uv run sqlmesh ui                    # start SQLMesh UI
uv run sqlmesh plan dev              # plan into dev env

Dagster (beyond dagster:dev / full-refresh / verify)

export DAGSTER_HOME="$PWD/.dagster"
export PYTHONPATH="$PWD"

uv run dagster asset materialize --select <key> \
  -f packages/databox/databox/orchestration/definitions.py

uv run dagster asset wipe --all \
  -f packages/databox/databox/orchestration/definitions.py

Pre-commit

uv run pre-commit run --all-files    # run every hook across every file
uv run pre-commit run ruff           # run one hook

Secret scan

python scripts/check_secrets.py      # scan repo root
python scripts/check_secrets.py path/to/file.py

Source layout + staging codegen

python scripts/check_source_layout.py        # lint per-source directory layout
python scripts/generate_staging.py           # regenerate trivial-rename stg_* SQL
python scripts/generate_staging.py --check   # fail on drift (also runs in task ci)

Watching

Task's built-in watch mode works without a dedicated target:

task -w ci                           # re-run ci on file change