Adds the workshop/office assistant and the plumbing several other features
were waiting on. The through-line: every new capability that could act on
its own proposes instead, and says out loud when it does not know something.
New service — workshop/
Project notebook (workshop.db) plus a never-pruned knowledge store
(workshop-knowledge.db): standing workflow instructions by activity,
keyword facts, durable project learnings, and the household's ONE hardware
inventory. GET /context returns everything applying right now in one call,
so the assistant is told the standing considerations rather than reminded
of them. Two databases because they have different lifetimes: rebuilding
the project store must not take the note about how you solder with it.
Hardware statuses distinguish reserved (still on the shelf) from in_use
(installed and working) — "can I use this right now" has different answers
for the two, and naming a project on an in_use item never silently demotes
it.
Gitea repos with append-only history: commit/push/branch yes, unattended;
force-push/rebase/amend/reset/filter-repo never, enforced server-side by
branch protection rather than only by this code refusing. When history
genuinely must be scrubbed, /scrub-request prints the commands for a human
to run — the manual step is the safety mechanism.
Fleet scripts: one monitoring-agent script per kind of machine, fetched by
each endpoint's fleet-bootstrap timer. Remote code execution by design, so
the constraints are the design — upload is a draft, publishing is separate,
scripts live in SQLite rather than on the writable share, every version is
kept, and the endpoint verifies the checksum and reports pass or fail.
Slots exist for the ESP32s and network appliances that cannot run a script
at all, holding the CheckMK-server-side config instead.
Infrastructure health
opnsense becomes a LIST of firewalls, each named, keyed by name rather than
index. CheckMK joins it. Both are polled by workshop (always-on) and read
by digest-engine, so the digest can say "critical since Tuesday" instead of
quoting a six-hour-old snapshot. Three states, because "I could not ask" is
not "nothing is wrong".
pantry-vision
All four stock movements are camera-driven; stock counts individual units
and folds brand-free via Grocy product groups. Door-sensor-triggered
appliance cameras record sightings as hints with timestamps, never as
stock — a camera at a door cannot tell in from out.
identity
Per-person colour and settable profile picture, assigned to avoid collisions
between people sharing an initial, on the 2-bit-per-channel lattice a colour
Pebble renders natively.
render/ — shared, vendored, dependency-free
media-visualiser: two-tier by necessity, since most endpoints have no local
audio; the synthetic tier says on screen that it is not an analysis.
floorplan-3d: canvas 2D rather than three.js — the scene is prisms on a
plane, which an isometric projection draws in ~200 lines, predictably on
weak panels, with the frontend still at zero dependencies.
Config and fleet plumbing
Rooms are one vocabulary (an HA area_id) from CoreSystemConfig through the
builders to suggested_area. Keycloak and FreeIPA are coupled as one
decision with USR_HA_ group naming, declaration-only for now and validated
as such. Immich alongside the photo share, read-only. Thin clients get the
full media-key set for a wireless remote.
Docs: fridge-item-location, workshop-assistant, rooms-and-endpoints,
endpoint-surfaces, pebble-presence-watchface.
Testing is stubbed suites and headless unit checks only — no real Grocy,
camera, vision model, CheckMK, Gitea, Samba or browser has been involved.
The CheckMK API shape and Gitea's branch-protection payload are written from
documentation and have version-sensitive field names.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FanS1vyE2gLhGkqKq6HtYj
Extends Phase 6's identity rather than adding a service — all of this is facts
about who someone is, already identity's job.
- admin.html/admin.js: manage people/guests, edit every field, prune, history,
access log. Deliberately not kiosk-shaped and not linked from any wall panel —
a panel anyone can walk up to shouldn't carry a "prune these people" button.
- Nicknames are an input alias only. /resolve accepts them; every payload also
carries speak_name (always the real name) and chores/ uses it for reminders.
A nickname colliding with anyone's name or nickname is refused; a spoken string
matching two people refuses with ambiguous_name rather than picking one.
- Visit history sampled from identity's own /presence. home:null writes nothing,
ever — an HA outage must not record a departure that didn't happen. Departures
need sustained absence (BLE flaps) and are stamped at the last time actually
seen. "With whom" is an interval-overlap query, not a second table.
- Pruning splits selecting from deleting: the filter fills the checkboxes, the
delete goes by explicit id, and the filter is never re-run at delete time.
- Device rights are an answer, never an action — identity stores grants and
answers GET /device-access; HA asks and HA acts. Deny is the default and the
only fallback. Grants can expire; every check is logged, denials included.
- Chore assignment prefers an assignee who's home but doesn't let an absent one
block the chore (CHORE_ASSIGNMENT_STRICT flips that). Litter still ignores
both exemption and assignment.
- Admin-added identifiers still enforce TRUSTED_ENTITY_PREFIXES; only the
"in range right now" check is relaxed, never the allowlist.
Resolves open decision #26; adds #34-37 for the new unknowns (DEPARTURE_GRACE_
SECONDS is untuned, the panel has never been opened in a browser).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Phase 19: trash-calendar (Kennelbach ICS -> CalDAV) and transit (GTFS
departures + OpenTripPlanner-backed voice route planning, slow walking
speed assumed). Phase 20: Tapo camera integration via identity's new
Frigate face-recognition presence signal, and chores, a presence/
calendar-driven household task nudger ("I don't care who does it, as
long as it gets done") with a passive fairness tally, litter culprit
attribution, and per-person chore_exempt/chore_reminder_style settings
on identity.
Also: the HA integrations + hardware-monitoring catalogs, Music
Assistant wiring, docs/network-integration.md (OPNsense VLAN
segmentation, no WAN port-forwards), the ESPHome BLE-proxy firmware,
and RuView CSI-presence integration (github.com/ruvnet/ruview) with
household automations for sleep/distress/concurrent-vitals/bathroom-
occupancy — all flagged with their real unverified assumptions and
open decisions. Fixed two real port collisions surfaced while wiring
this in (OTP vs. zigbee2mqtt on 8080, Music Assistant vs. pantry-vision
on 8095).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K6CrKjW3yVptUnjG35HjC1