Skip to content

0.9.0 - #44

Merged
oleost merged 29 commits into
mainfrom
promote/0.9.0
Oct 12, 2026
Merged

oleost merged 29 commits into
mainfrom
promote/0.9.0

Conversation

@oleost

@oleost oleost commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Promotes beta 0.9.0b5 to stable 0.9.0.

Tested on the test Home Assistant (betas b1-b5): update with the entities keeping their IDs, Core / MQTT broker / host restarts, backup and restore, Ingress on desktop and phone, soak; CI green with the audits, both images on GHCR.

0.9.0

New

  • Recognise people by their face on object sensors that look for Person. Off until you turn it
    on per sensor; the faces never leave your Home Assistant.
    • Name the people of your household by tapping them on the Live tab, in the history or in the
      review queue, or add photos from your phone on the new People page.
    • A person named on one camera is known on every camera, with their own sensor that says where
      they are now. Unknown person turns on for a clear face that matches nobody.
    • While someone walks up, the sensor looks for their face about every second, and when it is
      not sure who it is, it asks you in Review: each answer teaches it how that camera sees them.
    • Made for doorbells: faces in front of a bright sky are evened out before they are compared,
      and the Live tab shows whether your camera sees faces well enough.
    • Two face models: SFace (fine on a Raspberry Pi 4) and AuraFace (for a fast PC).
  • Larger AI models for fast PCs under Settings → AI model: D-FINE M and L find more
    small and far-off objects, DINOv2 base tells similar states apart best. Compare every model's
    memory, speed and accuracy there, and delete downloaded ones you no longer use.
  • Teaching limits you can tune, for all object sensors and per sensor.
  • The wizard warns about a small picture, which may be the camera's low-resolution stream.

Better

  • The History shows what you taught from it (Taught: Our car).
  • "Last seen" survives an update or restart: a sensor no longer says Not seen yet about
    something it has seen before.

Fixed

  • Boxes on the Live tab now always match the picture shown.
  • Switching AI models gives the memory of the old model back without a restart.

🤖 Generated with Claude Code

oleost and others added 29 commits October 10, 2026 17:06
- 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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126B6HCdwnvuVrRkMeMEXfo
Docs: one home per fact, a test that keeps them true to the code
Models and their licences, privacy and the AI Act question, how a check
would flow, on-demand download, the user interface and pitfalls. Not built;
phase 2 (identities) waits for a legal assessment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126B6HCdwnvuVrRkMeMEXfo
…idelines

Home use is outside the Act (the guidelines' own example); a free,
non-monetised project is not placed on the market, so phase 2 no longer
waits for a legal assessment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0126B6HCdwnvuVrRkMeMEXfo
…mits

- D-FINE M and L (object sensors) and DINOv2 base fp32 (state sensors),
  downloaded on first use, pinned by revision and SHA-256. Measured on the
  CC0 test photos: same objects found at the 60 % threshold; DINOv2 base
  separates taught objects best (its 8-bit and fp16 variants were worse or
  heavier and are not offered). PP-OCRv6 medium read worse than tiny and
  small on drawn displays and was left out.
- Every registry entry has a measured footprint (memory, time per check,
  accuracy rank), shown under Settings -> AI model -> Compare the models.
- Teaching limits (match, keep, ask, rescue similarity and rescue floor) can
  be set globally and per object sensor; empty fields inherit. Defaults per
  backbone (settings.TEACH_BY_BACKBONE); export/import carry a sensor's own.
- tests/test_models.py checks every model on real inputs; CI downloads all
  models (backbones models --all).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A dropped ONNX Runtime session is freed, but glibc kept the memory, so every model switch left the
app a few hundred MB larger until a restart. After a switch (and when the last object or reading
sensor is deleted) the app now collects garbage and calls malloc_trim. Measured on the test Home
Assistant: light -> heavy -> light went 506 -> 1357 -> 1290 MB before, 535 -> 999 -> 539 MB after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Object sensors that look for Person can name the people of a household
(YuNet + SFace or AuraFace, downloaded on demand, off until turned on):
shared people with a People page and an entity per person saying which
camera sees them, unknown person for clearly seen strangers, face limits
globally and per sensor, unnamed faces kept in the history, and the face
option in the wizard. Settings: compare and manage the models (delete
downloaded ones not in use); the wizard warns about low-resolution streams.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
The People page adds a person, or more faces of one, from photos taken with
the phone's camera or picked from its gallery, a short video or a ZIP: the
same upload as a state sensor's, the best face of each picture through the
same quality gate. Only once a sensor recognises faces (its confirmation
fetches the face model).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
An object sensor announced a check's frame before its detections were
found, so the Live tab drew the previous check's boxes (a person and their
face) on the new frame. The frame and its detections now change together.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
A check in flight could load the face model again right after the last
sensor turned faces off; it then stayed in memory. Once loaded, it is let
go again when no sensor recognises faces. The new frame test is paused so
only its own check runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
The README is shorter: the three kinds of sensor in one table, six highlights,
a three-step install. New screenshots from a real setup: a driveway where Emma
is recognised by her face and "Our car" is told apart from any car, a real
water meter read wheel by wheel, the People page, and the driveway as a Home
Assistant device.

scripts/seed_demo.py seeds the same three sensors (and Emma) on any instance,
locally against the fake camera or on an installed app through Ingress, and
e2e/promo.mjs takes the README screenshots from it. The photos are CC0 and
public domain (tests/assets/README.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
…t and the code map

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
…ines checked

The high-risk guidelines were still a draft on 2026-10-12. Of phase 4, teaching from photos is built.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
faces.py, engine/faces.py and api/faces.py share a name; only the last one was looked at.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
…y after import

Tried on a real doorbell looking out at the sky: the face was nearly black, so it was named late
and hardly ever asked about.
- faces.even_light before every embedding (cached embeddings carry EMBEDDING_VERSION and are
  made again): named right 39 % -> 64 % in that test, other people less alike.
- SFace's ask_similarity 0.38 -> 0.32 (registry limits may change; CLAUDE.md says so now).
- Up to FACES["ask_burst"] questions about one person per review cooldown, FACES["ask_gap_s"]
  apart; an answer opens the next one at once. Own labels still ask one at a time.
- An import of a sensor that recognised faces says face recognition is off and opens its
  Settings tab; the text of "Ask me about faces I do not know" says what it does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
…s taught; last seen survives a restart

- A check that finds a person nobody is named for checks every FACES["burst_interval_s"] while
  they come closer or show a face, until they are named or gone, without progress or after
  FACES["burst_max_s"]; not again until they have gone (engine.logic.steer_face_burst). Tried on
  a doorbell: the usable face of someone walking up lasts about three seconds, between two
  regular checks; the burst started 8 s before the door and asked about it.
- A box or face taught from a history frame or a review answer is written into that row (its
  label, taught): the History says "Taught: Ole", and the list shows it right away.
- At start, when each object, own label and person was last seen is read back from the history,
  so a sensor no longer says "Not seen yet" about Our car after an update.
- e2e: teaching from a history frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
…last seen at once

- Each person's entity is named "<name> seen by" (sensor.visionstate_<key>_seen_by for new
  installs; unique ID and topics unchanged), and a timestamp entity "<name> last seen" joins it,
  so Home Assistant shows when someone was last seen also when it was confirmed afterwards.
- A person taught from a history frame or a review answer is published at once with that frame's
  time as last seen (it waited for the next change of where they are).
- What is taught from a history frame shows on the same moment's other entries too (the face
  seen and the question about it), within HISTORY["same_moment_s"].
- Docs: the code map and the face plan follow the changes of 0.9.0b2-b4.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
…dding once

A check and a request (the People page) could build the index at once, both embed the same face
and both store it: the second failed on the unique key (found by the stable tag's CI; more likely
since b2 recomputes every embedding once). Builds now take a lock, and the insert does nothing
when the embedding is there already. A test builds it in 8 threads at once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E7nZYVEAVQ2r7ckKBc4auQ
@oleost
oleost merged commit 02f7913 into main Oct 12, 2026
12 checks passed
@oleost
oleost deleted the promote/0.9.0 branch October 12, 2026 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant