Skip to content

Latest commit

 

History

History
115 lines (90 loc) · 4.94 KB

CONTRIBUTING.md

File metadata and controls

115 lines (90 loc) · 4.94 KB

Contributing

Curatarr is a personal project that went public — issues and PRs are welcome, but the maintainer curates changes the same way the app curates media: deliberately.

Dev setup

You need Python 3.12, Git, and a running Ollama with enough VRAM for the configured base models (the LLM features need it; the app degrades gracefully without the optional metadata keys).

git clone https://github.com/Randomname653/Curatarr.git curatarr
cd curatarr
python -m venv venv                  # Windows: py -3.12 -m venv venv
source venv/bin/activate             # Windows: venv\Scripts\activate
pip install -r requirements.txt
python build_models.py               # pulls the base models, builds the curatarr-* tags
python -m uvicorn src.main:app --reload --reload-dir src

Open http://localhost:8000 and the setup wizard writes .env for you. To configure by hand instead, copy .env.example to .env and fill in the Plex and Ollama sections before the first start. On Windows, start.bat does all of the above in one step.

This command listens on 127.0.0.1 only. Developing on a headless machine, a VM or WSL2? Add --host 0.0.0.0 to reach it from another browser, and enter the setup code from its console when the wizard asks.

Backend changes reload the server; the frontend is served as static files, so a browser refresh picks up changes in frontend/.

Tests

No pytest — every suite is a plain script, run with the venv's Python:

python tests/run_all.py          # the whole battery, one suite per CPU (CI runs exactly this)
python tests/run_all.py --serial # one at a time (-j4 / CURATARR_TEST_JOBS=4 to choose)
python tests/test_<name>.py      # one suite
python tests/run_all.py --for wrapup_facts          # every suite that exercises a module
python tests/run_all.py --for wrapup_facts --list   # ...or just name them

The suites from the 2026 audits carry the audit's name (loop_free_g3, fail_closed_s2_g1, silent_failures_r3_*) because the sweep docs cite them as evidence; --for answers "where is this module tested" across them.

No suite touches your data/ or .env: the runner gives each suite its own temp database, vector store and caches, and fails the run if one still writes to data/ (--serial names it). So the battery runs while the app is running.

Policy: new functionality ships with tests for it, and a bug fix ships with the test that would have caught it. New tests follow the stdlib pattern — from _harness import app_db, check as the first import (temp stores; app_db() is the app's own migrated database), check(name, cond) / check.table(...), check.done() at the end — see tests/test_vector_reconcile_live.py. Prefer calling the code over grepping its source: tests/test_source_grep_ratchet.py only lets the number of source-text checks go down. In-memory databases come from _checks.memory_engine() (foreign keys on, loop guard installed), never a bare create_engine("sqlite://"). Wait for a condition with wait_until, not a guessed sleep. Regressions caught live become fixtures.

Dependencies

Two files describe the install:

  • requirements.txt — the direct dependencies, each pinned to one version. Edit this file to change a dependency.
  • lock/requirements.txt — the tested install, generated: every package the pins pull in, with platform markers and the sha256 of every distribution file (uv pip compile --universal --generate-hashes). CI installs it with --require-hashes, and the security scanners and Dependabot read it. Never edit it by hand.

The launchers keep an install in step with both at every start: they install missing or outdated pins, raise any package that fell below the lock (through the same hash check), and let the lock follow a newer version, so they never lower anything. The server itself never installs anything; it reports the comparison in Settings → Maintenance. To reproduce the exact tested set in a fresh environment:

pip install --require-hashes -r lock/requirements.txt

To change a dependency on purpose, bump its version in requirements.txt (or a tool version in lock/requirements-*.in) and regenerate the lock. This needs uv once (pip install uv):

python -m src.deps_lock --compile

That keeps every version the lock already holds and changes only what has to change. To move everything to the newest versions the pins allow, add --upgrade.

Style

  • Comments explain why (constraints, traps, history), not what the next line does — match the density you see around your change.
  • UI/app knowledge lives in src/services/app_context.py blocks, never inline in routers (tests/test_app_context_drift.py enforces it).
  • Frontend: design tokens/classes only, amber is the accent — rules live in the header of frontend/css/app.css.

License

Contributions are accepted under the project license (AGPL-3.0). Ported third-party code keeps its origin — see THIRD_PARTY_LICENSES.md.