From aeb51b3f509fd20b1824c3d4471a8b4af91db8b1 Mon Sep 17 00:00:00 2001 From: oleost <5670710+oleost@users.noreply.github.com> Date: Sat, 10 Oct 2026 17:06:07 +0200 Subject: [PATCH 01/28] Keep the beta channel config on beta after merging 0.8.0 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0126B6HCdwnvuVrRkMeMEXfo --- visionstate/config.yaml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/visionstate/config.yaml b/visionstate/config.yaml index 3c754f1..ccf9e20 100644 --- a/visionstate/config.yaml +++ b/visionstate/config.yaml @@ -1,5 +1,5 @@ -name: VisionState -version: "0.8.0" +name: VisionState (beta) +version: "0.7.1b6" slug: visionstate description: Teach a local AI to recognise states (open, closed, …), find objects (people, cars, pets) or read numbers in your camera images url: https://github.com/oleost/VisionState @@ -13,7 +13,7 @@ arch: ingress: true ingress_port: 8099 panel_icon: mdi:eye-check-outline -panel_title: VisionState +panel_title: VisionState β homeassistant_api: true hassio_api: true services: @@ -34,3 +34,5 @@ schema: mqtt_port: port? mqtt_username: str? mqtt_password: password? +environment: + VISIONSTATE_MEDIA: /media/visionstate_beta From e18d905fb8ace791d476f83e69da82f9ae16c081 Mon Sep 17 00:00:00 2001 From: oleost <5670710+oleost@users.noreply.github.com> Date: Sat, 10 Oct 2026 17:28:41 +0200 Subject: [PATCH 02/28] Docs: one home per fact, a test that keeps them true to the code - CLAUDE.md says where each kind of fact is written down; release steps move to docs/RELEASING.md, how to run it locally moves from README.md to CLAUDE.md, the code map in CLAUDE.md to ARCHITECTURE.md. - SCOPE.md: no version stamp; kinds, wizard, schema and reading fields corrected; repository layout, tech stack, identity and channels moved out (ARCHITECTURE.md, RELEASING.md); roadmap in order. - Wheel reader results live in tools/wheelreader/README.md; WHEEL_READER_PLAN.md gets a status column and B1 marked done. - README.md: the entity list lives in DOCS.md; development points to CLAUDE.md. - DOCS.md and the store text: object count, wheel reader and feedback wording updated. - tests/test_docs.py checks every link, repository path, code name and `setting` (value) in the docs. - SECURITY.md and issue forms (bug report; questions, ideas and shared readings go to Discussions). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0126B6HCdwnvuVrRkMeMEXfo --- .github/ISSUE_TEMPLATE/bug_report.yml | 45 ++++ .github/ISSUE_TEMPLATE/config.yml | 8 + CLAUDE.md | 345 ++++++++++--------------- README.md | 75 +----- SECURITY.md | 11 + docs/ARCHITECTURE.md | 33 ++- docs/RELEASING.md | 113 ++++++++ docs/SCOPE.md | 146 +++-------- docs/WHEEL_READER_PLAN.md | 85 +++--- tools/wheelreader/README.md | 13 +- visionstate/DOCS.md | 16 +- visionstate/README.md | 6 +- visionstate/backend/tests/test_docs.py | 155 +++++++++++ 13 files changed, 610 insertions(+), 441 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 SECURITY.md create mode 100644 docs/RELEASING.md create mode 100644 visionstate/backend/tests/test_docs.py diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..1690e17 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,45 @@ +name: Bug report +description: Something does not work as described in the documentation +labels: [bug] +body: + - type: markdown + attributes: + value: | + Thanks for reporting! Remove camera addresses and passwords from anything you paste. + - type: input + id: version + attributes: + label: VisionState version + description: Settings → Apps → VisionState (or VisionState (beta)) + placeholder: "0.8.0" + validations: + required: true + - type: dropdown + id: kind + attributes: + label: Sensor kind + options: + - State sensor + - Object sensor + - Reading sensor + - Not about one sensor + validations: + required: true + - type: input + id: system + attributes: + label: Home Assistant version and hardware + placeholder: "2026.10.0, Raspberry Pi 4 / Intel NUC / Proxmox VM" + - type: textarea + id: what + attributes: + label: What happened, and what did you expect? + description: Steps to see it again help a lot. A screenshot is welcome. + validations: + required: true + - type: textarea + id: log + attributes: + label: Log + description: The app's Log tab, around the time it happened. + render: text diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..3f91377 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: Questions, ideas and shared meter readings + url: https://github.com/oleost/VisionState/discussions + about: Ask, suggest a feature, or share an export of readings (Quality tab → Export readings) to help improve reading. + - name: Security vulnerability + url: https://github.com/oleost/VisionState/security/advisories/new + about: Report it privately, not as an issue. diff --git a/CLAUDE.md b/CLAUDE.md index 66ca9fe..47a6613 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,13 +3,39 @@ VisionState — a Home Assistant app that turns camera images into sensors, all locally: **states** the user teaches it (garage door open/closed; embedding model + small per-sensor classifier), **objects** found by a pretrained detector (people, cars, animals) and **readings** -(a number on a display, OCR). This file is the contributor guide for people and AI assistants. +(a number on a display or the wheels of a meter). This file is the contributor guide for people +and AI assistants. -- **Source of truth for scope and design decisions:** [`docs/SCOPE.md`](docs/SCOPE.md). - Update it when a decision changes. -- **Language:** everything in the repository (code, comments, UI text, docs, commit - messages, this file) is written in English. -- Public repository `github.com/oleost/VisionState`, Apache-2.0. Pull requests go to `beta`. +- **Language:** everything in the repository (code, comments, UI text, docs, commit messages) is + written in English. +- Public repository `github.com/oleost/VisionState`, Apache-2.0. Pull requests go to `beta`; + releases and branches: [`docs/RELEASING.md`](docs/RELEASING.md). + +## Where things are written down + +Every fact has **one** home; other files link to it instead of repeating it. + +| What | Home | +|---|---| +| What the app does for a user, how to use it, the defaults a user sees | [`visionstate/DOCS.md`](visionstate/DOCS.md) (the app's *Documentation* tab) | +| The pitch, install, screenshots | [`README.md`](README.md) (and the short store text `visionstate/README.md`) | +| Design decisions and why, non-goals, roadmap, open ideas | [`docs/SCOPE.md`](docs/SCOPE.md) | +| Where the code is, how a check flows, data on disk, recipes for common changes | [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | +| Values of defaults, limits and tunables | `settings.py` and the model registries — docs name the setting, not its value (DOCS.md may state what the user sees) | +| Branches, channels, CI, release steps | [`docs/RELEASING.md`](docs/RELEASING.md) | +| How to work: principles, checks, testing, pitfalls | this file | +| The wheel reader model: data, licences, results, how to train it | [`tools/wheelreader/README.md`](tools/wheelreader/README.md) | +| The plan for better counter readings, and its status | [`docs/WHEEL_READER_PLAN.md`](docs/WHEEL_READER_PLAN.md) | +| What changed in a version | `visionstate/CHANGELOG.md` (written at release, never edited afterwards) | +| Test image sources | `visionstate/backend/tests/assets/README.md` | + +- Update the home of a fact **in the same change** as the code; a change that makes a doc wrong is + not finished. +- No "as of version X" or "currently vN" status lines outside the CHANGELOG and the roadmap: they go + stale. Say what is, and let git say when. +- `tests/test_docs.py` (backend, runs in CI) checks every Markdown link, every repository path and + every `module.name` / `settings.X["key"]` in backticks against the code — a rename that leaves a + doc behind fails the tests. ## Principles (do not break these) @@ -19,205 +45,114 @@ classifier), **objects** found by a pretrained detector (people, cars, animals) - **Camera credentials never leak:** `redact.py` masks them in logs, errors and exports. - **No hard-coded defaults** outside `settings.py` / the registries; the UI reads them from `GET /api/v1/config`. -- Home Assistant state values stay lower-case keys (`open`, `car_parked`). +- Home Assistant state values stay lower-case keys (`open`, `car_parked`); unique IDs and topics + never change once released. - Marketing text (README, release notes) promotes VisionState on its own merits — no comparisons with other products. -## Layout and conventions - -- `visionstate/` is the Home Assistant app (build context of the Dockerfile). - - `backend/visionstate/settings.py` holds every backend default/tunable; import from there. - - **Map of the code: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md)** — what runs where, how a - check flows, which files a common change touches. Keep it current when the structure changes. - - `backend/visionstate/engine/` is the runtime: `Runtime` (`runtime.py`) is put together from one - mixin per part (`models`, `checks`, `objects`, `reading`, `teaching`, `training`, `publishing`, - `history`, `reminders`) on `RuntimeBase` (`base.py`, the shared state); a part inherits the parts it uses. - `state.py` holds `SensorConfig`/`LiveState`, `logic.py` the pure decisions. New engine code goes - into the part it belongs to; a long-running loop must survive any exception (log it once, try - again) — only `CancelledError` may end it. - - `backend/visionstate/backbones.json` (state sensors), `detectors.json` (object sensors) and - `readers.json` (reading sensors; also the wheel readers for mechanical counters, trained with - `tools/wheelreader` — see its README) are the model registries. Entries are never changed or - removed once released (a new model gets a new id); `python -m visionstate.backbones ` - downloads every bundled model of all three. - - Sensor kinds (`settings.SENSOR_KINDS`): `single_state`, `objects` and `reading`; the UI's tabs per kind - are in `ui.ts` (`TABS_BY_KIND`). New features must say which kind(s) they apply to. - - The History page and every sensor's History tab are one view (`lib/components/history/`, - a row component per kind); its filter is in the page URL (`lib/history.ts`). On the server - `api/history.py` turns every filter into SQL in one place (`history_query`); a new filter - goes there, a new event into `settings.HISTORY_EVENTS` + `EVENT_ROWS` + `ui.ts HISTORY_EVENTS`. - - Object sensors can be taught (`teach.py`, `api/teach.py`, `settings.TEACH`): taught boxes are - `sample` rows with `object_label`; own labels live in `objects["custom"]`. The detector is never - retrained; DINOv2 (always loaded) compares boxes with the taught ones. - - `frontend/src/lib/tokens.css` holds all colours/type/spacing; `ui.ts` holds UI constants; - `api.ts` is the only place that builds API URLs; `router.svelte.ts` defines app paths. - - The UI reads sensor defaults, limits and palette from `GET /api/v1/config`. -- Backend checks: `cd visionstate/backend && .venv/Scripts/python -m pytest -q && .venv/Scripts/ruff check visionstate tests && .venv/Scripts/ruff format visionstate tests` - (tests need the model: `python -m visionstate.backbones models`), and the types: - `.venv/Scripts/pyright --pythonpath .venv/Scripts/python.exe` (0 errors; CI runs it). CI measures - coverage and fails below 88 %; add `--cov=visionstate --cov-report=term-missing:skip-covered` to see - what is not tested. -- Frontend checks: `cd visionstate/frontend && npm run check && npm run build`. -- **UI testing routine** (every UI change, before a beta release) — many users run Home Assistant - on phones/tablets: - - Automated: `cd visionstate/frontend && npm run build && VS_PYTHON=../backend/.venv/Scripts/python npm run e2e` - (Playwright, `e2e/`; also runs in CI; once: `npx playwright install chromium webkit`). It starts the backend + `scripts/fake_camera.py`, - seeds one sensor of each kind (a trained state sensor, an object sensor on a real photo and - reading sensors on a drawn display and a drawn mechanical counter), and runs every page on **desktop** (1440×900, mouse), - **mobile** (Pixel 7, real touch via CDP) and **iphone** (iPhone 14, WebKit like the Home Assistant - app on iOS; gestures with the mouse): no console errors, no sideways scrolling, no text - running out of buttons or cards, plus the wizard (all three kinds), region editor gestures, - labelling, review, boxes, teaching an object sensor and readings. Add a test - for every new page or gesture. - - Look at the full-page screenshots in `test-results/pages/{desktop,mobile,iphone}/` after UI changes, - for every page in all three projects. - - Then try the change by hand in a real browser (Claude: the Chrome tools) — passing tests are not - enough: start `scripts/fake_camera.py 8198` and the backend (`VISIONSTATE_PORT`, `_DATA`, `_MEDIA`, - `_FRONTEND=frontend/dist`, `_BUNDLED_MODELS` as in `playwright.config.ts`; a copy of the last e2e - run's `data` and `media` folders gives seeded sensors), use the changed screens at desktop width - and at ~390 px, and check the console. Reload after a rebuild (a hash-only navigation keeps the old page). - A Chrome window does not get narrower than 500 px (and a maximised one not at all): for a real - phone width, open any same-origin URL (e.g. `/api/v1/status`) and replace the page with - `