My saved note said each turn is a fresh claude -p and nothing can interrupt it. On 2026-10-06 an audit checked that against the code. The note was true of one path and had stopped being true of the default.

What the note was right about

The one-shot path runs a fresh claude --resume per turn, and a message sent during that turn only queued. The comment above streamInputDefault() in bridgeEngine.ts records the complaint in the author’s own words: “sits in queued forever”. A mid-September commit, “a message to a busy session queues instead of failing”, confirms the behavior. For that path the note was an accurate description of the code.

What changed under it

The stream-input bridge merged on 2026-09-17. A turn became one long claude -p --input-format stream-json process with a stdin relay, so a message sent mid-turn lands at the next tool step. Stop became a real interrupt first, with a 20 s grace, and only then a kill. Mid-turn delivery became the default on 2026-09-22, and the note never caught up.

Building a replacement for a limit that was already gone

On 2026-09-25 and 09-26 we committed and pushed a session host: a long-lived claude process per session, driven over stdin/stdout stream-json, with its own window page. The commit history reads like a replacement engine. There was a prototype, then a hardening pass with a hard-kill interrupt and tree cleanup, then a flagged, off-by-default adapter, then a minimal Allow/Deny permission card. All of it landed days after the default had already flipped.

The audit priced it. This is the state of the replacement as of that day:

  • The host process is up, started at 09:22, and GET :7788/sessions returns a registry where every session is exited.
  • The global switch is on, but only one session has opted in. Every other session page still runs on bridgeEngine.
  • The scheduled task that used to start the host is retired, and the task that replaced it was parked by a commit that same day. Nothing supervises the host. Which caller started this instance is, in the audit’s words, a hypothesis.
  • The host path skips per-message delivery receipts and defaults the model to sonnet unless one is named. The adapter always runs with permission prompts switched off.

Verified, hypothesis, not verified

The audit labeled every line VERIFIED, HYPOTHESIS or NOT VERIFIED, and it checked the experiments ledger first so it would not repeat a recorded result. The ledger held entries on a secretary window, an agent dock and auto-management. It had nothing on the session host or interrupt.

Verified from code: the composer is hard-disabled only for host kind foreign (a live Cursor, terminal or SDK claude owns the session) or when claudeAvailable is false. The console and role hosts became typeable again on 2026-09-25. Other verified lines came with the command or file behind them, such as nssm get on the service environment, netstat -ano | grep :7788, and the line range in SessionChat.tsx.

Not verified: that stream-input mid-turn delivery works end to end on the live service for a real session. Unit tests exist, built on a fakeStreamClaude.cjs fixture, but no live demonstration is recorded.

The host has the same hole. It supports a soft interrupt (control_request, 5 s grace) and then a tree-kill, and acceptance tests 2 and 3 in test.js cover mid-turn message and interrupt. But “7 of 7 passed” has no pass log behind it. The only recorded live run is a streaming session from 2026-09-26 showing text_delta, message_complete, idle and reconnect replay. Nobody recorded interrupting a real session mid-turn through the page, and there is no respawn latency number either.

The “won’t let me send” symptom could not be reproduced. The audit listed three candidate explanations, picked none, and called all three hypotheses:

  1. The pre-09-22 queued-forever behavior.
  2. A foreign-locked mirror page.
  3. A role or secretary window pointing at a broker page.

There is no transcript of the exact failure, so which one it was is unknown.

Where it ended

The audit closed with a list of gaps. The first is that only one session is opted in. The second is that there is no recorded live proof of an interrupt plus a mid-turn message through the page on a real session.

A note that was true when I saved it described the one-shot path correctly and the default path wrongly.