Skip to content

fix(chat): a first message from the New tab dialog is held, not sent, while Claude Code starts #2525

Closed

Description

@jpcarranza94

What happened

I opened New tab, picked Claude Code (haiku), typed a first message and pressed Start. Claude Code started, but the message did not go. Chat showed it as held:

  • Most often: "Not sent: the pane's terminal or agent session changed. Review the message before sending it again."
  • Less often: "Not sent: the agent started for this message has ended. Review the message before sending it."

Nothing happens after that. The message waits until the user sees the card and presses Send now.

Expected: the message goes to Claude Code once it is ready. It does so in the launches where it is not held.

Cause

Claude Code runs short child processes in front of itself as it starts. herdr lists them before Claude Code and names no agent yet. A trace of one launch (a pane read every 50 ms, times from the create request):

254ms agent=null    fg=[git 63517, claude 63509]
306ms agent=null    fg=[gh 63525 "gh auth token", claude 63509]
408ms agent=null    fg=[claude 63509]
510ms agent=null    fg=[gh 63585 "gh auth token", claude 63509]
796ms agent=claude  fg=[security 63603, grep 63598, grep 63597, sh 63594 "sh -c ps aux | grep …", gh 63585, claude 63509]
846ms agent=claude  fg=[claude 63509]
  1. herdr's agent.start answers at once. The create route queues the first message 5 to 250 ms after the launch (server/workspace-routes.ts:152-156). A launch through agent.start reports no pid, so launchedPid is null.
  2. While herdr names no agent, currentIdentity takes the first process in front (server/core/pending.ts:414, ?? info?.foreground_processes?.[0]?.pid). In the trace above, that is git.
  3. queueFirstMessage binds the message to that pid (server/core/pending.ts:759-762). Its only check is that the pid is not the shell's.
  4. The child exits a few ms later. At the next pane event, learnLaunched checks the message (server/core/pending.ts:813-814):
    • herdr names claude: targetChanged sees another pid and holds the message with pending_target_changed.
    • herdr names no agent yet: launchGone sees the bound process gone and holds the message with first_message_launch_ended.

Proposed fix

With this fix, 0 of 18 live launches held the message (see below).

How often

Often. It depends on the startup timing.

  • A/B with a real Claude Code (haiku) in an isolated herdr session, two Ovis servers in ABBA order, headless Chromium at 1280×800.
  • main (feb3ae0) held the first message in 11 of 17 launches: 9 pending_target_changed, 2 first_message_launch_ended. One batch held 1 of 7, the next 10 of 10. An earlier set of batches held 23 of 32.
  • With the fix, 0 of 18 launches held it.
  • A held message is never sent on its own. When it was not held, main sent it 4461 ms after Start (median, n=5).

Ovis version

main (feb3ae0, v0.4.21). The new unit test fails the same way on 8d28829.

How it runs

Ovis servers from checkouts, on an isolated herdr session.

Server PC

macOS 26.5.2, Apple M4 (Mac mini), herdr 0.9.0

Device and browser

Headless Chromium at 1280×800. The cause is on the server and is not specific to a device.

Agent and PC

Claude Code 2.1.316 (haiku), local PC

Activity

  1. added a commit that references this issue on Nov 1, 2026
    c4cc67d
  2. added a commit that references this issue on Nov 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions