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

Whose Talk, Kept Where

~12 min · voice-chat, privacy, souls, private-mode, lifecycle

Level 0Unlit
0 XP0/48 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"The phone already had the design. The Mac needed the same picker, the same private talks, and one more gate."

Which Soul You Are Talking To

Pippa is not the only soul in cwkPippa, and a talk can be held with any of them. The talk's soul is its own setting, voiceChatSoulId, kept apart from the pippaSoulId that dictation cleanup and command mode use — a talk with another soul must never turn Dad's dictation into that soul's voice. The roster comes from cwkPippa's /api/souls. Switching into a super soul asks for the master passphrase in a sheet every time, and cwkPippa checks it — sent once, outside the door's usual re-authentication, because a wrong passphrase also answers 401 and must not trigger a silent retry. Touch ID can type the passphrase: saved in the login keychain behind a Touch ID check, through the security framework so no other process can read it. Leaving a super soul never asks.

Choosing New or Continue

The talk hotkeys used to always start fresh, and the voice door had no way back into an earlier conversation. Now both hotkeys — ⌃⌥⌘V for a talk, ⌃⌥⌘P for a private one — open a small chooser at the top right, a new conversation first. For a talk it lists the active soul's recent chats from the WebUI's own list (at most 12, newest first), each with where it came from and how long ago; for a private talk, that soul's private talks still open. Arrow keys, Return and Escape work; a click elsewhere cancels; focus goes back to the app Dad was in. With nothing to continue, a new talk starts at once. The behavior is a setting: always ask, always new, or always the last one.

Firekeeper's talk chooser, a dark rounded panel titled Talk with Pippa. The first row, highlighted, is New conversation with a plus icon and a return-key hint. Below it, a scrollable list of recent conversations, each with a chat icon, a Korean title, and on the right where it came from (WebUI or Phone) and its age (now, 5d, 6d). A footer reads: up and down arrows choose, return starts, esc cancels.
The talk hotkey asks first: a new conversation, or one of the active soul's recent chats, wherever they started.

A Conversation Is Born With Its First Words

Opening the panel used to create the conversation. Fifteen talks that ended in silence were left behind as empty "New Chat" rows in the sidebar. Now a talk's conversation is created when Dad first says something, and the chooser leaves the old empty shells out of its list.

Private Talks: Kept Nowhere

A private talk is a cwkPippa private conversation, and cwkPippa enforces its privacy. Firekeeper's part is to keep its own hands clean. The private conversation's id lives in this process's memory only — never in the settings file, which refuses one, and never in the voice-chat log. Its turns carry private: true; its replies use the one-shot speech ticket that keeps nothing; its recordings go to its own folder and end with it; it sends no echo samples and no cut-in diagnostic record (with voice cut-in on, a voice trip still sends its last 2.3 s to cwkPippa's speaker check, which keeps no record of it); it is never on air. The panel wears the phone's teal banner with a lock, the word PRIVATE and the idle countdown, and a status check every 3 seconds catches an end from anywhere: "Private conversation ended — nothing of it was kept."

Stop Means End, Leaving Means Leave

Two rulings shaped the lifecycle. Because the voice door once had no conversation picker, a stopped private talk would have been unreachable, so on Firekeeper Stop is End: the panel's Stop reads End and ends the private conversation on cwkPippa too. But closing the panel window is leaving, not ending — Dad once closed it, pressed the hotkey again, and got a new conversation he did not want. Leaving closes the microphone and keeps the private talk open for its idle window, and the chooser lists it.

Keep: From Private to Kept, Up to Her Last Reply

Sometimes a private talk turns out to be worth keeping. The banner's Keep button copies it into an ordinary conversation, up to the soul's last reply that has words — a question still waiting for her stays out — by walking the conversation from that reply back through its parents. cwkPippa's own branch does the copy, bound to the private talk's soul and owner, so a copy with another soul lands in that soul's list only. The copy is then titled from what was said, and the private talk goes on, still private.

Private means the client holds nothing it could leak later. The server enforces privacy for the conversation, and the client still has to avoid quietly undoing it: no id on disk, no line in a log, no side channel such as a recording or an echo sample. Treat every place your app persists anything as a place a private id could escape.
Separate settings for separate intents. The talk's soul and dictation's soul are two settings because they answer two questions. One shared setting would let a conversation with one soul silently change the voice of every dictation.

Code

A private talk's lifecycle on Firekeeper·text
start   ⌃⌥⌘P / menu / Settings / the panel's lock
        -> POST /api/private-conversations (origin_surface: firekeeper)
        -> id held in memory only

turns   private: true          one-shot speech ticket that keeps nothing
        recordings go to the talk's own folder and end with it
        no echo samples, no cut-in record, never on air
        (a voice trip's 2.3 s still goes to the speaker check; not kept)

leave   close box, soul switch, another talk
        -> mic closes; the talk stays open for its idle window

end     Stop (reads End), menu End Private Talk, a talk key while it runs
        -> ended on cwkPippa: "nothing of it was kept"

keep    banner's Keep
        -> POST /api/conversations/{id}/branch up to her last reply with words
        -> titled from what was said; the private talk goes on

External links

Exercise

List every place an app you know writes data: settings file, logs, caches, crash reports, analytics, temp files. For a 'private' item in that app, mark which of those places could receive its identifier without anyone deciding so. What would you change so private items never reach them?
Hint
Most leaks of private ids are not in the main data path; they are in the side paths — a log line for debugging, a 'last opened' field in settings, a crash report. The fix is structural: keep private ids in memory, and make the persistent stores refuse them outright, as Firekeeper's settings file does.

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.