Room change watcher
A free image-change trigger with an explicit interpretation boundary.
Documentation revision 1 · Contract reference API 54 · Installed readiness unknown
Preview offline card · Complete HTML interaction body · Machine-readable recipe
What runs where
- Timer → camera → free local image comparison → watch.matched event → controller inspection or offline status card.
- model none makes no Jev/Clef calls and establishes a baseline before reporting changes.
Controller integration
- Receive events, avoid duplicate processing by event ID/sequence, persist meaningful history.
- Controller model interpretation and alerts are optional integrations, not features of the change filter.
Only explicit decision-model/weather requests leave the phone; direct or relay transport still requires a running reachable phone.
Boundaries
- A changed image is not an intrusion, person count, danger or proof that something happened outside the frame.
- The latest state and recent checks are bounded; controller must persist event history it needs.
Lifecycle
start
POST /v1/watches with the start example; retain the returned watch_id. Then render/post the card with resource_id.
update
GET state/tally first. To change the definition, export required history, DELETE old watch, POST revised definition. No watch PATCH exists.
pause
POST /v1/watches/{id}/pause with {"paused":true}; resume with false. Confirm user_paused from the returned metadata. Expiry is unchanged.
stop
DELETE /v1/watches/{id}; confirm deleted equals the saved id and watch.ended reason deleted. Archive needed tally BEFORE deletion. Cancel the interaction separately.
Failures and costs
- Lights, shadows and movement can trigger changes. Tune sensitivity using known examples.
- Locked/busy camera is an error gap; first baseline does not count as a change.
- Free local comparison, no paid calls. Captures use battery and require camera permissions and an unlocked phone for built-in cameras.
Complete synthetic contract examples
These fixtures demonstrate contracts. They are not observations from a phone. Replace image/resource IDs with returned authorized IDs. Load request.json as the complete body of POST /v1/interactions; it contains the full offline HTML.
start
{
"id": "start",
"request": {
"method": "POST",
"path": "/v1/watches",
"body": {
"label": "Room image changes",
"data": [
"camera"
],
"camera": "rear",
"model": "none",
"interval_s": 30,
"window": 1,
"min_readings": 1,
"expires_in_s": 3600,
"repeat": true,
"cooldown_s": 120,
"local": {
"change_check": true,
"sensitivity": "normal",
"max_reuse_s": 300
}
}
},
"response": {
"status": 201,
"body": {
"watch_id": "w0123456789ab",
"label": "Room image changes",
"user_paused": false,
"created_at": "2026-11-04T10:00:00Z",
"expires_at": "2026-11-04T11:00:00Z",
"interval_s": 30,
"data": [
"camera"
],
"checks": 0,
"matches": 0,
"last_match_at": null,
"readings_held": 0,
"last_check": null,
"usage": {
"model": "none",
"answered_locally": 0,
"paid_calls": 0,
"paid_cost_usd": 0,
"paid_calls_last_hour": 0,
"max_paid_per_hour": null,
"skipped_over_paid_cap": 0,
"change_check": true
},
"spec": {
"label": "Room image changes",
"data": [
"camera"
],
"camera": "rear",
"model": "none",
"interval_s": 30,
"window": 1,
"min_readings": 1,
"expires_in_s": 3600,
"repeat": true,
"cooldown_s": 120,
"local": {
"change_check": true,
"sensitivity": "normal",
"max_reuse_s": 300
}
},
"callback_secret": null,
"first_check_in_s": 0,
"delivery": "watch.matched and watch.ended go to your registered callback if you have one, and to GET /v1/events (both need the interactions permission)"
}
},
"evidence": "Synthetic contract fixture, not a device observation."
}
stop
{
"id": "stop",
"request": {
"method": "DELETE",
"path": "/v1/watches/w0123456789ab"
},
"response": {
"status": 200,
"body": {
"deleted": "w0123456789ab"
}
},
"evidence": "Synthetic contract fixture, not a device observation."
}
Extensions
- Escalate only selected changes to a controller model, with a fresh capture.
- For a specific yes/no condition, change model to clef and set a paid-call cap; stop/recreate to update.