miloco v2026.8.5
Since v2026.7.17: 171 commits, 26 PRs, 269 files changed (+28,623 / β2,942).
π― New Features
- Pet recognition (experimental, off by default) (@ExWang): the largest change in this release. Pets become first-class family members β a pet roster with structured identities, multi-image registration with reference crops persisted and injected into the fused perception prompt, appearance-text matching with an explicit abstain discipline, and body grounding for non-cat/dog species. Ships with a full Web management UI (registration flow, auto-generated appearance, editable profiles, reference-image counts), a CLI command group, and a
miloco-miot-pet-registeragent skill. Gated behindfeatures.*flags, get/set-able from the CLI. - Smart Crop β adaptive resolution before OMNI inference (@Molly-3000): crops the active region out of each perception window before inference, so the model sees the subject at usable resolution instead of a full frame downscaled. Two independent config switches, short-edge upscaling by tier when the crop is below budget, crop video + full-frame reference persisted side by side, and crop coordinates recorded into the trace. Frame selection uses per-frame human/cat/dog detection boxes inside the window and excludes
no_personfalse detections. Enabled by default. - Upgrade notice and one-click self-upgrade in Web (@hlccd): opening the dashboard checks GitHub
releases/latestonce (server-side cached, with aforcere-check) and shows a dot next to the sidebar version plus a dismissible top banner; confirming runs the officialinstall.shin non-interactive agent mode, detached so it survives the backend restarting itself, and the front end polls/upgrade/statusthrough download β install β restart. Release deployments only β dev (git) deployments are pointed atgit pull. If GitHub is unreachable it degrades silently rather than erroring. - Camera IP direct-connect, with cross-NAT streaming diagnostics (@HCl8): cameras on a different subnet can now be streamed directly β the cloud
localipfield is parsed correctly (previously read aslocal_ip, so direct-connect silently never worked), unicast probing moved to its own socket isolated from broadcast, and already-connected cameras count as LAN-reachable. When a cross-subnet stream stalls, the camera card now says what to do ("join the same network, or switch to full-cone / open NAT") instead of just failing. Scanning pauses once every known camera is connected. - Process CPU and thread-count charts on the Perf page (@Zirconi): per-process CPU and thread count tracked as a time series with dual axes, CPU normalized to 0β100%, and in-bucket peaks surfaced so a one-minute full-core spike isn't averaged away in the 24h / 3d views.
- Agent action ledger (@LeonJoeeee): persistent audit of every agent-initiated device control, TTS, and scene trigger, merged into the event page timeline.
- On-demand perception log (@Molly-3000): actively querying the log now persists its result with artifact storage, front-end display, clip playback, and feedback.
- Per-camera perception prompt (@HCl8): each camera can carry its own perception-guidance prompt, injected at the tail of the system prompt for both video and audio paths.
- Urgency filter for suggestion β agent dispatch (@Molly-3000):
perception.min_suggestion_urgencyfilters which suggestions reach the agent, exposed through the admin API and CLI, and surfaced in Web as a 3-stop slider plus an "agent interruption threshold" three-way selector in the settings drawer. - Task name and trigger status in rule-reminder logs (@Molly-3000): logs now show which task and which rule fired, with a collapsed-state badge for the backend's trigger verdict.
- Editable task trigger conditions in Web (@idootop): task detail consolidated into a single edit entry point.
- Manual avatar replacement for family members (@ExWang): explicit avatars are stored separately under
avatars/, with in-browser cropping.
π§ Perception Stability
- Latent memory leaks hardened, and the stale match / centroid cache on cluster-centroid change fixed (@idootop):
_match_cacheinvalidation widened from member-set to centroid change and extended to fetch-side embedding backfill and partial cluster-member eviction; dead clusters evicted from_centroid_cache;_drainedtrimmed regardless offull_action. - Decoder worker leak on reconnect fixed (@Zirconi):
stop()now joins before clearing the reference, returnsFalseon timeout so the camera can consume it concurrently, and a failure mid-stop no longer aborts the rest of the cleanup. - KleidiAI disabled on the silero VAD CPU-EP session and the EventEmbedder session, via a shared
apply_kleidiai_opt_outhelper with CI-enforced spy tests (@idootop). - Smart Crop robustness: bad config now fails closed, crop rejection reasons are observable, upscaling is capped per axis so an upscaled frame can't exceed the original, degenerate/out-of-bounds coordinates fold into a single 410, and a corrupt trace no longer swallows the entire reference-frame card (@Molly-3000).
- Pet-recognition correctness: the registration size gate switched to absolute size + linear area ratio (large sharp pets no longer rejected),
multiple_petsnow requires same-frame co-occurrence (a broken track no longer reports one pet as many), subject tracks count real frames, and pool eviction keeps gate-passers first (@ExWang). - Plugins grant butler capabilities without overriding the host agent's identity; the backend event body and the habit-suggest skill no longer make the agent refer to itself as miloco (@idootop).
- Deploy-timezone handling aligned with the CLI write path via
ZoneInfofor UTC configs (@HCl8).
π Performance
- Idle thread pools trimmed across libraries (@Zirconi): every library defaulted to one thread per CPU core, which sits mostly idle on a single low-quality stream. swscale pixel conversion pinned to 2 threads, video decode to 4, OpenCV to 4, the ONNX detector / reid down from 4 to 2, and a new
TINY_MODEL_THREADS=1used by dedup and VAD, where fork-join costs more than it saves. - SQLite free pages actually reclaimed now (@Zirconi):
PRAGMA incremental_vacuumis driven by consuming its result set, and the missingfetchallmeant each cleanup reclaimed exactly one page while pages freed byDELETEpiled up β a productionobservability.dbhad 142.5 MB of free pages inside 222.8 MB. Reclaim is now capped per run, split into short write transactions, validated against theauto_vacuummode, and moved to a worker thread since it is real blocking I/O.
βοΈ Improvements: CLI / Web
- Habit-suggestion state machine moved from the plugin tool into
miloco-cli(@HCl8), for both the OpenClaw and Hermes plugins, which is what letsplugins/openclawandplugins/hermesshed ~1,900 lines between them. - Web loading behavior reworked: skeleton placeholders instead of a permanent skeleton on API failure,
loadinginitialized totrueto kill the first-frame "load failed" flash, the settings drawer no longer exposes default slider values before data arrives, and the log tab no longer flashes stale history before going blank (@Molly-3000). - Device status semantics clarified in Web (@wei-dou).
- Pet reference-image lookup switched to
functools.lru_cache, dropping a module-level try-once global (@ExWang). - Rule-reminder log labels trimmed to "task / rule" across backend and front end (@Molly-3000).
miotunit tests now actually run in CI βnorecursedirshad excluded the whole directory, so they never had (@HCl8).
π Security / Supply Chain
- Avatar and pet reference-image endpoints hardened (@ExWang): on-disk extension decided by content magic bytes rather than the filename,
realpathcontainment checks on avatar paths,subject_idvalidated in the storage layer, uploaded bytes verified as images,person_idanchored with\Zto reject trailing newlines, and a size gate applied before the body is read into memory instead of after. - Log-injection fixes flagged by CodeQL: CR/LF stripped from
read_crop_metalogging (@Molly-3000); path and log injection closed in the pet and avatar paths (@ExWang); an emptyexceptin perf sampling given a debug log (@Zirconi). - Rule short-name stripping now collapses whitespace before matching and narrows its regex to ASCII on both sides, closing a
task_idleak through whitespace-leading names, plus free-text prompt-injection guards (@Molly-3000). - Unicast probe replies filtered against a source-IP allowlist (@HCl8).
- PR AI-review job timeout raised 30 β 60 minutes (@ExWang); offline eval artifacts and sampling lists added to
.gitignoreso subject labels can't leak through (@Molly-3000).
π Docs
- Full-chain resolution table added β capture / streaming / omni / crop / provider, with the source and conversion at each tier (@Molly-3000).
- Smart Crop's two config switches renamed by configuration layer, with the CLI-writes-
config.jsonfailure path documented (@Molly-3000). create-taskskill tightened (@Zirconi): the TTS action JSON contract documented,Rule.action"play fixed text" scoped to speakers, the perception-viewpoint section given a "no single camera subject" branch, and cross-references realigned.- One-click upgrade documented as a feature page, with troubleshooting entries (@hlccd).
- Perception-guidance injection wording aligned between the system-prompt tail and the video+audio paths (@HCl8).
π Acknowledgements
Special thanks to @ExWang for landing experimental pet recognition β the biggest change in this release β and to @Molly-3000 for Smart Crop.
Thanks as well to everyone else who contributed: @Zirconi, @hlccd, @LeonJoeeee, @HCl8, @idootop, @wei-dou