# Coding Conventions These are the rules a contributor needs in their head before touching Vigilar. They are distilled from `CLAUDE.md` and from the patterns already in the codebase. ## Language and style - Python 3.11+. - Ruff for linting. Line length 100 (see `pyproject.toml`). - Type hints on all public functions. Internal helpers may omit them when the types are obvious from context. - No docstrings unless the logic is non-obvious. Short, well-named functions should speak for themselves. ## String constants All string constants referenced in more than one place live in `vigilar/constants.py`. The file uses `StrEnum` for enumerated values — `ArmState`, `Severity`, `EventType`, `SensorType`, `AlertChannel`, `RecordingTrigger`, and friends — and a `Topics` class for MQTT topic builders. If you are about to write `"MOTION_START"` or `"vigilar/camera/..."` in a second place, stop and add it to the appropriate enum or the `Topics` class instead. Defaults like `DEFAULT_IDLE_FPS` also live in this module. ## Database access - SQLite in WAL mode, opened through `vigilar/storage/db.py`. - SQLAlchemy Core expressions only — no mapped classes, no ORM session. - Schema lives in `vigilar/storage/schema.py`. Named query helpers live in `vigilar/storage/queries.py`. - New tables go in `schema.py`. New query helpers go in `queries.py`. Do not scatter ad-hoc SQL across subsystem code. ## Processes and the MQTT bus - Each subsystem runs in its own `multiprocessing.Process`, spawned by the supervisor in `vigilar/main.py` via the `SubsystemProcess` wrapper. Cameras are the exception: `CameraManager` owns one child process per camera directly. - Subsystems communicate only through the local MQTT broker at `127.0.0.1:1883`. No direct imports or function calls across subsystem boundaries. - Topic naming: `vigilar///`. Every topic comes from the `Topics` class in `vigilar/constants.py` — do not construct topic strings ad hoc. - If you are tempted to reach into another subsystem directly, publish a topic instead. ## Configuration - `config/vigilar.toml` is the only config file the app reads at runtime. - It is validated by Pydantic v2 models in `vigilar/config.py`. Add new fields to the Pydantic models, not just to the TOML. - Secrets are file paths, not inline values. Never put a key, password, or token directly in the TOML. ## Testing - `pytest` from the repo root. - Tests live under `tests/`. ## Committing - `ruff check vigilar/` must pass. - `pytest` must pass. - One logical change per commit. Commit often.