01 Changelog
App changelog.
One list for the whole desk side. The Android and iOS apps share a version; the daemon and the VS Code extension share another, and since 2.19.9 the desktop half can move on its own — each entry says which parts it touches. Newest first. App releases also carry their notes inside the app, under About → Changelog. Looking for the desk device? The SofaNode firmware has its own changelog.
Not in the list? Report the bug or request the feature — entries here name the reports they close.
2.36.2App only · daemon & extension 2.37.0 · SofaNode firmware 0.14.0 · Sep 2026
Custom endpoints count as local
- Custom endpoint (local). Models from a custom OpenAI-compatible server set up under Local LLM in the SofaCode extension now sit in the LOCAL section of the model picker, beside LM Studio and Ollama — which reads Ollama (local) now too. Nothing else moves. Needs daemon & extension 2.37.0 for the models to be offered at all; the picker is unchanged for everyone else.
2.37.0Daemon & extension only · app stays 2.36.1 · SofaNode firmware 0.14.0 · Sep 2026
Local LLM (beta): Copilot Chat on your own models
- Your own servers in Copilot Chat’s model picker. Turn on Local LLM in the SofaCode extension and models from LM Studio, Ollama or any OpenAI-compatible server (vLLM, llama-server, OpenRouter…) appear in Copilot Chat’s picker — and, because the app lists whatever Copilot Chat can see, in the SofaCode model picker on your phone, watch and SofaNode, under LOCAL. Streaming, tool calling and agent mode included. The guide takes each server from install to first reply.
- Off until you turn it on. Nothing registers and nothing shows until the switch on the SofaCode: Local LLM settings (beta) page is flipped; it takes effect at once, no reload. It is a beta: used daily, still moving.
- Grown from LM-CODE. This is the LM-CODE extension brought inside SofaCode, so one install gives you everything. LM-CODE itself keeps working and keeps its own life; with both on, Copilot lists LM Studio models twice, so disable one. The first time you enable Local LLM it offers to copy LM-CODE’s servers across.
- The daemon changes nothing of its own — it versions together with the extension.
2.36.1App only · daemon & extension 2.32.1 · SofaNode firmware 0.14.0 · Sep 2026
Subscribing works outside the United States
- The two plans are on sale in 173 countries. They had only ever been priced for the United States and Mongolia, and Google Play will not sell a plan in a country it has no price for. Everywhere else, Play refused to hand the app its own products and both Subscribe buttons did nothing at all when tapped — no purchase sheet, no error, nothing. Both plans and the 7-day free trial now carry a local price in every country Play sells in. Prices in the United States and Mongolia are unchanged, and nobody already subscribed is affected.
- The paywall stops failing in silence. If the store cannot open a purchase, the paywall now says why and stays where it is, instead of closing on a tap that went nowhere.
- iPhone and iPad were never affected — the App Store has been selling both plans in 175 territories throughout.
2.36.0App only · daemon & extension 2.32.1 · SofaNode firmware 0.14.0 · Sep 2026
A screensaver, like the node's
- Screensaver. When the app is holding the screen on and nothing is working or waiting on you, a moving picture covers it after the idle time you set — five minutes by default — so nothing burns in. Code rain, Psychedelic and Sacred geometry are the SofaNode's own three, number for number; new on the phone: Flow field, Code being built, Geometry being built, and Shuffle. Mostly black, never still, lit from your theme. The first touch brings the app straight back; so does any session becoming busy. The connection stays up throughout.
- Settings → Screensaver picks the style and previews it at once; Screensaver after sets the wait (1 to 30 minutes).
2.35.1App + daemon & extension 2.32.1 · SofaNode firmware 0.14.0 · Sep 2026
Phones stop fighting over the deck
- Each phone keeps its own place. With more than one phone on a daemon, a tap on one used to re-aim every other one — and undo its own pick — because the computer reported the window the daemon had just raised as if you had clicked into it. The daemon now tells its own raise apart from your click, and only your click moves a phone that is following focus. (Daemon 2.32.1.)
- The rail is yours. The left rail and the window pill followed the daemon's shared trigger target, so another phone's pick changed what was listed on yours. Both now follow the window your own aimed session lives in.
- No hopping inside one window. With several sessions behind one VS Code window, the deck used to jump to whichever one changed state last. A session that is working or waiting on you now holds the deck until it goes idle. (Daemon 2.32.1.)
2.35.0App only · daemon & extension 2.32.0 · SofaNode firmware 0.14.0 · Sep 2026
Tuck the circle or the chat out of the way
- One bar, either half. Drag the bar between the ring and the chat and you can now tuck either out of view — push it down to hide the chat and let the ring fill the deck (as before), or up to hide the ring and let the chat fill it. The bar parks at the edge; drag it back, or tap it, to bring the half back. Same gesture in landscape, side to side.
- More room before it closes. On a tablet the ring used to stop growing about halfway down before the chat snapped shut; you can drag it about three-quarters of the way now.
2.34.0App only · daemon & extension 2.32.0 · SofaNode firmware 0.14.0 · Sep 2026
The deck turns sideways
- Landscape, everywhere. Turn the phone and the whole deck rotates in place: the session rail drops to the bottom of the screen, the hero ring and its pills take the left, and the reply preview, prompt box and chat controls stack down the right. Every gesture, theme and control works the same — it is the same deck, laid across instead of down. On both Android and iOS.
- Older phones stay supported. The direct build now runs on 32-bit-only devices as well, so an old handset kept alive on the sideload channel isn't left behind.
2.33.0App only · daemon & extension 2.32.0 · SofaNode firmware 0.14.0 · Sep 2026
The deck becomes a cockpit, and the app stops repeating itself
- Mode switching stopped being a guessing game. One selector on both screens lists every mode your provider offers with a one-line meaning, marks the active one, and sets it in a tap. Bypass wears red, and the deck shows the current mode as a pill beside the window pill.
- The ring names its model — and switches it. The model in use sits under the state word in the circle; tap it to open the same model picker the chat has.
- Files and terminal, one tap from the deck. Two chips beside the task button open the file browser and the terminal for the session you're aimed at.
- Enter writes a new line. Multi-line prompts stay one prompt — the send button sends, and a hardware keyboard's Ctrl or Cmd Enter sends. The deck's box no longer closes itself mid-thought.
- Replies speak once. Coming back to the deck no longer re-reads the last reply — what was spoken stays spoken, per session, across navigation.
- Fresh installs can speak at all. Newer Android hides speech engines from apps that don't declare them; ours never did, so a brand-new install was silent. Declared now.
- Small fixes: the speaker toggle lost its overlapping outline, and a chat memory leak that could crash long sessions is gone.
2.31.2App only · daemon & extension 2.32.0 · SofaNode firmware 0.14.0 · Sep 2026
The rail folds away too, and the bars answer a tap
- The session rail collapses. A slim handle on the rail's edge drags it closed — the whole deck spreads into the freed width — and a parked handle at the screen's edge drags it back. Same feel as the ring divider, same real-time follow.
- Tap either bar to toggle. A tap on the divider hides or restores the chat box; a tap on the rail handle folds or reopens the rail. Dragging still works everywhere.
2.31.1App only · daemon & extension 2.32.0 · SofaNode firmware 0.14.0 · Sep 2026
The divider follows your finger
- The deck's new divider drags in real time. In 2.31.0 the seam only redrew when something else on the deck was animating, so on an idle deck it froze mid-drag and jumped at finger-up. It now follows the drag frame by frame.
- And it has real travel. The drag was pinned to the ring's default size cap, which taller phones already sit at — pulling down barely moved. A deliberate drag can now grow the ring half again past the default before the usable-box limit takes over.
2.31.0App · daemon & extension 2.32.0 · SofaNode firmware 0.14.0 · Sep 2026
A deck you can reshape, tasks everywhere, and a real code editor
- Drag the deck into the shape you want. A small handle between the ring and the chat box re-splits the deck: pull it up for more transcript, down for a bigger ring — and past the stop the box tucks away entirely, leaving a glanceable deck of just the ring and its pills. Your split sticks until you change it.
- The task list is one tap away, on both screens. A floating button over the deck's chat box swaps the box itself to the session's task list — same button flips back. The full chat has the same button, opening the list as a card you dismiss by tapping anywhere outside it. The old Tasks pill in the chat toolbar is gone; this is faster.
- New replies glow their age. A message that arrives while you watch wears a green tint that steps toward amber as newer ones land, then fades — five shades, smooth, in the deck's box and the full chat. The deck's box also carries the chat's "working · N agents running" line now, so the circle and the box agree. A switch in Settings turns the tint off.
- The editor is a code editor now. Syntax highlighting (Python, JavaScript, JSON, Markdown and friends), line numbers, bracket matching, code-aware themes for all six looks — built on CodeMirror, bundled entirely inside the app, nothing loaded from the network. Autocorrect is shut out of your code. The plain editor is still there under Settings → Classic editor.
- The editor stopped trusting luck. Real redo. Find and replace. If the app dies with unsaved edits, they're offered back on reopen. If the file changes on the machine while you read, a clean buffer reloads itself and a dirty one warns you. If a save's answer gets lost in transit, the app checks what actually landed instead of guessing — and a conflicting save shows you the actual difference before you overwrite anyone, including your agent.
- Binary files stopped being editable lies. Opening an image or other non-text file used to show mangled text that would corrupt the file if saved. The daemon now says what a file really is; the editor shows a read-only notice and offers a download instead.
2.32.0Daemon & extension only · app 2.31.0 · SofaNode firmware 0.14.0 · Sep 2026
The daemon learns what a file is before letting anyone edit it
- File reads carry a verdict. The daemon classifies every file it hands to an editor — text, binary, or text in an encoding it can't faithfully round-trip — and refuses to serve the unsafe ones as editable content, so no client can corrupt a file by accident again.
- Writes over non-text need intent. Saving over a binary is refused unless the client says the user insisted — and even then, a genuine conflict still wins.
- Conflicts can show their work. A conflicting save can now return what's actually on disk, so apps show a real diff instead of a blind choice. All of it is backward-compatible: older apps keep exactly the behavior they had.
2.29.3App only · daemon & extension 2.30.1 · SofaNode firmware 0.14.0 · Aug 2026
Dictation waits for you, and the chat fits your eyes
- Dictation no longer stops the moment you pause. Phone dictation — the chat’s mic and the deck’s box — used to end about a second after you stopped talking, and finishing a sentence meant tapping the mic again. It now keeps listening through your pauses, on both platforms, until you tap stop. Closes #11.
- A mic that fails tells you why. Some microphone failures ended dictation with no message at all — indistinguishable from a button that does nothing. Every failure says something now, including the quiet one: start dictation, say nothing the phone could hear, and it tells you it caught nothing instead of just switching off.
- Chat text, your size. A new text-size control in the chat scales the transcript and the input up to half again as large — for everyone whose arms were getting too short for the default.
2.30.1Daemon & extension only · app 2.29.3 · SofaNode firmware 0.14.0 · Aug 2026
Windows stops flashing terminals at you
- No more stray console window on Windows. The VS Code extension used to start the daemon in a visible terminal — and closing that terminal, which is what anyone does with a stray terminal, killed the daemon and took the phone offline. It now starts hidden and detached, so it also survives closing or reloading the VS Code window that started it. Closes #7.
- The login task runs windowless too. The Windows installer used to register the logon task against the console sofacode.exe — a terminal parked on the desktop at every logon, and closing it killed the daemon until the next reboot. The task now runs through pythonw with no window at all, and restarts itself up to three times if the daemon crashes. If an earlier, elevated install left an old task that can’t be updated, the installer now says exactly that instead of pretending it succeeded. Closes #6.
- An unattended upgrade no longer switches the computer-mic bridge off. Run non-interactively with no answer given, the installer used to write audio.enabled=false over a working setup. No answer now means no change — an upgrade keeps the machine’s setting, a first install follows the daemon’s own default. Saying yes or no, by keyboard or SOFACODE_AUDIO, works as before. Closes #8.
- GitHub carries the full release now. Every release on GitHub gets the daemon tarball, the VS Code extension and a SHA256SUMS alongside the direct APK — and both installers fall back to those, checksums verified, when the download host is unreachable. The README’s version line is generated at release time so it can no longer drift from what shipped. Closes #9.
- The extension package dropped its bundled debug map — a quarter of the download nobody’s editor ever read (#10).
2.29.2App — daemon & extension 2.30.0 · SofaNode firmware 0.14.0 · Aug 2026
Answer the question, not just yes or no
- Questions are answerable now. When Claude asks you something, it used to arrive as one more Allow/Deny card: the options were never shown, and "Allow" agreed to a question nobody had read. The card now lays out the question, its options with the reasoning under each, and a box to type an answer of your own. Pick one — or several, where the question allows it — then Send answer. Don't answer is still there and still means what it says.
- Every screen you own. Both phones draw the same form. The Apple Watch and a Wear OS watch put one question on screen at a time as a list of options and answer it with a tap; there is no typing on a watch, so a written answer is the phone's job. The SofaNode's card reads QUESTION and a tap opens the option list — where a swipe up used to agree to a question with nothing in it.
- The deck's text box got the chat's buttons. A mic and a send icon, in the same places the chat composer puts them, doing the same things — the mic is your phone's speech-to-text, straight into the box.
- Fixed: on Android 16 the deck's text box stayed under the keyboard when you tapped it. The deck slides up now, the way it always has on iPhone.
2.30.0Daemon & extension — with app 2.29.2 · SofaNode firmware 0.14.0 · Aug 2026
A question is not a permission
- Questions reach your devices whole. Claude Code hands the daemon an AskUserQuestion on the same held-open permission hook as everything else, and the daemon now passes the questions, their options and each option's reasoning to every device — instead of a card whose one line read "questions".
- And the answers reach Claude Code. What you pick comes back inside the tool's own input, so the call succeeds with your answer in it rather than being denied with a note attached. Multi-select answers are joined the way Claude Code expects, an option no device was offered is dropped, and an empty form is never sent as consent.
- An older app or an un-updated node still gets a plain Allow/Deny for the same prompt, and a permission that is not a question is untouched.
2.29.1Daemon & extension — with app 2.28.3 · SofaNode firmware 0.13.0 · Aug 2026
The whole transcript on the wire, skills found where they live, nodes updated on command
- Transcript detail. A new sessions.chat_detail (default full) sends tool calls with their output — the first 400 characters — and up to 24 tools per turn, so the phone's chat and quick look can show what VS Code shows. reduced is the old shape; both are settable from the phone.
- Reads back. tts.read_scope — replies (default, exactly what it spoke before), replies and tools or everything — applies to spoken replies on a SofaNode and to "say last".
- Skills are found where Claude Code keeps them: your skills, the project's skills, project and user commands, and installed plugins' skills (from the plugin cache, prefixed with the plugin's name — not the marketplace's), plus Claude's built-ins; the list cap is 200. Codex and Copilot sessions get an honest empty list instead of Claude's.
- Approvals follow what you do in VS Code. Answer a permission prompt — or a plan, or a question — at the keyboard and the card clears on your phone, watch and node within a second, in every mode. It used to sit until the four-minute timeout, or forever if the daemon restarted first. The card comes down on three signals and nothing else: the editor closing the request, the tool actually running (an allow), or the transcript recording a refusal newer than the prompt (a deny). Ordinary work in the same session — a background subagent's tool call, the end of a turn, your next message — no longer counts, so a prompt you have not read yet stays on the phone. The daemon now also installs a PostToolUse hook for this; re-run the installer or sofacode install-hooks to pick it up.
- Secrets stay on the computer. The new tool output is withheld — the call still shows, its contents read [hidden] — when it read a key, a certificate, an .netrc. Build logs arrive as text, with terminal colour codes stripped rather than drawn as boxes.
- Tool output that arrives late still arrives. A tool that takes longer than a second used to show up with no output at all; its result now reaches the phone as soon as it is written.
- A repository you cloned cannot write your "/" menu. Skills reached through a symlink are skipped, and a skill or command whose name is not a name is never offered — the apps type that string into your editor. Claude's built-ins are always listed, even on a machine with 200 skills.
- Update a node from the computer: sofacode node update <id|all> (and POST /nodes/{id}/update) tells a connected SofaNode to check and flash now — no more tapping Menu → Update on each one.
2.28.3App — daemon & extension 2.29.1 · SofaNode firmware 0.13.0 · Aug 2026
The quick look reads along, and the deck explains itself
- The quick look follows the session live. It shows the aimed session's transcript as it streams, the way the chat screen does, pinned to the newest line while you are at the bottom; scroll up and it holds your place until you come back down. It walks 200 messages of history now, flicks, and a drag that starts inside it is always a scroll — never the deck's swipe. Tapping it no longer opens the chat (open session or a swipe up does), and the press outline is gone.
- The quick look shows the whole transcript, not a reduced one: user lines, replies with code blocks, tool calls with their output, thinking (when you have it on) and the task list, in the chat screen's own visual language. What gets read aloud does not change — replies only, as before — and a new Reads back setting (replies / replies and tools / everything) lets you widen it, on the phone's own speech and on the computer's.
- Skills, like VS Code. Type / at the start of a prompt and the machine's skills and commands appear above the composer without taking the keyboard — user, project, plugin and command skills, pulled from the computer you are aimed at. Tap one to insert it (nothing is sent), long-press to pick several and insert them together, star the ones you use; a Skills pill in the chat opens the same list with search. Type / then a space and the menu gets out of the way.
- The prompt box says Prompt. The old "tap the ring · speak · hold to send" hint is gone; while you dictate with nothing said yet, the red mic and a caret are the whole signal.
- ⓘ — tooltip mode. A small ⓘ at the bottom right of the deck. Tap it and every ordinary action is suspended: tap anything — the ring, a pill, a rail card, the box — for a one-line explanation of what it does; tap ⓘ again to leave. The spotlight tour has a step for it.
- iPhone reaches every paired computer from away. The iPhone app now dials through any paired gateway (a computer with its own tunnel) to reach the others, the way Android has since 2.24 — a second forwarded port per machine is no longer needed. A machine reached through a relay no longer writes the gateway's public address into its own LAN list (both platforms).
- Docs and tour describe the quick look, the prompt box and ⓘ.
2.28.2App — daemon & extension 2.29.0 · SofaNode firmware 0.12.1 · Aug 2026
A security round, and the deck stops wasting a strip
- Access codes are checked with a slow key derivation now. Both phones used a bare hash of the code, which is fine against a guess and not fine against a computer working through the shipped app offline. They now run PBKDF2-HMAC-SHA256 with a fixed app salt and 100,000 rounds — identical on Android and iPhone, proven by a shared test vector — and the App Review code was rotated with the change. Redeeming a code runs off the main thread; nothing else about codes changed.
- Every machine setting the daemon exposes is on the phone. The per-machine settings screen gained permissions (set the mode for Codex), Copilot (on/off, refresh interval, sessions listed, native submit), Codex (on/off, sessions listed), spoken replies (read new replies aloud, stop after N characters, wait after the mic) and the download filters (.env, checksum size cap). Settings the daemon keeps machine-only — dotfiles and secrets in downloads, the submit key, the two remote permission gates — are shown dimmed with a note, not hidden.
- The deck gives an empty strip back. The approve/deny slot under the response box only takes height while a permission prompt is actually waiting; the rest of the time the quick look gets it — on a Fold that was a visible blank band above the pill, and on a 360×640 phone it is the difference between a quick look and none. The session name was also printed a second time above the box; it isn't any more.
- Pairing sends the header daemon 2.29.0 asks for on tap-to-pair, claim and discovery, so the daemon can tell an app from a web page.
- The docs and the tour describe the deck as it is. The chat opens from the quick look, open session or a swipe up; a triple-tap or a swipe down clears the box; tapping the box types into it — and the rail's foot cell is called ACTIVE WINDOW everywhere, not THIS WINDOW. Chinese (Simplified and Traditional) caught up on every string that had only been in English.
2.29.0Daemon & extension — with app 2.28.2 · SofaNode firmware 0.12.1 · Aug 2026
The security round, desk side
- Nothing a phone sends can reach the keyboard as anything but keys. Keystroke combos are validated everywhere they can be set — the config file, the local API and a device's settings patch — as real key chords, and they may not name an xdotool command (that tool chains commands out of its own arguments, so a bare word like exec was an escape). The submit-key setting is machine-only now; the phone still shows it, dimmed.
- A device's class is bound to its token. Whether a credential belongs to an app or a node is recorded when it pairs and checked on every connection, so a node's token — which the owner can read off the node — can never buy the app-only remote terminal. Devices paired before this release keep working and are classed by what they say until they re-pair.
- The two switches that gate remote permission-mode changes are machine-only. They were settable by the very device they gate.
- Claude's permission hook carries the header the daemon requires. It never had, the daemon's CSRF gate answered it 403, and approvals only ever reached a phone through the notification fallback — answered by typing at the window. They arrive as real decisions now, applied to exactly the session that asked. Re-run the installer (or sofacode install-hooks) to pick it up. The Claude and Codex hooks also keep working when the local API is opened past loopback.
- Tap-to-pair takes a client header. Without it, a web page open in any browser on your LAN could pop a claimable pairing window on your screen. Apps and nodes from this round send it; older ones keep working for one release, with a line in the log.
- Smaller closes: config.toml (it holds tokens) is written owner-only; text handed to espeak-ng can no longer be read as options; machine capabilities and hostname go out only after a device authenticates; the button-event names a device sends are an allowlist; the extension's "Open Daemon Config" opens the file the daemon actually writes.
- The installers verify more. The VS Code extension is checksum-verified from the release manifest the same way the daemon tarball already was, and the daemon ships a pinned dependency list the installers use, so a fresh install gets the tested set.
2.28.1App — daemon & extension 2.28.0 · Aug 2026
The computer's mic bridge is optional
- A computer without the audio driver says so, and the deck adapts. Daemon 2.28.0 reports mic_off for a machine set up without the bridge (or whose driver is missing). The ring reads TAP TO DICTATE there: a tap dictates with your phone's own speech-to-text into the box under the ring (or opens the session with dictation already running, on a screen too short for the box), and nothing is billed for the tap itself. The open session pill is always shown on such a machine.
- Computer mic bridge switch, per machine. Under Settings › the machine's daemon settings. Off: the deck dictates on the phone; a SofaNode keeps chimes, spoken replies, sessions and approvals. On: the deck streams to the computer as before — the driver still has to be installed (re-run the installer with SOFACODE_AUDIO=yes), and the app tells you if it isn't.
- Onboarding and the in-app docs now describe what the installer actually does per platform, including that the audio driver is asked for, not assumed.
- Watch / Wear OS: a machine without the bridge shows NOTIFY ONLY — approvals, sessions and sending still work; dictation is on the phone.
- The ring sits higher, sized to a budget instead of a device. Up to 36% of the free height, clamped between 132 and 220 dp, so it reads the same size on a compact phone and a tablet. Its animated glow is clipped to its own band now, so it can't bleed into the preview or the box below it, and every label there uses a fixed font size across screen sizes instead of scaling with the screen.
- The quick-look preview and the response box now span the full width beside the session rail. The preview is a real scroller — drag it, grab the scrollbar thumb, newest message at the bottom, tap it to open that session. The box below it is 52 dp, and tapping it (not just the ring) opens the keyboard: type or edit in place, and it grows to three lines as you go. Dictation from the ring and typing both land in the same box; nothing is sent until you hold. There's no LISTENING word any more — a red mic glyph and the words appearing live are the signal, and the ring's own waveform shows what it's capturing. A triple-tap only ever clears the box; it never reaches the computer. On a screen too short for both, the preview drops first, then the box.
- The ring no longer streams your voice to the computer by default. A new Ring tap streams to the computer switch, off by default, under Settings › Speech brings the old wireless-mic path back when you want it; a SofaNode is unaffected either way, since its microphone still goes through the computer's mic bridge. The ring reads TAP TO DICTATE whenever it's dictating on the phone.
- “open chat” is now “open session” — the deck's pill, the tour, and the in-app docs.
- Fixed: ACTIVE WINDOW / ALL WINDOWS and MARK READ now fit the cap cell's real rounded corner (the earlier fix measured the wrong radius); a machine name long enough to crowd the REMOTE marker off a machine pill now ellipsizes instead, and the marker stays put; the aimed rail card's label no longer runs through its icons on short landscape screens; rapid ring taps can always stop dictation; holding to send with no reachable session keeps your words and sends nothing — and bills nothing; dictation requests reach the deck whichever screen is on top; re-opening the chat with a draft in progress keeps it; and reconnecting after a drop tries the last endpoint that worked first, which helps on remote links.
- Unread is legible now. MARK READ shows a count (MARK READ · 3), and the bell badge inside the ring pairs its number with a NEED YOU caption — both count the same thing.
- The daemon-update dialog knows which OS it's talking to. Since daemon 2.28.0 the daemon says whether it's on Windows, macOS or Linux, so the dialog shows that machine's exact update one-liner — Windows included, which used to get the bash command like everyone else — with a one-tap Copy update command.
2.28.0Daemon & extension — with app 2.28.1 · SofaNode firmware 0.12.0 · Aug 2026
The mic bridge stops being mandatory
- State reaches every phone and node, even over a flaky remote link. The daemon now remembers, per connection, which ring state (READY / WORKING / NEEDS YOU) and window it actually delivered, retries anything a dropped write lost, and re‑checks every ten seconds. Until now a working push that died on a half‑open tunnel socket was never resent, so a remote node or app could sit on READY through a whole turn. A repeated identical state is harmless — clients just repaint.
- Tests can no longer type on the developer's desktop. The daemon's test suite neutralises every keyboard injector by default; a test daemon with no editor attached is in keystroke mode, and two review repros had typed ctrl+d and ctrl+a BackSpace into a live editor.
- The installer asks now, instead of assuming. The computer's audio driver — BlackHole on macOS, pulseaudio-utils + PortAudio on Linux, VB-CABLE by hand on Windows — is optional and asked for, not installed on sight. Say no and nothing audio-related touches the machine; xdotool/wmctrl (prompt delivery and window focus, not audio) still install unconditionally on Linux either way. SOFACODE_AUDIO=yes or =no skips the question for a scripted install.
- A computer without the bridge stops being a dead end. The daemon used to start the mic stream anyway and let it stream into a void; now it refuses before the chime, tells the ring to stop, and a tap dictates with the phone's own speech-to-text instead — a SofaNode keeps its chimes, spoken replies, sessions and approvals either way.
- A "Computer mic bridge" switch, per machine, in Settings on both apps — flip it without reinstalling anything. The driver itself still needs a SOFACODE_AUDIO=yes re-run of the installer.
- sofacode config --set now works with the daemon stopped — it edits the saved config directly and applies at the next start, which is what the installer uses to remember your answer. sofacode devices also stops tracebacking on a machine with no audio backend at all.
- The SofaNode hides its Voice rows on a machine with no speech synthesiser, the same way it already hides the touchpad row on one with no pointer.
- The machine message now carries os — windows, darwin or linux — so the apps' daemon-update dialog can show the right install command instead of defaulting every machine to bash.
- The VS Code extension's update notice gained two buttons: Update now runs the installer in a dedicated terminal you can watch — typed passwords work, same as running it by hand — and Copy command puts it on the clipboard instead. The status-bar update badge runs the same update when clicked.
2.27.1Daemon & extension — with app 2.26.2 · Aug 2026
What you type into VS Code reaches the phone
- Messages typed while the assistant is busy show up in the chat. Newer Claude Code queues a message typed mid-turn and records it differently from one typed while idle; the daemon only read the idle kind, so a whole afternoon of instructions typed into VS Code was missing from the phone's transcript. Both kinds are read now. Nothing else changed in the extension; it moves with the daemon.
- The macOS installer stopped on its first line. Anyone who ran the install command from this site on a Mac got install.sh: line 36: DL_BASE?: unbound variable and nothing else. A variable name sat directly against an ellipsis, and macOS's C library counts the first byte of that character as a letter — so the shell looked for a variable that does not exist and gave up. Linux does not, which is why it was never seen here. Fixed, and the release now refuses to ship a script with that shape in it.
- The installers now tell you what they are going to do before they do it, per platform — what lands in your home folder, what asks for your password and why, what is installed with sudo on Linux, and what Windows does not do at all. Downloads retry instead of failing the whole install on one blip, and an unverifiable download is now refused outright rather than installed.
2.26.2App — daemon & extension 2.27.1 · Aug 2026
A way of unlocking the app without paying is closed
- A developer-only unlock could be switched on in a released build. The switch itself was never in the shipped app — but the setting it read was, so on a modified phone that value could be written by hand and the app stayed unlocked for good. Released builds now ignore it outright. Nothing changes if you subscribe, redeemed an access code, or are on the free trial.
2.26.1App — daemon & extension 2.27.1 · Aug 2026
Stop it talking, pin what matters
- Tap to stop the voice. While the deck reads a reply aloud, a tap on the ring cuts it off — the next tap is the ordinary press — and the SAY LAST cell reads STOP while it is speaking, so there are two ways to shut it up.
- Which session you are on, twice over. The aimed session's name sits inside the ring above the state word, and its card slides up to the top of the rail — ▲▼ slide the whole list to the next window.
- Pinned sessions. Hold a card for Pin to rail; pinned cards keep their place under the session you are on, with Move up / Move down to arrange them, while the rest still shift by recency. Pinned cards wear a ★.
- A card tap is a full switch. With the rail on ALL WINDOWS, tapping a session from another VS Code window switches the window pill (and the machine) with it, not only the name in the ring. The window picker's "Auto (follow focus)" row is gone — following the computer's focus is simply how the pill behaves; a manual pick holds until the focus moves, and only that hold is marked.
- The rail's foot reads ACTIVE WINDOW / ALL WINDOWS, two lines with the count. In active-window mode a ▲▼ pair above it steps through the machine's VS Code windows without opening the picker; in all-windows mode every card names its window instead.
- The session browser lists windows in name order, newest session first inside each, and archives in bulk: Archive… opens pick-the-rows (tick boxes, Select all / none, Archive N), archive everything older than N hours, or the old archive-all. The chat has a ← back to the deck.
- Quieter sounds. Every UI cue is struck rather than held, pitched lower, played at half the level; in Console every control has a figure of its own, and the working sound is a soft low run. The ring stops growing at 175 dp, so an unfolded Fold no longer draws a dinner plate.
- The iPhone tour can be finished. On the walk around the deck, the steps carrying a list of marks — the deck, the rail, what the marks mean, the sessions screen — grew taller than the phone, and Next and Skip were drawn off the bottom of the screen with no way to reach them: on a smaller iPhone the tour stopped dead on its second step. The card now keeps its title and both buttons on screen and scrolls its own middle instead, exactly as Android already did. The spotlight ring was drawn a notch too high on every step, too, and now sits on the control it is pointing at. The pin and the connection dot are taught on the window-pill and machine-pill steps, where they actually live, rather than crowded onto the marks page — which is how the phone app has always done it.
2.27.0Daemon & extension — with app 2.26.0 · SofaNode firmware 0.11.0 · Aug 2026
The desk finds out too
- VS Code says when SofaCode is behind. The daemon already checked every six hours and told the phones and the nodes; the person at the computer was the one surface it never told. Now the extension shows a notice — this daemon, the extension itself, the phone app, or a connected SofaNode's firmware, each with have → latest — with a link to what changed, and a small ⇧N badge on the SofaCode status-bar item until the stack is current. One notice per distinct answer, so you are not told twice.
- Read-only on purpose: VS Code can no more install a phone app or a node's firmware than the
node can. Turn it off with
sofacode.updateNotifications.
2.26.0App · SofaNode firmware 0.11.0 — daemon & extension 2.24.0 · Aug 2026 · the first SofaCode on the App Store, approved 30 Aug
Your sessions live on the deck, and the SofaNode wears the app's themes
- The left of the deck is a session rail. The sessions in the VS Code window you are aimed at, as solid colour blocks with the name and machine set upright in black — six colours per theme, the panel-computer look in every theme, not only Console. Tap a block to go straight into that session, scroll for the rest, tap ALL for the full browser, and MARK READ at the top to quiet everything that is waiting. Long-press a block to archive that session, long-press ALL to archive everything on the rail that is not running or waiting on you (the Sessions screen has an Archive all pill for the same job). It replaces the session button that used to sit at the bottom, and the rest of the deck re-centres beside it.
- It breathes in the colour of the need. A session blocked on you pulses its block in the attention colour, a broken one in the error colour; when the need is in a different window, the window pill breathes instead. Tap it and the windows are pill buttons, the needy ones tinted and counted — the machine picker is pill buttons too. The whole app draws the panel-computer way now — block rail, pill buttons, all-caps chrome — each theme in its own colours, Console in the classic ones, and the old elbow frame is gone. Each block shows its assistant and what it is doing: working blocks breathe; blocks waiting on you, failed, or finished-and-unread pulse in the colour of the reason.
- The needs-you count moved into the ring — a box with a number in it, the same one the SofaNode shows, and it does something now: each tap jumps to the next session waiting on you and counts down; once you have seen them all, a tap opens the list.
- A VOICE button on the deck. Switch it on and the phone reads the aimed session aloud the way the SofaNode does: the last three replies first, oldest to newest, then every new one as it lands — and while it is talking, the ring shows the node's bar waveform instead of the state word. Same switch as the speaker button in chat.
- The Sessions screen is a list again. One machine's sessions — the active one, switched from the bar at the top — as compact bars: a colour tab for the state, the title, one line of meta. The per-row permission box, the chip strip and the pinned duplicate are gone, and folders show their real names instead of the assistant's encoded keys.
- The watch deck is the node's deck. On a watch or any small screen: swipe left for the node's menu (Silent, Assistant, New session, Read aloud, Usage, Machines, Pair), swipe right to slide the session rail over the deck (again for the full list), hold a session for Follow / Allow / Deny / Permission mode / New session here / Archive, and swipe up or down to allow or deny while a prompt is waiting.
- A tour, a legend, and help that matches the app. The setup wizard covers microphone, computer and pairing; then the tour walks the deck itself — a spotlight on each control, what it does, what its marks mean. Run it again from Settings → App tour; Icon legend and How it works keep every mark and screen written up. Hold a session on the rail for its details and actions; the bottom rail cell switches between this window and all windows (hold it for the session browser); "say last" sits beside open chat.
- One machine at a time. Pick a machine and you see that machine's sessions and nothing else until you switch. Every list, count and chip now agrees on which computer you are driving.
- SofaNode firmware 0.11.0: the app's six themes, on the device. Ember, Ice, Matrix, Plasma, Volt and Console are now on the node too, under Menu → Theme — the whole palette, not just the ring. It replaces the old nine-swatch colour picker, and a node that had one of those colours keeps the closest theme to it.
2.25.1App — Google Play (the iPhone app caught up at 2.26.0) · daemon & extension 2.24.0 · SofaNode firmware 0.10.0 · Aug 2026
The panel theme is now called Console
- The theme with the elbow panels and the computer chirps is now called Console. Same colours, same chrome, same chirps — only the name changed, and if you had it selected it stays selected.
2.25.0App — Google Play (the iPhone app caught up at 2.26.0) · daemon & extension 2.24.0 · SofaNode firmware 0.10.0 · Aug 2026
The app opens again — and you can tell us things from inside it
- Fixed: the Android app would not open. Every install from Google Play since 2.19.2 closed on the splash screen or showed "this app has a bug". A mandatory flag added by Google's billing library in August was missing, and it threw before the first frame was drawn. Nothing was wrong with your device, your account or your subscription — updating to this version is the whole fix. iPhone was never affected.
- About → Support opens the real forms now. Report a bug asks for the versions, the steps and a screenshot — and if a SofaNode is involved, a second set of questions about the device: which part, how it was powered, how it was connected, and what the face was showing.
- Request a feature is new — for the apps, the watches, the desktop side or the SofaNode hardware itself. Tell us what you were trying to do and what it should do. Both buttons used to open the website's generic contact form.
2.24.0Daemon & extension · app 2.20.3 · SofaNode firmware 0.10.0 · Aug 2026
A quiet node stays honest
- Menu → Silent, firmware 0.10.0's first menu row: it mutes chimes, spoken replies and the volume blip on that node alone — the ring still flashes on a chime and the reply excerpt still toasts, so you can see something arrived without hearing it. Remembered across reboots; toggling it on mid-reply flushes whatever was buffered.
- A SofaNode in Silent gets no speech streamed to it, and when no node can hear, its followed session's replies are held as dots on the SESSIONS screen instead of being counted as heard — turn Silent off and tap Play. The node's Silent row is per node; the daemon's Voice switch is unchanged and still governs every device.
- An older daemon simply ignores a silent node's status and keeps streaming to it; the node stays quiet on its own end regardless.
2.23.0Daemon & extension · app 2.20.3 · SofaNode firmware 0.9.0 · Aug 2026
Start a session from the node
- New session from the SofaNode. Tap a session on the SESSIONS screen and pick "New session" to start a fresh one with that row's assistant, in that row's window; the main menu's "New session" starts one with the node's own assistant in the window the node is aimed at (the focused one when nothing is pinned). The node and the phones follow the new session as soon as it exists.
- Claude sessions are known the moment they open. A new
SessionStarthook registers the session before its first prompt, so the node lands on it right away (runsofacode install-hooksonce after updating). - A new session started from anywhere — the node or a phone — pulls the node onto it.
2.20.3App only · daemon & extension 2.23.0 · SofaNode firmware 0.9.0 · Aug 2026
The phones keep up with the node
- Sessions started from a node appear and are followed. A session the SofaNode starts shows up in the list and the app moves onto it, with a toast saying which node started it.
- Codex and Copilot rows show live state — working, needs you, ready — like Claude's.
- Clearer errors when a new session can't start: the window isn't open, it has no folder, or VS Code could not be focused.
- iOS: switching assistant with no session of that kind offers to start one, as Android already did.
- The Apple Watch has a real SofaCode app — Node mode on the wrist, embedded in the iOS build (on the App Store since 2.26.0). A permission card offers Allow/Deny for a tool call, swiping up to allow and down to deny exactly like the node; sessions group by VS Code window with a needs-you count, and a node-shaped menu covers Silent, Assistant, New session, Read aloud, Usage, Machines, Pair and your subscription status.
- The watch reconnects the moment you raise your wrist, releases the microphone when the app is suspended, and points you to subscribe on the iPhone app instead of tapping to nothing if you aren't subscribed yet.
- iPhone's deck swipe sides flip back to match Android and the node — swipe left for the menu, swipe right for sessions.
- The microphone onboarding step is one Continue button into the system prompt, with no skip, on both platforms; the iOS paywall's Terms of Use now links Apple's standard EULA.
2.22.0Daemon & extension only · app 2.20.2 · SofaNode firmware 0.8.1 · Aug 2026
READY means ready — for Claude, Codex and Copilot
- The node and the app said READY while the assistant was still working. A 40-second watchdog treated any pause in the transcript — a long think, a big file write, an agent run — as an interrupt and flipped every device to ready, then the next tool call flipped it back. Gone. A turn now ends only when the assistant says so, or when its own transcript shows it was stopped.
- Pressing Esc in Claude Code now shows on the node. Claude fires no hook on an interrupt; the daemon reads the interrupt marker from the transcript instead, so the ring goes calm within seconds rather than never.
- Copilot Chat has live state. Working, needs-you (a tool confirmation waiting) and ready now come from the chat journal VS Code keeps, so a Copilot session lights the deck and lists on the node like the others. VS Code writes that journal on its own timer, so Copilot can trail by up to a minute.
- Codex: aborted turns and hook-less runs. The rollout's own turn markers are read too, so a
codex execrun with no hooks installed shows working/ready and a stopped turn ends cleanly. - A closed window,
/clearor an exit ends its session's state (newSessionEndhook for both Claude and Codex — runsofacode install-hooksonce after updating).
2.21.1Daemon & extension only · app 2.20.2 · SofaNode firmware 0.8.1 · Aug 2026
More than one node, more than one phone
- An API voice start could target a phone. Whichever device linked last was "the device", so a phone reconnecting after a SofaNode (routine on mobile) received the start and streaming switched on with no microphone behind it. Physical devices are always the target now.
- A node that dropped and came back kept a dead transcript. If every node left and one returned while the same session was still in focus, the daemon never reopened its chat tail — transcript, tasks and read-aloud stayed blank on the node until desktop focus happened to move. Reopened on return now.
- Approval logs say which SofaNode answered when two share the name.
2.21.0Daemon & extension only · app 2.20.2 · SofaNode firmware 0.8.0 · Aug 2026
The node hears windows, approvals and modes
- SofaNode sessions are grouped by window, with each row carrying its own held approval, permission mode and provider — new session_action and session_mode verbs — instead of one flat list with no way to tell which window a session belonged to.
- Firmware 0.8.0 draws it: a dim > WINDOW header wherever the grouped rows change window, and the permission mode on plain rows. Tapping a row now opens an action list — Follow / Allow / Deny (when it's waiting on you) / Mode (Claude: cycle) / Play or Clear reply — and on the deck, a session waiting on you with no held card up answers straight to a swipe: up to allow, down to deny.
- Codex sessions reach the SofaNode for the first time; the phone apps are unchanged by this half.
2.20.2App only · daemon & extension 2.21.0 · SofaNode firmware 0.8.0 · Aug 2026
Tasks is a button in chat
- The task list is a button in chat now — the ☰ Tasks pill beside Stop, Mode and Compact. Swiping up on the transcript used to open it, and it opened by accident constantly; that gesture is gone. The SofaNode keeps its own gestures.
- Works with daemon and extension 2.21.0; SofaNode firmware 0.8.0 adds the node's per-session Allow / Deny / Mode list and groups its sessions by window.
2.20.1Daemon & extension only · app stays 2.20.0 · SofaNode firmware 0.7.7 · Aug 2026
Long-press send no longer leaves Claude dictating into nothing
- A SofaNode long-press could toggle Claude Code's dictation back on after the send, with no microphone behind it — that was the "Dictation error" toast in VS Code, and the node showing the stream off while the computer kept recording. The daemon now marks the ended dictation before it takes the microphone away, so the send stops it exactly once.
sofacode doctorreports whether the Codex hooks are installed and trusted.
2.20.0App, daemon & extension · SofaNode firmware 0.7.7 · Aug 2026
OpenAI Codex joins Claude Code and Copilot Chat
- OpenAI Codex is a third assistant, alongside Claude Code and Copilot Chat. Codex sessions — the CLI and the VS Code extension — appear in the session list with their own ⬡ glyph, stream live, and show token and context stats.
- Approve or deny a Codex tool call from your phone, watch or SofaNode, exactly like Claude: the daemon holds Codex's permission request open and answers it with your tap.
- The provider chip and the deck's rail cell now cycle through whichever assistants the linked machine actually has — a machine with Claude and Codex but no Copilot flips straight between those two.
- Permission modes cover Codex: a running Codex session reports its live mode, and the new-sessions default writes Codex's approval_policy + sandbox_mode. Modes Codex has no equivalent for say why.
- New session… offers OpenAI Codex where the machine supports it.
- Works with daemon and extension 2.20.0; SofaNode firmware 0.7.7 adds Codex to the node's ASSISTANT picker.
- Daemon & extension: Codex sessions are read from
~/.codex/sessions;sofacode install-hookswrites and pre-trusts~/.codex/hooks.json, so live state and approvals work without a "Trust all" prompt.sofacode doctorand/statussay whether the Codex hooks are installed and trusted. New[codex]config section.
2.19.9Daemon & extension only · app stays 2.19.8 · SofaNode firmware 0.7.4 · Aug 2026
Windows works again
- The daemon could not start on Windows at all in 2.19.8. A Linux-only module was imported unconditionally, so the login task died before it opened a port — and the installer still said Installed. Fixed.
sofacode paircrashed on Windows when its output went through a pipe (the pairing code and QR are drawn with block characters the console codepage can't encode). It prints UTF-8 now, and the log file is UTF-8 too.- Both installers check their work. They load the daemon right after installing it and confirm it is actually running before they say Installed; if it isn't, they say so and point at the bug-report page.
sofacode doctorgives the Windows PATH location on Windows, not the Linux one.- Versioning changes from here: the daemon and the extension move together, separately from the app, so a desktop-only fix never waits on two store reviews. App 2.19.8 works with daemon 2.19.9.
2.19.8App, daemon & extension · SofaNode firmware 0.7.4 · Aug 2026
Dictation tells you how to fix it, and a polish pass
- When dictation can't start, the app says why. If the device has no speech recognition, or the microphone permission was denied, pressing talk used to do nothing at all — it now tells you what is wrong and how to fix it.
- Every dialog matches the app. The confirmation and error dialogs used the stock system look; they now use the app's own theme, on both platforms.
- The buttons feel like buttons. They show a press and a focus state, have larger tap targets, and carry screen-reader labels.
- Onboarding lets you step back a screen and copy the install command, and the subscription screen shows what the yearly plan saves against paying monthly. Text contrast is clearer throughout.
- iPhone and iPad gained all of the same in this release.
- Security hardening in the daemon. A revoked device loses access immediately instead of keeping it until it next reconnects, and the remote terminal is limited to the phone app. The local API no longer returns its own secrets, and it rejects requests forged through a web browser.
2.19.7App, daemon & extension · SofaNode firmware 0.7.4 · Aug 2026
You can see what you're typing again on Android 16
- The keyboard covered the text box. On Android 16, opening the keyboard in chat hid the box you were typing into — you could not see a word of your own reply, and the one-tap canned replies and the context meter went under it too. Fixed.
- It was never only chat. The same fault hit every screen with a text field: the terminal, the code editor, the system prompt, saved prompts, projects, and both the remote-access and SofaNode setup screens. All eight are fixed in one place rather than one at a time.
- Why it started: Android 16 makes apps draw underneath the system bars and ignores the old opt-out, and that quietly stops the window from resizing itself for the keyboard. The app now measures the keyboard and makes room for it. Android 15 and older, and iOS, were never affected.
2.19.6App, daemon & extension · SofaNode firmware 0.7.4 · Aug 2026
The rim tells the truth again, and a dropped tap is gone for good
- The SofaNode's rim looks alive while it talks. Brightness had been pinned flat since colour landed, so only the bar length and hue moved — on ordinary speech that was barely visible. Length, hue and brightness now move together.
- Turning the rim to switch sessions no longer overshoots. One flick used to blow straight past three or four sessions on a six-item ring; picking one now takes a deliberate turn, and scrolling through the list is exactly as light as before.
- A dark screen stays dark. The node could relight itself the instant it started speaking, even when it should have stayed off in your pocket — only a genuine wake event turns the screen on now.
- Menu and sessions traded sides. Swipe LEFT opens the menu, swipe RIGHT opens sessions — one consistent direction on the node, the phone's Node mode and the watch.
- A tap on the SofaNode touchpad could be dropped for good on Linux desktops that accept but silently ignore synthetic clicks (wlroots-class Wayland compositors) — the pointer would move but a tap would never land as a click, indefinitely. Fixed daemon-side.
- Android's rim dial and the Apple Watch crown can roll backward through sessions and paired servers, not just forward, and Android gained a real Off for node speech instead of only ever being able to turn it on.
- The Apple Watch mirrors the phone properly now: chat, menu, sessions, and a live quota ring.
2.19.5App, daemon & extension · SofaNode firmware 0.7.3 · Aug 2026
Voice on Windows, the deck away from home, and a screen that stays on while you use it
- The SofaNode can drive your mouse. Switch on Touchpad in the node's menu and the screen becomes a trackpad for the computer it is paired with — drag to move, tap to click, hold for a right click, and turn the rim to scroll. It works on Wayland and X11 on Linux, on macOS and on Windows; the row only appears when the computer can actually move a pointer, so it is never a control that does nothing.
- Screensavers. After five idle minutes with nothing running, the node can fall into falling code, a slow psychedelic plasma, or a turning Metatron's Cube. Style and timing are yours, and any touch brings the deck straight back. On battery the screen still sleeps first — the screensaver is for a node that sits lit on the charger.
- Spoken replies queue instead of cutting each other off. Two replies landing together used to mean the first was chopped mid-word and lost. They now play in turn, and a session you were not watching keeps its last few replies so you can jump to it and hear what you missed.
- Six voices — American, English, Scottish and Northern English — downloaded on demand the first time you pick one.
- The node shows what your session limits are doing. A ring counts down to the next reset, with bars for the weekly limits underneath, read from the real figures rather than a guess.
- The SofaNode lasts far longer on battery. The radio now drops to modem-sleep whenever nothing is being spoken or dictated — it had been pinned fully awake at all times — the amplifier switches off during dictation instead of staying powered for the whole session, and the screen sleeps after a minute on battery while staying always-on whenever it's plugged in. Two states that used to spin the processor flat out while simply waiting for Wi-Fi now wait properly.
- The SofaNode's side button is now simply wake and lock. Press it to put the screen out, press it again to bring it back, each with a CRT-style animation. It used to double as a second tap surface — waking the screen on one press and toggling dictation on the next — so what it did depended on a state you could not see. The touchscreen is the control surface; holding the button still powers the node down.
- The SofaNode screen no longer switches off while you are using it. Touching the screen was what turned it off: the idle timer was read a fraction of a second before your touch was recorded, so the node concluded it had been sitting untouched for seven weeks and went dark on the spot.
- The screen-sleep setting now means what it says. "15 sec" turns the screen off fifteen seconds after you last touched it — it used to dim at fifteen and stay lit for another fifteen. Dictation, spoken replies and a waiting permission all hold the screen awake and reset the clock, instead of the timer running underneath them and the screen dying the moment they finish. Touching a dimmed screen brings it straight back.
- Tapping the notification count opens the session it points at. The bar sits close enough to the rim that an ordinary thumb tap could be read as a turn of the dial and scrub through sessions instead, and a slow press on it submitted the prompt. A press that stays put now belongs to the bar, however long you hold it.
- The node's settings menu shows what each setting is set to. "Charge lit", "Wake tap" and "Auto update" flipped silently behind a toast that vanished, so there was no way to tell whether stay-lit-on-the-charger was on. Each row now carries its current value, and toggling one keeps the menu open.
- Dictation starts from the app on Windows and macOS. Pressing talk streamed your voice but never turned Claude's dictation on — and pressing stop turned it on instead, so every press ran one step behind. Only Linux was unaffected. Reported by a beta tester with the fix already worked out.
- The deck reaches CONNECTED away from home. Over the internet it sat on LINKING… forever on both iPhone and Android, even though the computer had accepted the connection. Pressing it anyway still toggled dictation on the computer with nothing listening, which made it look like anything except a connection fault.
- Swiping around the chat no longer opens TASKS by accident. A quick sideways flick counted as a swipe up, so reading a transcript kept getting interrupted. A swipe now has to actually go up — the same rule the SofaNode uses.
- The TASKS screen can be opened on iPhone at all. It had been built, translated and dismissable, but nothing could reach it. Swipe up from the newest line, as on Android.
- The paywall quotes what your store will actually charge, in your own currency, instead of always saying $5/month.
- About → Open-source licenses lists the third-party components inside the app, with their licenses.
2.19.4App, daemon & extension · SofaNode firmware 0.6.5 · Aug 2026
The pairing prompt that would not go away
- "Link new machine?" could reappear forever on a machine you had already linked — and since that prompt deliberately cannot be dismissed by tapping outside it, the app sat stuck behind it.
- The cause was the button meant to dismiss it. Approving without typing a code — the normal thing to do for a machine that needs no token — saved an empty token over the working one. The computer then answered "you need to pair", which raised the same prompt again.
- Approving now updates the machine you already have rather than replacing it: an existing token survives a blank box, and the other addresses that machine answers on (a second Wi-Fi address, a VPN hostname) are kept instead of being thrown away.
2.19.3App, daemon & extension · SofaNode firmware 0.6.5 · Aug 2026
Answer it on the computer and everything else stops asking
- Clicking into a session on your computer clears its notification everywhere. The Node stops saying NEEDS YOU, the phone's banner goes away, and any reply that session was holding for you is dropped — you're reading it on screen. Nothing about the session changes: it still shows as waiting in the sessions list, because it still is. Move between the Node, your phone and your desk without dismissing the same thing three times.
- It re-arms by itself. The mark only covers the moment you looked; the next time that session needs you, it says so again.
- One notification rectangle above SOFANODE on the deck, replacing the corner badge and the edge pip. It counts sessions blocked on you and sessions holding a reply you haven't heard — amber while something is blocked, ember when all that's left is audio. Tap it to jump to the next one and watch the count fall; once you've seen them all, the next tap opens the SESSIONS list. Viewing that list by any route clears the count.
- The Node's SESSIONS screen is a real picker now: every session that's actually doing something always appears, plus your recent ones — up to five per window, nothing older than a day — so you can jump back into a session that has been quiet for an hour without hunting for it.
- Firmware 0.6.5 and a lockstep daemon, extension and app bump.
2.19.2App, daemon & extension · SofaNode firmware 0.6.4 · Aug 2026
The Node stops reading one session and forgetting the rest
- Picking a session on the Node's SESSIONS screen now actually follows that session. It used to aim at the session's window, and several sessions can share one VS Code window — a repo and a subfolder of it are two working directories behind one open folder — so the tap landed on whichever of them had written to disk last. With three agents running in one window, that was the whole "it only ever reads one of them" problem.
- The Node also stops drifting between sessions on its own. Sibling sessions in one window are ordered by a whole-second timestamp, re-read every three seconds, so the one being followed used to flip at random — which clears the dial and swallows the very reply that caused the flip, because a transcript re-read from the top is history, and history is never read aloud.
- New: a session that finishes while you're listening to another one keeps its last reply. It raises a pip on the SESSIONS screen and a count on the left edge of the deck — swipe left, tap to hear it, tap again to clear it. Nothing plays on its own; twelve agents talking over each other is exactly what this replaces. If that session speaks again, the pip lights again.
- Hold on a session to switch to it whether or not it has something to say. Read-aloud still follows the one session you're on, and the pip never appears on a machine with no voice installed.
- Firmware 0.6.3/0.6.4: the WORKING ring's comet stops drawing sky blue, the rim dial can finally roll past the end to the next paired machine (the message it needed was never being sent), a permission card no longer survives a dropped link — it used to sit at "0s left" eating every gesture and holding the screen awake until the battery died — and rim turns made while offline no longer replay as a burst on reconnect.
- Every SofaNode now includes 6 months of SofaCode free — a 6-month subscription code for Google Play or the App Store arrives with the order confirmation.
- The remote-access command line stops trapping people: a tunnel token set with config --set now survives a restart, remote gateway on is no longer undone by the next remote start, and the setup walkthrough no longer recommends the Cloudflare Access step that locked your own devices out.
2.19.1App, daemon & extension · SofaNode firmware 0.6.2 · Aug 2026
The SofaNode's battery tells the truth now
- The charge bolt stayed lit when the Node was off the charger. The charge-status pin was being read with the wrong polarity and with an internal pull-up the board fights, so "no charger" read as "charging" — and with stay-lit-while-charging on, the screen never slept, which slowed the actual charge as well.
- The battery gauge could never reach 100%. It was computed in millivolts against an assumed 2:1 divider; a full pack came out somewhere in the 40-65% range, and a nearly empty one dropped off the display entirely. It now uses the calibration curve the hardware was built with, in raw ADC counts, averaged over eight samples.
- Battery and charge state are sampled independently of the link to your computer, so a Node that goes offline no longer freezes its gauge at whatever was last true.
- A connected Node reports battery, charging and the raw sensor values behind them to GET /status — enough to tell a bad reading from a bad wire without a serial cable.
2.19.0App, daemon & extension · Aug 2026
Subscriptions on iPhone
- The iPhone app sells the same subscription as Android: 7 days free, then $5/month or $50/year, billed by the App Store.
- Your subscription follows your Apple ID — Restore purchases brings it back after a reinstall or onto a second device, and Manage subscription opens Apple's own sheet.
- Entitlement is read from the store on every launch and every time the app comes forward, so a lapsed, refunded or cancelled plan locks itself correctly on both platforms.
2.18.0App, daemon & extension · Aug 2026
One app on two phones
- The iOS app now matches Android screen for screen — same colours, spacing, deck typeface and app icon. The default Ember theme had drifted on iOS, right down to the deck's state colours.
- The deck's swipes match again: up for chat, down to clear, right for the menu, left for the session picker. The chat microphone is the phone's own dictation on both.
- Layouts hold up on small screens and big ones, and iOS text now follows the system text-size setting.
- Remote access setup is on iOS, and the SofaNode is documented in-app on both platforms.
2.17.0App, daemon, extension & firmware 0.6.0 · Aug 2026
The SofaNode sets itself up — and keeps itself current
- Node setup is now: set up the app, then Settings → Set up a SofaNode. A freshly flashed Node shows a QR the moment it joins Wi-Fi — scan it, and every machine the app knows, LAN addresses and remote/WAN domains alike, gets pushed to the Node at once, each with its own freshly issued, independently revocable token. No node-side setup screens, nothing to type.
- The old node-side 8-digit flow isn't gone — it's Pair by code in the Node's menu now, for whenever a camera isn't handy.
- SofaNode OTA: firmware checks for updates at boot, offers Check update from the menu on demand, and flashes itself over the air — sha256 and size verified before anything touches flash, and it only ever moves to a strictly newer build. Auto-update is on by default; toggle it off if you'd rather do it by hand.
2.16.5App, daemon & extension · Aug 2026
Dictation errors fixed at the root, one deck everywhere
- The recurring “Dictation error / WebSocket error”: SofaCode's own dictation watchdog could tear down a live voice stream it merely failed to detect. It now acts only on a dictation it actually saw start and then end — a blind spot does nothing.
- Deck swipes now mirror the SofaNode on every deck: up = chat (up again = tasks), down = clear input, left = sessions, right = menu. Switching machines moved to a tap on the machine pill.
- The machine-connected dot is green again — “linked” is a different signal than the agent's orange “ready”.
2.16.4App, daemon & extension · Aug 2026
Voice that stays in sync
- The daemon now observes Claude's real dictation state on the machine instead of trusting a blind toggle counter, so the app, node and editor can no longer drift out of phase — and no device shows LIVE against a mic nobody hears.
- The chat box mic is now your phone's own speech-to-text, typing into the input field; the wireless voice mode lives on the deck where it belongs.
- Session attention everywhere: the node gains a SESSIONS screen (states, needs-you first, tap to switch), and finished-in-the-background gets its own chime, distinct from the session you're watching.
- The app's EMBER theme is retuned to the SofaNode's warm orange palette with matched ring animations — the app deck and the hardware deck read as one product.
2.16.3App, daemon & extension · Aug 2026
Connect at home once, roam forever
- Devices paired before remote access existed never learned the way in from outside and rotated LAN addresses forever. The daemon now hands the remote endpoint to every device on every connect — pair at home once and roaming just works.
- iOS catches up on remote access: wss endpoints, certificate pinning, and the same no-cleartext-over-WAN policy as Android.
2.16.2App — daemon, extension & firmware unchanged since 2.16.1 · Aug 2026
The task list, on Android too
- Fling up a second time and the tasks fill the screen. The node's second swipe-up level is now on every Android face — watch node mode included, since the watch is the node in software. An upward fling in the chat, while you're following the newest line, opens a full-screen TASKS view of the session's current list: running task bold, done struck through, updating live while it's open. Swipe down or back returns to the chat, and the gesture only fires at the bottom of the transcript, so reading history is never hijacked by an accidental fling.
2.16.1App, daemon, extension & firmware 0.3.1 · Aug 2026
The task list reaches the node
- The SofaNode gets its own TASKS screen. The daemon already pulled the running task list out of session transcripts for the app's chat; it now pushes the same compact list to the node too — on a follow-focus switch, on connect, and whenever the list changes — so fling up in the chat (swipe up again on the node) to watch tasks tick off in real time. The phone keeps its richer inline rendering inside the chat transcript; the node's screen carries the same information, sized for its display.
2.16.0App, daemon & extension · Aug 2026
One token per device
- Every device now pairs with its own token instead of a shared one, so a lost phone is revoked alone — sofacode paired revoke — without re-pairing the fleet.
- Plus a full adversarial security review's worth of hardening across the daemon, apps and firmware, including a master switch that disables the remote terminal entirely (terminal.enabled) which the phone itself cannot switch back on.
2.15.xApp, daemon, extension & firmware · Aug 2026
The SofaNode era — and remote access
- SofaNode grows into a peer of the app: spoken replies (pick the voice), chat and approvals on the dial, pairing to new machines by dialing the 8-digit code — no cable — up to six machines, Wi-Fi onboarding, and a browser web flasher that updates firmware, sets up Wi-Fi and timezone from Chrome.
- Node mode lands on Android: the stripped-down circular node deck for watches and small screens, auto-on for watch-class displays. The Apple Watch node deck is written and inbound.
- Remote access (off by default): one encrypted endpoint through a Cloudflare tunnel or direct TLS with certificate pinning; pairing stays LAN-only and a token never crosses the internet. A gateway machine can relay to every other daemon on your LAN through a single door.
- Spoken replies default on, wait politely until you stop talking, and can be interrupted with a tap. Plus dozens of voice-reliability fixes.
2.14.0App & daemon · Aug 2026
A HUD in your glasses
- Plug USB-C AR glasses into your Android phone and your busiest sessions tile into a heads-up display — up to four at once, most urgent first, each showing the recent back-and-forth, with a pulsing banner when one needs you.
- Any DP-alt-mode glasses work, not one brand — the HUD is a plain second display through Android's stock Presentation API, so XREAL, Rokid, Viture and TCL all drive it with no vendor SDK. The panel floats with a dead-zone, spring-damped follow as you turn your head, and eases back to centre as you settle rather than pinning itself to your exact gaze.
- The SofaNode's dial follows your computer's focus: whichever VS Code window has the keyboard, the ring shows that session's state.
2.13.0App, daemon & extension · Aug 2026
Multi-root workspaces stop being invisible
- Multi-root .code-workspace windows could never receive a prompt — the window reported its workspace file, not its folders. The extension now reports every workspace folder and the daemon routes to the deepest match.
- A mapped drive and its UNC path (U:\docker vs \\server\docker) are one directory with two spellings; both sides now canonicalise before comparing, so Windows network-drive setups route correctly.
2.12.3App, daemon & extension · Jul 2026
Voice button stays in sync
- The app's voice button could invert if you toggled Claude Code's own dictation by hand in the editor (its mic button / Ctrl+D) — a toggle SofaCode can't see. The daemon now tells the extension the intended state on every start, so the app, daemon and extension stay in agreement and the button no longer does the opposite of what you press. (Claude Code's dictation is a blind toggle with no readable state, so a manual mic-button press in the editor can still flip Claude's own listening once — use the app's button, not the editor's, to stay in sync.) Also: the submit key (Enter vs Ctrl+Enter) can be changed per machine from Settings.
2.12.2App, daemon & extension · Jul 2026
Quiet the reconnect chime
- Moving between WiFi and cell used to play the connection sound on every hop. Settings › Sound gains a switch to turn the connection sound off on its own, and a reconnect quiet period that stops it repeating for a while after connecting (default 1 minute, off to 5 minutes). Per device.
2.12.1App, daemon & extension · Jul 2026
中文,每一個畫面
- Finishes the Chinese localization from 2.12.0 — every remaining screen (permissions, per-machine config, approvals, projects, saved prompts, stats, usage, docs, onboarding, about) in Traditional (Hong Kong) and Simplified, with permission-mode names and descriptions translated at the source so no English clause is left inside a Chinese sentence.
2.12.0App, daemon & extension · Jul 2026
繁體中文 · 简体中文
- The app speaks Chinese — Traditional (Hong Kong) and Simplified, over 1,300 strings across every screen. Pick it in Settings, or let it follow your phone.
- New “Assistant replies in” setting. Claude Code and Copilot already answer in whatever language you write to them, so it is off by default — turn it on to write Chinese about an English codebase and still get Chinese back. It adds one line to your message; nothing is machine-translated in between.
- The bottom “Talk to” pill lists only the sessions belonging to the selected server and window — server, window, session, in that order.
- Submit key is now an app setting: Enter or Ctrl+Enter, matching whatever you rebound Claude Code's send to.
2.11.1App, daemon & extension · Jul 2026
Long press sends again
- Long press to send did nothing when the computer's display session had changed under the daemon (an RDP reconnect renumbers displays; the service kept typing at a dead one). The daemon now finds the live display that actually hosts your VS Code windows by itself, re-checks whenever a keystroke fails, and heals without a restart.
2.11.0App, daemon & extension · Jul 2026
Tap to pair
- Pairing is two taps and a camera point now. Tap a discovered machine in Machines and its pairing QR pops up on that computer's screen; the app opens the scanner for you. The code still never leaves the computer — you scan it off that screen — so nothing about the trust model changed, only the walking. Machines that don't want this can turn it off (
pairing.remote_open). - The installer puts a “Pair SofaCode” shortcut on the desktop, so opening a pairing window later never requires remembering a terminal command.
2.10.1App, daemon & extension · Jul 2026
The phantom dictation toasts
- Voice input worked, but VS Code sometimes showed “Dictation error: no audio detected” — and “WebSocket error” in a second window. Claude Code's dictation is a blind toggle, and SofaCode's stop signals could land in a window that wasn't dictating, switching a phantom dictation ON onto a microphone nobody was feeding. Stops are now guarded — only a window whose own dictation is running ever acts on one — so the phantoms, and their error toasts, are gone.
2.10.0App, daemon & extension · Jul 2026
Never lose the stream, follow every server
- A chat you are reading never freezes again. Clicking out of a VS Code window on the computer used to silently stop that conversation updating on the phone. Aiming and subscribing are separate now: the open chat owns its own stream and jumps with the focus instead of losing it.
- Follow-focus works across all your servers. Click between VS Code windows on two different machines and the app switches server, window and session with you — the window you touched last wins, wherever it is. Manual picks still pin the app until you touch a computer again, and attention bubbles keep every other server's sessions one tap away, in chat as well as on the deck.
- A context meter sits under the chat input: how full this session's window is, 0–100% against the model's real limit (1M models included). Amber past 80%, red past 95% — tap it for the full stats.
- The deck's chat button is sized to the pair of buttons under it instead of spanning the whole tablet.
- The iOS app compiles and runs on hardware for the first time, catches up with the 2.9 deck, and lands a wide parity pass with Android — same screens, same controls, same behaviour.
2.9.0App, daemon & extension · Jul 2026
Follow your computer's focus, and a cleaner deck
- The app now follows your computer. Whichever VS Code window you click into on a server becomes the active chat on your phone — move between windows on the computer and the app moves with you, no tapping. Pick a session or window on the phone and it holds there until you focus a window on the computer again, which takes back over. Only the server you have selected is followed; switching server stays your choice.
- The deck is rearranged. Chat is now a full-width button on its own row — the thing you reach for most is the easiest to hit. The VS Code window is a small pill right under the server name, the session is the pill at the bottom, and the smaller buttons are tidied to one row.
- Tapping the session pill shows sessions and nothing else. The server is the pill up top, the window is its own pill — so the session picker stopped repeating both. Windows and sessions everywhere are scoped to the server you have selected.
- Chat has one-tap “continue” and “try again” replies, so the two answers you give an agent most often don't need the keyboard.
2.8.8App, daemon & extension · Jul 2026
Windows delivery, and same-named folders
- Windows: prompts went to whatever app was in front instead of VS Code. The daemon never brought the editor window forward on Windows at all — that step was written for Linux and silently did nothing everywhere else — and it could not check which window had the keyboard either, so it typed regardless. Approving from the phone never worked there for the same reason.
- The VS Code extension is now installed by the installer. It was always required — a prompt goes to a session's WINDOW, and the daemon only knows a window exists once its extension connects — but installing it was a manual step that was never written down, so a new machine could pair perfectly and never deliver a word. Reload VS Code once after updating.
- Two projects whose folders end in the same word (~/work/api and ~/side/api) now both work. They looked identical to SofaCode before, so a prompt could land in the wrong one. Windows are told apart by their full folder, and the editor window itself confirms it is in front before anything is typed.
- sofacode doctor now checks the things that actually stop a prompt: whether a VS Code window is connected, whether this machine can type at all, and whether it can bring a window forward.
2.8.7App, daemon & extension · Jul 2026
A prompt could land in the wrong project
- A prompt could be typed into the wrong project. Two VS Code windows whose folders end in the same word — ~/work/api and ~/side/api — looked identical to SofaCode, which knew each window only by that last word. A session in one of them resolved to whichever window you were looking at, and every safety check agreed, because they all compared the same word. Windows are now told apart by their full folder, and where keystrokes still cannot be aimed at exactly one window, nothing is sent and the app says why.
2.8.6App, daemon & extension · Jul 2026
Upgraded machines were stuck on the old release channel
- Machines upgraded from the old name kept checking a release address that no longer exists. The rename preserves your existing settings on purpose — that is what keeps your devices paired — but it carried the old update address along with them. The check failed every time, the daemon fell back to the last answer it had, and the machine went on advertising an ancient version however new it really was. The address is now corrected automatically on startup.
2.8.5App, daemon & extension · Jul 2026
A Windows installer that runs, and the extension's version
- Windows install fixed. A
??had crept intoinstall.ps1. That operator is PowerShell 7 only and Windows ships 5.1, where an unknown operator is a parse error — so the whole script died before its first line ran and a stock Windows machine got red text and no install. It also now forces TLS 1.2 (5.1 negotiates 1.0 by default, which the download host refuses) and spots the Microsoft Storepython.exestub instead of failing later with an unrelated error. - Settings shows the VS Code extension's version alongside the app and daemon — the one piece of the stack whose version nothing ever reported.
2.8.4App, daemon & extension · Jul 2026
Settings on the deck, and the right daemon version
- Settings is reachable straight from the talk screen — the gear beside the machine name. It used to be two taps down inside the machine picker.
- The daemon version in Settings showed whichever machine reported last rather than the one you are using, so with several machines paired the number could change to one from a machine you weren't looking at. It now follows the active machine.
2.8.3App, daemon & extension · Jul 2026
The daemon version you saw was its own stale cache
- A machine could report an old daemon version long after it had been upgraded, and every app connected to it showed the same wrong number. The daemon was reading its own version out of a saved update check written by an older build — and nothing ever corrected it, because an update check tells you what is available, never what you are running.
- It now reports the version it is actually running, always.
- The app, the daemon and the VS Code extension share one version number from here on, so a mismatched set is obvious at a glance.
2.8.2App, daemon & extension · Jul 2026
A tidier download host
- The one-line installers moved to a per-product path —
dl.codedatda.casa/sofacode/install.shand/sofacode/install.ps1— so more of our apps can ship from the same download host. Update any bookmarked command; already-installed machines keep updating themselves. - The Android app is now handed out through GitHub releases rather than this site, while it's in private beta and on its way to Google Play. Ask for early access and we'll send you the link.
2.8.1App & daemon · Jul 2026
Pairing that actually connects
- Pairing now works on machines with more than one network — the QR carries every LAN address and the app tries each, so a phone on a different subnet than the computer's main one still connects.
- The pairing window (code + QR) pops up on the computer automatically when a new device tries to connect — no need to run
sofacode pairfirst. - The installer opens the firewall for the daemon (Windows Defender, Linux firewalld/ufw, macOS) — the most common reason a phone couldn't reach the computer.
- Clearer connection errors: firewall vs. wrong-network / AP isolation vs. bad address, instead of one catch-all line.
- Terminal output no longer shows raw shell escape-code garbage.
2.8.0App & daemon · Jul 2026
New name: SofaCode — plus Claude usage & chat fixes
- CouchCode is now SofaCode. Same product, new name and a new home here at sofacode.codedatda.casa. Existing users re-pair their devices once.
- Claude usage: token spend and estimated cost across your sessions — today, this week, all time, broken down by model.
- Tapping an attention bubble opens that conversation directly; the chat now shows bubbles for other sessions that need you.
- Long-press a message to read it — and everything after it — aloud.
- Auto-scroll follows the reply while it streams, and holds your place when you scroll back.
2.7.0App · Jul 2026
Terms up front, and an About screen that says something
- A first-run Terms & Privacy gate, shown once before onboarding or anything else starts — accept it or the app closes.
- About is rebuilt. App and daemon versions, an in-app What's New that mirrors this changelog, a link to the guide and to Terms & Privacy, and Report-a-bug / Contact links straight to the website's forms.
- Opt-in debug logging. A toggle captures only this app's own log to a file on the device — off by default, never uploaded on its own — with Export to attach it to a bug report and Clear to wipe it.
2.6.0App & daemon · Jul 2026
Deck rework, cross-session alerts, shell-grade terminal
- Reworked the voice deck: machine on top, and a clean provider · window · session · new rail — pick Claude or Copilot right there, and it filters the sessions.
- Cross-session attention bubbles: when a session on another machine needs you or finishes, it pops up as a tappable chip — one tap switches to it.
- Pinning that sticks: starred sessions get their own section at the top of the list and lead the deck picker.
- Terminal now feels like a shell — a live working-directory prompt, command history, and a Ctrl-C interrupt.
- Move and rename files right in the in-app explorer.
2.5.0Jul 2026
Payments & polish
- Settled pricing: 50 free chat interactions, then $5/month or $50/year. A chat interaction is a message actually sent to an assistant, typed or voice — slash commands and terminal commands never count, and typing without sending bills nothing. Typed prompts now count and gate exactly like starting the mic, closing a gap where they used to be free.
- Photo and file transfers both directions.
- A Play-compliant build flavor. The app now builds two ways: the direct download keeps the self-updater and the "Get the app" nagging; the Play flavor compiles that out entirely, since steering Play users to a sideloaded APK is a store-policy violation. Daemon-update hints stay in both — the daemon is desktop software Play has no claim over.
2.4.xJul 2026
Routing safety & live terminal
- A prompt can no longer land in the wrong window — or the wrong app entirely. Prompts, terminal commands and approvals that name a session now route through one resolver, focus is verified before a single key is sent, and a request that can't be routed is refused with a real message instead of typed into whatever had focus.
- Live terminal output over VS Code's shell integration, with exit codes and working directory, plus favorite commands with cross-platform import/export.
- The deck is rebuilt on a band allocator — labelled server/window/session/new/chat cells with no overlapping hit targets — and sessions split the overloaded pin into last-viewed plus starred favorites, with auto-archive for the rest.
- 2.4.1: the intermittent "Dictation error" toast, run to ground four ways — Claude's dictation could start before the virtual mic was fed, never stopped when the phone's connection dropped mid-sentence, and could be toggled from the wrong window. Dictation now starts only once the first audio frame arrives, survives a brief reconnect, and stops only in the window that owns it.
- Launch-readiness pass: onboarding scrolls on small screens and asks for notification permission, session switches stop stacking chat screens, two phones can no longer interleave keystrokes into the same prompt, and deny-on-timeout honors its setting.