Doors That Answered Anyone
Pippa reaches Oriel through two doors: the eyes door for looks, over the tailnet's HTTPS twin, and the app door for writes, on loopback. Until the same day the page moved to PIN sessions, the eyes door answered anyone on the tailnet and the app door answered any program on Pippa's home Mac. The eyes gate and Dad's quoted words still stood behind both, so nothing could be opened without approval. But nothing said the caller was cwkPippa. A curious script on the tailnet could still ask for a look while the eyes were in Auto, and that is a look the house did not intend.
Coop 1110-13 gave every caller a name. The doors now ask for a bearer token, and each token belongs to exactly one named caller, minted by Oriel, for one purpose.
Tokens Kept as Hashes
Every kind of named caller in Oriel (Pippa's service, Oriel's own tools, Dad's other screens, satellites on other Macs, watch-along watchers) uses the same small registry. Its rules are the ones you would want for any secret:
- Minted once, shown once.
python -m backend.callers add cwkpippa --label "…"prints the token a single time; it is delivered to the holder on stdin, never as a command-line argument (which other users of the machine can see in a process list) and never in a log. - Only the hash is stored. The registry file keeps the token's SHA-256, written with mode 0600 from the moment the file exists (the kit's atomic writer sets the mode before the rename, so there is no instant when the file is readable by others).
- Compared in constant time. A request names itself with
Authorization: Bearer <token>, and the comparison does not leak, through timing, how much of a guess was right. - One shared implementation. The satellites' and the watchers' registries were two copies of this code until 2026-11-06; now there is one root and every caller kind is an instance of it.
A Name Opens Only Its Door
The point of names is not just knowing who called; it is limiting what each caller can do.
| Caller | What its token opens |
|---|---|
cwkPippa (cwkpippa) | the eyes door and the app door; never a page route, never an approval on its own (the gate and Dad's words are still asked) |
Oriel's own tools (local) | the same two doors, from this Mac; the engine mints it at start into a file only her account can read |
| Dad's other screens (surfaces) | set the eyes mode, press the kill switch, and start or stop Solo Mode, as Dad's hand on that screen; no look, no frame |
| Satellites, watchers | their own worker routes only |
The surfaces row is worth a second look. A family screen like cwkPippa's web app has already verified Dad's PIN session on its own side, so its press can carry his hand to Oriel. But its token cannot take a picture. If that screen's engine were compromised, its token could change the mode, press the kill switch, or start, extend and stop Solo Mode, but never take a look or a frame. One route is guarded by the gate rather than by a name, and it is worth knowing: a camera's latest frame answers any caller that reaches the engine while the eyes gate covers that camera. There, the gate is the whole guard. Put the two facts together and a compromised surface could set Auto with its own press and then read a home camera's latest frame through that route; its token never carries a picture, but that two-step path exists, and what makes it visible is that every mode change is logged with the surface's name, and the red eye lights the moment a camera is actually in use.
Reads Without a Picture Need a Name Too
The last gap was subtle. Reads that return no picture (the state, the eye, the session list, the activity log) still describe the house: which cameras are open, when Dad was on air. Dad closed it the same day: put the picture-less reads behind the PIN too. Every such route now answers only Dad's session, a named service caller, or a surface by its token. A few routes stay open, as in every family app, and each has a reason: health and version (for the registry's census and the fleet monitor), the sign-in state (so the page can show the sign-in card), and the probes' question to the gate (a refusal carries its reason; a yes carries the input's id, name and media kind, nothing more).