Skip to content
C.W.K.
Lesson 04 of 06 · published

Every Door, One Brain

~14 min · surfaces, deep-links, watchos, macos

Level 0Muted
0 XP0/64 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete
"Defer Telegram and Council, and just leave them on record. We might never do them." — Dad, 2026-09-26

The Web and Every Sidekick

The WebUI's main chat was the first surface, and the shared hook from Track 1 carried voice mode into every sidekick panel the same day: the prose editor, the music engine, the art studio and the rest all talk like the main chat, because each one renders the same chat view through the same embed and mounts the same hook. A browser still asks for the microphone once per origin, and only over HTTPS or localhost.

The Phone

The native app got the most work, and most of Tracks 4 through 7 happened there first: its own streaming decoder, one owner for the audio session so the talk survives a dark screen, a face screen, a Live Activity that follows the conversation, echo cancellation with the reply on the microphone's own engine. Every change went out through TestFlight to Dad's own phone, where many of the bugs in this quest were found.

The iPhone voice screen while listening: Pippa's face in a rounded teal frame, a seven-bar meter under it, the word 'Listening', a Pause button, and Cut-in and Captions controls at the bottom, with KO at the top right.
The same face on the phone, listening: the teal frame, the same meter, Pause, and the Cut-in and Captions toggles.

The Mac: Firekeeper

Firekeeper, the family's dictation app, became the Mac's door into voice mode. A global hotkey opens a small floating panel for a hands-free talk from any app; its menu can start a talk with any soul, continue a recent voice chat from any surface, or open a private talk that lives only in memory. It doesn't use its own on-device speech engine for this: it listens through cwkPippa's realtime session, so the partial words, the end-of-speech window and the keyterms are exactly the web's and the phone's. The turn rides the brain's own chat route with reply_modality: spoken, on a model slot reserved for voice chat rather than the main one, and a talk is an ordinary conversation that shows up in the sidebar like any other. As Track 7 told, it cuts in by key rather than by voice, and it lets each Mac choose its own microphone and speaker, because remote-desktop software kept taking over the default devices.

The Wrist

The watch has no speech recognizer an app can drive outside its own dictation screen, and it isn't on the family's private network, so its door works through the phone. A Pippa Voice complication takes a dictated message on the wrist, the phone turns it into a dictated, spoken turn, then fetches the finished take in the soul's voice and hands the MP3 back to the watch as a file, not a stream. It was proven on Dad's watch through the speaker and through earbuds, with the crown as the volume knob. A hands-free start exists too, and it is deliberately not a loop: a press opens the microphone for one utterance, the phone transcribes it, her reply plays, and the microphone stays closed until the next press (Track 6 tells why the loop was taken out). And when Dad's AirPods are on the iPhone, the iPhone reads the wrist's reply into them, and the watch keeps the take silent behind Play.

The Road

Pathfinder, Dad's navigation app for driving and walking, is a door that had to keep the loop inside itself. Spark hands its thread to the phone app; Pathfinder can't, because one app on the audio route is the only way the guidance prompts and her voice can share it. Another app's prompts are not cancelled by this app's voice processing, so they would be transcribed as Dad. It is the third app loop built from the shared voice kit's parts, after the phone and Firekeeper, and the road comes first: her ears close while a guidance line sounds, an urgent line cuts her off where she is, and a guidance line waits up to 3 seconds for her to finish a stretch. A drive's talk is one ordinary conversation, continued for two hours.

Handing a Thread Across

The interpreter app, Spark, is a case of saying no to a door. Its web sidekick talks like every other. But its phone app has no conversation screen, and Dad ruled it shouldn't grow a voice loop of its own. So Spark's "Talk with Pippa" buttons open the moment's thread in the phone app through a link that names the conversation and the language, and the phone app opens it in voice mode, already listening.

The Doors Not Built

Telegram voice notes and multi-soul Council turns got complete designs in the doc, and Dad deferred both, saying they may never happen. Half of Telegram has since arrived by another road: a voice note there is now a dictated turn that keeps its recording, so the speaker check from Track 8 covers it like any other door. Its replies are still written, never spoken turns, and Council's voice turns stay a record, not a plan. A written-down "not now" is part of the architecture too, and so is noticing when part of it quietly became "now".

Code

One brain behind every door, and a link that hands a thread to the phone in voice mode·python
from dataclasses import dataclass
from urllib.parse import parse_qs, quote, unquote, urlparse

SCHEME = "cwkpippa"
LANGUAGES = {"ko", "en"}


def voice_link(conversation_id: str, language: str) -> str:
    """A sibling app hands a moment's thread to the phone app, in voice mode."""
    if language not in LANGUAGES:
        raise ValueError("KO or EN, picked by Dad, never auto")
    return f"{SCHEME}://conversation/{quote(conversation_id, safe='')}?voice={language}"


@dataclass(frozen=True)
class OpenRequest:
    conversation_id: str
    listen_in: str | None     # None: open the thread normally, no voice


def parse_link(url: str) -> OpenRequest:
    parts = urlparse(url)
    if parts.scheme != SCHEME or parts.netloc != "conversation":
        raise ValueError(f"not a conversation link: {url}")
    conversation_id = unquote(parts.path.lstrip("/"))    # undo voice_link's quote
    if not conversation_id:
        raise ValueError("missing conversation id")
    voice = parse_qs(parts.query).get("voice", [None])[0]
    return OpenRequest(conversation_id, voice if voice in LANGUAGES else None)


# The doors: every one reaches the same brain with the same two facts.
DOORS = {
    "WebUI main chat":  {"loop": "useVoiceMode hook", "reply": "spoken"},
    "Sidekick panels":  {"loop": "the same hook, inside /embed/<app>", "reply": "spoken"},
    "Phone app":        {"loop": "native loop on the shared voice kit", "reply": "spoken"},
    "Firekeeper (Mac)": {"loop": "native loop, key to cut in", "reply": "spoken"},
    "Pathfinder (road)": {"loop": "its own loop on the kit; the guidance first", "reply": "spoken"},
    "Watch":            {"loop": "one press, one turn; the phone transcribes", "reply": "spoken"},
    "Telegram":         {"loop": "a voice note is a dictated turn", "reply": "written"},
    "Council":          {"loop": "deferred by Dad's ruling", "reply": None},
}

link = voice_link("conv-1234", "ko")
print(link, "->", parse_link(link))
print(parse_link("cwkpippa://conversation/conv-1234"))
odd = "private/쪽지 #2"                                  # reserved characters round-trip
assert parse_link(voice_link(odd, "en")).conversation_id == odd
for door, how in DOORS.items():
    print(f"{door:18s} {how['reply'] or '-':7s} {how['loop']}")

External links

Exercise

Run the code, then add a door of your own to the DOORS table (a car, a smart speaker, a terminal) and write in one line how it would listen and how it would play. Decide whether it can run the loop itself or should hand off to another surface the way Spark does, and write the link or call it would use.
Hint
Ask two questions about the new door: can it hold a microphone open and play audio with echo cancellation, and can it reach the brain directly? If either answer is no, it is a hand-off door like the watch or Spark: it captures or triggers, and a surface with the full loop does the rest.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign in — Please sign in to comment.

No comments yet — be the first.