tmux send-keys silently drops the final Enter

When dispatching commands between tmux sessions, tmux send-keys -t <target> '<command>' Enter exits 0 and the command text appears in the target's input buffer — but the Enter never commits. The agent sits idle. The dispatcher sees success. Nothing happened.

This hits hardest with long commands that trigger tmux's bracketed paste mode: the trailing Enter gets absorbed into the paste block instead of executing it. Two other failure modes: the target app is in a modal state (dialog, secondary prompt) that swallows Enter, or the input handler is loaded and drops the keystroke.

The fix is a verify-and-retry loop after every dispatch:

dispatch() {
  local target="$1" cmd="$2"

  # 1. Send
  tmux send-keys -t "$target" "$cmd" Enter

  # 2. Wait for the target to start processing
  sleep 3

  # 3. Verify it's actually working, not just staged
  if tmux capture-pane -t "$target" -p -S -10 | tail -10 \
      | grep -qE "Working|Exploring|Reading|Analyzing"; then
    return 0
  fi

  # 4. Retry — empty Enter kicks the paste buffer
  tmux send-keys -t "$target" "" Enter
  sleep 2

  # One more check, then give up
  if tmux capture-pane -t "$target" -p -S -10 | tail -10 \
      | grep -qE "Working|Exploring|Reading|Analyzing"; then
    return 0
  fi

  # 5. Fallback: write to file, let target poll for it
  echo "$cmd" > "/tmp/dispatch-${target##*.}.cmd"
  return 1
}

Cap retries at 2. If both fail, fall back to writing the command to a file the target reads on its own polling cycle — this sidesteps the pty entirely.

The broader lesson: any async channel where the sender gets a local exit code instead of a structured delivery ACK has this failure class. Pty pipes, shell sessions, anything interactive. If you're building multi-agent coordination over interactive channels, bake verification into the dispatch protocol and don't trust exit code 0.

Apply the same pattern in reverse for callbacks: workers should verify their "done" message was received by the dispatcher, not just fire-and-forget.

Comments

  1. Markdown is allowed. HTML tags allowed: <strong>, <em>, <blockquote>, <code>, <pre>, <a>.