Repository navigation
Conversation
Typing /btw <question> in a Claude chat sent it to Claude as an ordinary message, and Claude Code replied "/btw isn't available in this environment": it runs the command only in its terminal UI (slopus#1226). The SDK offers the same feature as the side_question control request. Claude answers once from the live conversation, with no tools, nothing is written to the transcript, and it is served while a turn is running. The CLI now registers a side-question session RPC that hands the question to the running query. Query.askSideQuestion ships in the SDK runtime but is missing from its public typings (checked through 0.3.286), so it is typeof-gated like the usage seed. The server gives up on an RPC after 30 seconds, and an answer over a long conversation can take longer, so no single RPC waits for the whole answer: `ask` starts the question and waits up to 20 seconds, `wait` picks it up again with the returned id, and `cancel` drops it. A question nobody collects is dropped after 10 minutes. When Claude is running in the terminal, or no Claude process has started yet, the RPC says so and the app explains it instead of failing. In the app, /btw in a Claude chat no longer becomes a message. It opens a sheet that shows the answer, takes follow-ups (sent with the earlier exchanges as history, as Claude Code's own panel does), and is gone when closed. /btw is listed among the slash suggestions for Claude chats. A CLI from before this change answers "RPC method not available", and the sheet asks for it to be updated. Fixes slopus#1226 Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
A session keeps running the CLI it was started with, so after a CLI update every session already open still lacks the side-question RPC. /btw there said only to update the CLI, which does nothing for someone who just did. The message now says to restart the session as well. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
The /btw answer lived in a modal sheet, so whatever took the sheet away took the thread with it. On a wide screen a tap on the session list behind the sheet landed on its backdrop and closed it; on a phone Back did the same. Closing cancelled the question still being answered, and coming back to the chat found nothing. The thread now lives outside the screen, one per chat, in memory (sync/sideQuestionThreads.ts). Leaving the chat, for the list or for another chat, keeps the question running and its answer lands in the thread; the chat shows the thread again on the way back. Only the panel's close button ends it. The sheet becomes a panel over the top of the chat instead of a modal, so the session list, the chat and its composer stay usable while it is open. It is opaque where there is no blur, since the chat now sits right behind it, and takes at most 60% of the room below its top, less the keyboard. With the composer usable, /btw can now arrive while an answer is still coming. A thread answers one question at a time: a later one waits its turn and is then asked with the earlier answer in its history, as a follow-up is, so the panel's send button no longer has to be disabled in the meantime. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Follow-up commit: the /btw thread survives leaving the chatUsing this on my own build turned up a gap. The answer lived in a modal sheet, so whatever took the sheet away took the thread with it: on a wide screen a tap on the session list behind the sheet landed on its backdrop and closed it, and on a phone Back did the same. Closing cancelled the question still being answered, and coming back to the chat found nothing. 783c987 keeps the thread outside the screen, one per chat in memory ( Web, through the session list (the answer reached the app 7.6 s after leaving): Android emulator, x86_64 debug build, through Back (answer 12 s after leaving; with the keyboard up the panel shrinks and keeps its field visible): Re-verified on this head: app typecheck clean, the side-question tests plus the new |
A /btw with no question opened an empty side panel with its field focused. Claude Code replies "Usage: /btw <your question>" instead and asks nothing (checked in Claude Code 2.1.301), so the app now does the same: the line shows in the chat as a notice that stays on this device, never sent to the agent or the server (sync.showLocalNotice), and no panel opens. The panel's focus request and its empty-thread placeholder had no other use and are gone. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Follow-up commit: a bare /btw answers with its usage4783bd2 matches Claude Code for Live run on a local stack with a paired daemon: a bare |
Claude Code's /btw panel copies the answer with `c`, so it can go into the main conversation; in Claude Code 2.1.301 that is the answer alone, without the question. The side panel now does the same: each answer carries the copy button the chat's own messages use, which copies the answer text and shows a tick for a moment. A canned stand-in answer has none. MessageCopyButton is exported from MessageView for this. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Follow-up commit: copy a /btw answer into the chat8c3acd1 adds what Claude Code's panel offers as Live run on a local stack with a paired daemon and real Claude (8/8 checks): |
"Answered from this chat — nothing here is added to it." left the reader to work out what "it" was. The subtitle now says it outright: "Claude answers from this chat. Nothing asked or answered here appears in the chat." The other languages already named the chat and are unchanged. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
Withdrawn: continue a /btw question in a new sessionRemoved from this PR: the button's commit and its revert cancelled each other out, so a force-push dropped both, and the branch is back at 7b46adb with the same code as before the button. The button forked the chat into a new session, which is not what Claude Code's |
441e4c1 to
7b46adb
Compare
|
The failing |




Fixes #1226.
/btw <question>in a Claude chat now opens a panel with Claude's answer instead of reaching Claude as an ordinary message, where Claude Code replies "/btw isn't available in this environment" because it runs that command only in its terminal UI. The SDK offers the same feature as theside_questioncontrol request — Claude answers once from the live conversation, with no tools, nothing is written to the transcript, and it works while a turn is running — so the CLI registers aside-questionsession RPC that hands the question to the running query, and the app intercepts/btwin Claude chats and shows the answer in a panel over the top of the chat that takes follow-ups (sent with the earlier exchanges, as Claude Code's own panel does). The panel leaves the rest of the screen usable, and the thread is kept per chat outside the screen: leaving the chat for the session list or another chat keeps the question running, the chat shows the thread again on the way back, and closing the panel ends it with nothing left behind. A bare/btwanswers with its usage in the chat, as Claude Code does, and opens nothing. Each answer has a copy button that copies the answer alone, ascdoes in Claude Code's panel, to paste into the chat./btwis also listed among the slash suggestions for Claude chats.Proof
The thread survives leaving the chat, on web through the session list and on Android through Back, including an answer that arrived while another chat was on screen:
Both are live runs on a local stack (standalone server, a happy-cli daemon and real Claude), the first in Expo web and the second on an Android emulator (x86_64 debug build) against the same server. On web,
/btwgoes out in one chat, a click on another chat in the session list leaves while Claude is answering, and the CLI log has the answer 7.6 s later, with oneside-questioncall per question, so nothing was cancelled on the way out. On Android a follow-up from the panel's field was answered 12 s after Back took the app to the list. A scripted run of 25 checks covers both widths on web, and that a closed panel stays closed when the chat is opened again.Answered mid-turn, with a follow-up, and nothing left in the chat (captured with the first commit, when the thread still sat in a modal sheet):
The first message gives Claude a code word and asks for a ~1200-word story. While it writes,
/btwasks for the code word (answer:PINEAPPLE-42.) and a follow-up asks for the keeper's name (Ada.); after the turn ends a third/btwasks what the story is about. The CLI log has the first two side questions arriving at 14:16:49 and 14:16:54 and the third at 14:17:35, around the turn's result at 14:17:31. After the thread is closed, the chat holds neither the questions nor the answers.Notes for review
RPC_CALL_TIMEOUT_MS), and an answer over a long conversation can take longer, so no RPC waits for the whole answer:askstarts the question and waits up to 20 s,waitpicks it up again by id, andcanceldrops it (sent when the panel is closed). A question nobody collects is dropped after 10 minutes./btwcan arrive while an answer is still coming. It waits its turn and is then asked with that answer in its history, as a follow-up is. The thread lives in memory (sync/sideQuestionThreads.ts), so an app restart starts without it.Query.askSideQuestionships in the SDK runtime but is missing from its public typings (checked through 0.3.286), so it is typeof-gated the same way as the usage seed inclaudeRemote.ts.unavailable: local | not-started, and the panel says what to do. A session still running a CLI from before this change getsRPC method not available(after the server's 15 s grace for a handler to register), and the panel asks to update the CLI and restart the session, since a running session keeps the CLI it started with. Offline sessions are caught before the call./btwasks the running Claude in place and leaves no session behind.claude/sideQuestion.test.ts(CLI),sync/sideQuestion.spec.ts,sync/sideQuestionThreads.spec.ts(a thread outliving its screen, a late answer after a close, the queue),suggestionCommands.spec.ts, andfirstSendComposers.test.ts, whose explicit scope gains the three names the send handler now calls. App and CLI typecheck clean. The app suite passes apart fromcomponents/sessionPresentation.test.ts, which fails the same way onmain(__DEV__ is not definedwhile loadingexpo-modules-core).🤖 Generated with Claude Code