← Projects

Rust · Computer vision · Daemon architecture

sky-vision

sky-vision is a daemon-first home computer-vision system in Rust: a 17-crate workspace where a single daemon owns the cameras, supervises a fleet of out-of-process inference plugins, tracks who is where in the house, and forwards useful events to an AI agent — with a hard requirement that an 8-camera setup stays responsive even when a detector stalls or crashes.

The problem

Home CV systems usually die one of two deaths: the monolith, where the UI, cameras, and models share a process and one slow inference run freezes everything; or the pile of scripts, where nothing supervises anything and the system quietly stops working on a Tuesday. The interesting constraints are architectural — inference must not block capture, model crashes must not take down the daemon, and identity must be opt-in and local, because this thing watches your house.

What I built

How it works

The daemon never runs model inference itself. Detectors and embedders are separate processes that ask the daemon for work over gRPC streams, which inverts the usual dependency: the daemon controls dispatch, owns the queues, and measures end-to-end latency per request, while a misbehaving model can only hurt itself. Supervision closes the loop — each plugin gets its own task with restart backoff that resets after a stable run, and operators can disable or restart plugins live.

Everything downstream consumes one typed event stream: five event kinds — detection, track, identity, presence, face signal — in a single envelope that carries the camera id, so consumers can route without decoding payloads. The broadcast is bounded and lagging consumers drop; nothing in the pipeline is allowed to apply backpressure to capture.

ArchitectureOne daemon owns the cameras and the queues; models live in supervised processes that can crash without taking anything with them.

Architecture diagram viewer

100%

Scroll to zoom · drag to move

Identity is where the privacy and concurrency design meet. People, aliases, embeddings, and enrollment samples are local, opt-in, and cascade on delete down to the face-crop files. The live loop hangs off a pure identity gate — per-track cooldown, in-flight dedup, transition-only emission — and hands derivation to an ONNX sidecar. The measured win from moving face inference to the GPU: helper CPU dropped from roughly 2000% to 350% with embedding parity verified at cosine similarity 1.0000.

Autonomous identity loopThe loop closes detect-to-identity without ever blocking the event path: the gate is pure, the queue is bounded, and derivation happens out of process.

Autonomous identity loop diagram viewer

100%

Scroll to zoom · drag to move

How it achieves the goal

The mandate was bounded intelligence: useful CV that degrades honestly. Every seam in the system is a place where slowness turns into counted drops instead of stalls, and every crash domain is a process boundary. That discipline is tested — 362 test functions across the workspace, CI running fmt, clippy with warnings as errors, and the full test suite, plus 8-camera smoke and 24-hour soak scripts for the parts CI can't reach.

None of it pretends to be finished, and the gaps are deliberate: the tracker is simple greedy IoU (a ByteTrack placeholder was considered and removed), security is a documented local-trust model on a Unix socket rather than app-level auth, and the in-process plugin mode is a recognized seam without a real plugin yet. Those are recorded decisions with revisit conditions, not accidents.