Remote Control: message arrives in TUI composer but is never submitted (swallowed Enter) — tmux/headless, intermittent
Summary
Messages sent via Remote Control (claude.ai mobile app) to a Claude Code TUI running inside detached tmux intermittently arrive in the composer input box but are never submitted — the text sits after the ❯ prompt indefinitely and the turn never starts. To the sender the agent simply appears to ignore the instruction; there is no error on either end.
We hit this 10 times in one day (2026-07-16) across a fleet of always-on headless sessions driven from the mobile app. Examples of stranded texts (visible in the composer, dim-rendered while a turn was active, normal-intensity once idle): keep going autonomously, ok restart the agents now, find and fix the delivery bug that swallows the Enter (yes — the instruction to fix this bug was itself swallowed, twice).
Environment
- Claude Code 2.1.211 (Linux CLI), Ubuntu 24.04, kernel 6.8
- TUI running detached in tmux 3.4 (
claude --dangerously-skip-permissions --resume <id>), one session per workspace, no attached client - Remote Control registered per session; driven from the claude.ai iOS app
- Sender and host on the same tailnet, but delivery is via the RC service (not SSH/tmux)
Observed behavior
- The message text does arrive at the TUI — it is visible in the composer (
❯ <text>) in a pane capture. So the injection path populates the input buffer, but the submit step is lost. - While a turn is running, the stranded text renders dim (same styling as queued input); when the turn ends it remains in the composer at normal intensity and never submits. Text swallowed mid-turn does not self-deliver at turn end.
- Occurrences cluster in three windows:
- TUI busy / turn-start transitions — message sent while a turn was starting or running;
- TUI boot — message sent while the session was relaunching (
--resumetranscript replay on screen); - after RC re-registration churn — we re-registered bridges for many sessions the same day (account changes), leaving orphaned server-side registrations for the same session names; several strandings followed within minutes of re-registration.
- No correlation with message length or content; all strandings were short single-line texts.
What we ruled out
- Our own fleet tooling also injects messages via
tmux paste-buffer+send-keys Enter, and it had a separate race we found and fixed (verified submit loop). The 10 strandings above are not that path: our delivery tooling keeps a provenance log of every message it injects, and none of the stranded texts appear in it. The only remaining writer for these sessions is the Remote Control path. - Not a tmux-attach/human-typing artifact: sessions had no attached clients at the time (
session_attached == 0).
Expected
Either the message submits (starts a turn), or delivery fails loudly back to the app ("not delivered"). Silent arrival-without-submit is the worst case: the sender believes the agent received and ignored the instruction.
Repro sketch
- Run Claude Code in detached tmux, register Remote Control, drive it from the mobile app.
- Send messages specifically during: (a) an active turn, (b) session relaunch while the resume replay is rendering, (c) shortly after the RC bridge for the session name was re-registered.
- Capture the pane (
tmux capture-pane -p) — the failure signature is the message text sitting after❯with no turn started.
Intermittent — on a quiet, idle, freshly-connected session we could not force it; under the three windows above it reproduced multiple times per day under real use.
Workaround (for anyone else hit by this)
A cron/systemd watchdog every 2 min: for each tmux session with no attached client and no running turn, capture the pane, and if the same composer text (≥3 printable chars, not the dim placeholder hint) survives two consecutive ticks, press Enter (tmux send-keys Enter) and verify the composer cleared. Converts every stranding into a ≤4-minute self-healing delivery. Caveats we hit implementing it: the empty composer renders a dim Try "..." placeholder that naive captures read as text, and queued mid-turn input also renders dim — distinguish by the hint shape, not the styling alone.