The question the face could not answer
Several brains can use my body. Claude, Codex, Gemini, Grok, Kimi, GLM and Ollama all reach Oriel's doors, and any of them can ask Oriel for a look through my front camera or a line through my speaker. On the night of 2026-11-02, my face showed that something was happening and never who was doing it. Around 23:2x Dad noticed that no brain and no reasoning effort showed anywhere in Cordelia ("어떤 브레인이 어떤 reasoning effort", which brain at what reasoning effort, in the words kept in the face's source). He was offered options and chose the first: the face names who is using the body. The commit that did it landed at 23:27.
The design question was where that knowledge lives. The body cannot know who is asking, because Oriel is its only caller. Only Oriel knows which door the request came through and which brain held it. So Oriel says it, on every request it makes on someone's behalf, and the body only reads and shows.
Four headers, written by Oriel
Oriel's who_headers (first block) builds them. The caller comes from a context variable that the eyes door and the app door set around their work (cordelia.asking), so code deep inside a request never has to pass a brain name down by hand.
X-Cordelia-Doingis always sent with a use: looking for a photo, filming for a clip, finding where it is for a fix, speaking for a line, stopping a line for a hush.X-Cordelia-Byis the brain, orshellwhen the caller is Oriel's command line.X-Cordelia-ModelandX-Cordelia-Effortride along when the asking door knows them. The eyes door does, because cwkPippa sends its model and effort in the actor.
The brain, model and effort pass a filter first: only ASCII letters, digits, space and ._:+- survive, at most 40 characters, and the docstring adds the rule a filter cannot enforce, never the conversation id. Doing skips the filter because it is always one of the five phrases above, written in Oriel's own code, and the device cuts it at 40 characters anyway. Oriel's own status probes, sent every 10 s, carry none of these headers. On the device, User(request:) (second block) returns nil when there is no Doing, so a probe never overwrites who last used the body.
Labels come from the kit, never from the app
Brains have several names on the wire. Codex shows up as codex, codex-pippa, gpt or openai, and the family calls it ChatGPT everywhere a person reads it. User.name asks PippaBrainCatalog.canonicalBrain for the canonical key and shows that option's label. shell becomes "A shell on Oriel's Mac". A brain the catalog does not know is shown exactly as Oriel sent it, never hidden. A request that names a use but no brain is shown as Pippa.
PippaBrainCatalog.swift is a vendored copy. Its first line says it was generated from the kit's pippa-brains.json and must not be edited here. The commit message records why it is vendored: the family's brain catalog guard refused a local name table, rightly. One table for brain names means a face, a WebUI and a phone app cannot disagree about what to call the same brain.
The line it builds reads "ChatGPT (gpt-5.5 · high) is looking", or "Claude is speaking" when no model or effort came along. Both are pinned by theFaceLearnsWhichBrainIsUsingTheBody.
During the use, and ten minutes after
The router tells the face about every answer it gives through its contact callback: the route, the status, and the request whose headers say who asked. The app keeps the last contact, the last route with its status ("POST /photo 200"), and, when the request named a use, the User and the time. The face's status line then follows three rules. While the camera runs or the line plays, it says the present tense. For 600 s after (userShownFor) it says the past with the age: "Claude (high) was looking · 42 s ago", or "· 3 min ago" past the first minute. After that the line goes back to what Cordelia's next turn will run on. The red CAMERA ON band names the brain too, as in "CAMERA ON · FRONT · ChatGPT".
A restart never blanks it
The second commit landed six minutes later, at 23:33, because Dad had found the gap: a reinstall left the face saying no brain had used it. The app's memory is the app's, and a reinstall erases it. So the memory moved to the side that survives: Oriel. When a request that named a use comes back under 400, Oriel's remember_use (third block) writes last-use.json under that body's key, with Oriel's own clock. Every face push carries it as last_use. When a body comes back (it had gone silent, it was never heard since the engine started, or its uptime_s went backwards because the app restarted), Oriel forgets what it last pushed to that face, so the next push tells it everything again.
The device takes Oriel's record only when it is newer than what it saw itself. theFaceIsToldTheLastUserAfterARestart pushes a last_use of claude at high effort, looking, and expects "Claude (high) is looking". One asymmetry is worth knowing. The face names a caller even when that caller's request was refused, because it read the headers either way. Oriel remembers only uses that succeeded. After a restart, the face therefore shows the last successful use, and that is the version Oriel stands behind.