You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Bug]: Claude AskUserQuestion renders as a plain tool call in the desktop Chat UI on a paired headless Remote Orca Server — no question card, answerable only in the terminal #11761
Server: headless orca serve (orca-ide --serve --serve-port 6768 --pairing-address <tailnet-ip>) on an Ubuntu 26.04 LTS Hetzner VPS, v1.4.162, reachable tailnet-only
Client: Orca desktop on Windows, paired to that server
Agent: Claude Code, running in a workspace on the server
View: native Chat UI (not terminal view)
The desktop host's shell (PowerShell vs WSL) is not in this path — the agent runs on the remote Linux host and the desktop is only a viewer. This is a different topology from the WSL Chat UI reports (#10326, #10523, #11327).
Symptom
When Claude calls AskUserQuestion, the desktop Chat UI renders it as an ordinary collapsed tool call in the message stream. No question card, no clickable options. The session reads as still working, so you wait on an agent that is actually blocked on you. The question is only discoverable by expanding the tool-call details, and only answerable by switching to the terminal view, where the TUI prompt has been waiting the whole time.
Root cause — two independent layers
1. The desktop chat has no transcript fallback for the ask prompt; mobile has one
src/renderer/src/components/native-chat/NativeChatInteractiveCard.tsx derives the card from exactly one source:
extractPendingAsk lives in src/shared/native-chat-ask.ts — cross-platform code — but is imported only by mobile. Its own docstring describes the resilience the desktop therefore lacks:
Transcript replay parses each tool-call through the same registered-parser + canonical-shape fallback as live status, so a question tool that rendered live cannot vanish from pending state after a reconnect/replay.
Consequence: on desktop, if the live status never arrives, the card cannot render at all — even though the pending AskUserQuestion tool call is sitting right there in the transcript the view has already parsed and rendered.
2. HTTP-hook status does not reach paired desktop clients on a headless server (#11210)
Claude reports status over the HTTP hook Orca installs into ~/.claude/settings.json (src/main/claude/hook-settings.ts, PreToolUse among others), and src/shared/agent-hook-listener.ts is what stamps interactivePrompt when the tool is AskUserQuestion.
That is precisely the transport #11210 documents as broken under headless --serve:
applyNormalizedStatus only updates the in-process cache, writes last-status.json, and sends agentStatus:set over Electron IPC to the local renderer. On a headless server there is no renderer, so the IPC is a no-op. […] session.tabs's agent-status projection (getFreshRetainedAgentStatusForMobileTab) only reads the OSC 9999 retained store, not the agent-hook cache.
#11210 was filed for OpenCode's missing activity dots, but the broken path is shared by every HTTP-hook agent, and Claude is one of them.
Verified on the affected server:
~/.claude/settings.json contains the Orca hook entries invoking ~/.orca/agent-hooks/claude-hook.sh for PreToolUse / PostToolUse / PermissionRequest / Stop / SubagentStart etc.
~/.config/orca/agent-hooks/last-status.json is written live with agentType: "claude" rows carrying state and toolName — so server-side capture works.
PR #11212 fixes the projection for working/idle state. It is not clear from that diff whether interactivePrompt and toolName are carried through to paired clients, which is what the question card needs.
Now confirmed (see the follow-up comment below): polling that cache at 200 ms during a live AskUserQuestion captured 188 consecutive samples over 6m35s, every one carrying state: "waiting", toolName: "AskUserQuestion" and the full untruncated interactivePrompt JSON — while the paired desktop client showed only a collapsed tool call. Server-side capture is correct; the defect is in delivery to paired clients and in the absence of a desktop fallback.
Why this is worse than a missing activity dot
A missing dot is cosmetic. A missing question card means the agent is blocked on human input with no signal in the view the user is looking at — the session reads as working. On a remote server this is the ordinary case, not an edge case, and the workaround (switch to terminal view) defeats the purpose of the Chat UI.
Expected
The question card renders in the desktop Chat UI whenever Claude has an unanswered AskUserQuestion, whether the agent runs locally or on a paired headless remote server, and answering from the card works without switching to terminal view.
Proposed fix
Two parts, ideally both:
Desktop transcript fallback (client-side, robust). Give the desktop view the same askFromStatus ?? extractPendingAsk(messages) resolution mobile already has. The shared helper exists and is already covered by tests; this survives any relay gap, not only this one, and needs no server change.
The server has one local patch, applied because the AppImage AppRun unconditionally injects --no-sandbox, which crashes ELECTRON_RUN_AS_NODE mode on a userns-restricted host. The patch replaces the orca-ide CLI wrapper on $PATH so it execs the extracted app directly. It does not modify the application bundle, and the running serve process is the stock AppImage. Mentioning it for completeness only — it is not plausibly related to chat rendering.
Environment
orca serve(orca-ide --serve --serve-port 6768 --pairing-address <tailnet-ip>) on an Ubuntu 26.04 LTS Hetzner VPS, v1.4.162, reachable tailnet-onlyThe desktop host's shell (PowerShell vs WSL) is not in this path — the agent runs on the remote Linux host and the desktop is only a viewer. This is a different topology from the WSL Chat UI reports (#10326, #10523, #11327).
Symptom
When Claude calls
AskUserQuestion, the desktop Chat UI renders it as an ordinary collapsed tool call in the message stream. No question card, no clickable options. The session reads as still working, so you wait on an agent that is actually blocked on you. The question is only discoverable by expanding the tool-call details, and only answerable by switching to the terminal view, where the TUI prompt has been waiting the whole time.Root cause — two independent layers
1. The desktop chat has no transcript fallback for the ask prompt; mobile has one
src/renderer/src/components/native-chat/NativeChatInteractiveCard.tsxderives the card from exactly one source:NativeChatView.tsximportsNativeChatInteractiveCardand nothing else — there is no transcript-derived path anywhere in the desktop view.Mobile resolves from two sources, in
mobile/src/session/use-mobile-native-chat-prompts.ts:extractPendingAsklives insrc/shared/native-chat-ask.ts— cross-platform code — but is imported only by mobile. Its own docstring describes the resilience the desktop therefore lacks:Consequence: on desktop, if the live status never arrives, the card cannot render at all — even though the pending
AskUserQuestiontool call is sitting right there in the transcript the view has already parsed and rendered.2. HTTP-hook status does not reach paired desktop clients on a headless server (#11210)
Claude reports status over the HTTP hook Orca installs into
~/.claude/settings.json(src/main/claude/hook-settings.ts,PreToolUseamong others), andsrc/shared/agent-hook-listener.tsis what stampsinteractivePromptwhen the tool isAskUserQuestion.That is precisely the transport #11210 documents as broken under headless
--serve:#11210 was filed for OpenCode's missing activity dots, but the broken path is shared by every HTTP-hook agent, and Claude is one of them.
Verified on the affected server:
~/.claude/settings.jsoncontains the Orca hook entries invoking~/.orca/agent-hooks/claude-hook.shforPreToolUse/PostToolUse/PermissionRequest/Stop/SubagentStartetc.~/.config/orca/agent-hooks/last-status.jsonis written live withagentType: "claude"rows carryingstateandtoolName— so server-side capture works.PR #11212 fixes the projection for working/idle state. It is not clear from that diff whether
interactivePromptandtoolNameare carried through to paired clients, which is what the question card needs.Now confirmed (see the follow-up comment below): polling that cache at 200 ms during a live
AskUserQuestioncaptured 188 consecutive samples over 6m35s, every one carryingstate: "waiting",toolName: "AskUserQuestion"and the full untruncatedinteractivePromptJSON — while the paired desktop client showed only a collapsed tool call. Server-side capture is correct; the defect is in delivery to paired clients and in the absence of a desktop fallback.Why this is worse than a missing activity dot
A missing dot is cosmetic. A missing question card means the agent is blocked on human input with no signal in the view the user is looking at — the session reads as working. On a remote server this is the ordinary case, not an edge case, and the workaround (switch to terminal view) defeats the purpose of the Chat UI.
Expected
The question card renders in the desktop Chat UI whenever Claude has an unanswered
AskUserQuestion, whether the agent runs locally or on a paired headless remote server, and answering from the card works without switching to terminal view.Proposed fix
Two parts, ideally both:
askFromStatus ?? extractPendingAsk(messages)resolution mobile already has. The shared helper exists and is already covered by tests; this survives any relay gap, not only this one, and needs no server change.interactivePromptandtoolName, not just live working/idle state, so the live path works as designed.Local modifications (disclosure)
The server has one local patch, applied because the AppImage
AppRununconditionally injects--no-sandbox, which crashesELECTRON_RUN_AS_NODEmode on a userns-restricted host. The patch replaces theorca-ideCLI wrapper on$PATHso it execs the extracted app directly. It does not modify the application bundle, and the runningserveprocess is the stock AppImage. Mentioning it for completeness only — it is not plausibly related to chat rendering.Related
--serve(filed for OpenCode)AskUserQuestionfixes, both on the local path