Open bug report

/claude/inject with a stale context_index after relaunch typed a Claude prompt into a Codex panel

John Lauer · 4d ago

Hydrogen 1.0.645 (Windows, release tier), ab 2.1.184, 2026-10-19 ~01:33Z.

After Hydrogen relaunched itself (auto-update 1.0.644 → 1.0.645), VS Code came back with a Codex panel in front. I asked for the Claude context and typed into it:

  1. GET /claude/conversation-state → {"contextIndex": 10, "ready": true, "msgs": 3, "turns": 2, "input_count": 0}
  2. POST /claude/inject {"text": "...", "context_index": 10, "typed": true, "submit": true}

The text was typed and submitted into the Codex panel (GPT-6 Astra), not a Claude conversation. That panel held an unsent draft from another thread; the inject replaced it, and Codex started a turn on a prompt meant for Claude.

Expected: /claude/* routes only ever resolve to Claude Code webviews. If the context id is stale after a relaunch, or input_count is 0, refuse with an error rather than typing into whatever composer has focus.

Related: #111 (census attaches the wrong Codex conversation id; a send could land in the wrong thread).

2 Replies

John Lauer · 3d ago

Seen twice more: POST /claude/inject {context_index, typed:true, submit:true} returned ok:false "context 13 not found / no Claude input there" (and later "context 14 not found") while the text WAS typed and submitted into the right Claude tab (it is in that session's transcript). So the error can't be trusted either way: a caller that retries double-submits.

John Lauer · 3d ago

Both halves found and fixed in a233c17c (in the next build after 1.0.658, not built yet: the build box is busy).

Typed into Codex. Execution-context ids are handed out again after a relaunch or an editor reload, and neither GET /claude/conversation-state nor a pinned POST /claude/inject {context_index} checked that the context was still a Claude Code conversation. Any composer qualified, so id 10 was the Codex panel by then. Now:

  • /claude/inject {context_index} first probes that one context and types nothing unless it is a Claude Code conversation with a visible box. Otherwise it answers ok:false, typed:false with stale_context (the id no longer exists) or not_claude plus which panel it is (for example "a Codex panel").
  • /claude/conversation-state answers ready:false, not_claude:true for a non-Claude panel instead of handing out its id.

"context 13 not found" after typing it. The typing script answers only once the last character is in. The per-context eval gave up after 8 s, so any typed prompt longer than about 150 characters at the default 50 ms came back "not found" while it was still being typed and submitted. The wait now covers the whole prompt (every character at the worst of its jitter, plus 30 s). If the context passed the pre-check and still does not answer, the reply is ok:false, typed:"unknown", uncertain:true with "the text may already be typed and submitted, check conversation-state before sending again", never "not found". So typed:false now always means nothing was typed, and only then is a retry safe.

Gate: unit test gate_inject_wait_covers_long_typed_prompt, and scenario claude-inject-claude-only (a stale id and the workbench are refused with nothing typed; a 300-character typed prompt answers ok with the text in the box). I will close this once that passes on the next build.

Log in to reply.