Skip to content

[enhancement] Encode the interactive-CLI protocol in a high-intent terminal_send_message tool (text + Enter + settle + confirm) instead of leaving send_keys/Enter to the model #482

Description

@serge-ivo

Summary

The terminal / tmux Operator connector exposes two low-level write tools and makes the model choose correctly between them and remember to submit:

  • tmux_run_command / terminal_run_command — types text and presses Enter (for shell/git/build lines).
  • tmux_send_keys / terminal_send_keys — types text without Enter unless the model passes keys:["Enter"] (for answering an interactive prompt, sending Escape/C-c/arrows).

Driving an interactive CLI like Claude Code needs "type this message, then Enter, into the CLI's input box." Today that maps to send_keys plus a correctly-remembered keys:["Enter"], sent into a pane the model must independently know is ready. That's a footgun, and it misfired in production (see #481): the message was sent into a not-ready pane and dropped.

Best-practice framing

Encode the correct protocol in the tool, not in the model's judgment. Add a high-intent tool — the tmux/terminal analogue of the Coder path's send_to_cli (workers/api/src/lib/storage-tools.ts:231-237) — that does the right thing atomically:

terminal_send_message (write) — "Send a message to the interactive CLI running in this pane and submit it."

  1. Verify/await the pane is at an input prompt (readiness gate from [bug] Terminal/tmux Operator writes are fire-and-forget — no readiness gate, no landed-confirmation; the first message to an interactive CLI is silently dropped #481).
  2. sendText(text) then sendKey("Enter").
  3. Settle + confirm the pane changed (landed-confirmation from [bug] Terminal/tmux Operator writes are fire-and-forget — no readiness gate, no landed-confirmation; the first message to an interactive CLI is silently dropped #481).
  4. Return the grounded result: landed + post-settle pane, or an explicit "did not land, resend."

Keep send_keys for genuine key-level control (Escape, C-c, arrows, multi-key sequences) — it stays the escape hatch. send_message becomes the default, hard-to-misuse path for "tell the CLI to do X."

Optionally expose a thin terminal_wait (read scope) that polls capture until the pane quiesces or a pattern appears — the reusable "wait for ready" the Coder path has (coding-loop.ts:179-183 waitIdle) but the connector lacks. send_message uses it internally; the model can also call it explicitly.

Depends on

Acceptance criteria

Metadata

Metadata

Assignees

No one assigned

    Labels

    connectorsConnector + tool frameworkenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions