Skip to content

Interactive TUI ignores all keyboard input written to its PTY (only Ctrl+C responds), breaking automation/orchestration tooling #4180

Description

@jmirandasq

Describe the bug

When copilot runs its interactive TUI inside a programmatically-driven PTY (agent orchestrators, tmux send-keys, expect, pty.fork()), the TUI ignores every keystroke written to the PTY. Printable characters, /, Tab, arrow keys, Ctrl+L and Enter all produce no reaction: the ❯ composer stays empty and nothing is submitted.

The only key that does work is Ctrl+C, which cleanly tears down the alt-screen and exits — so the process is reading stdin, but the composer's key handling never sees the events.

Typing by hand in a regular terminal works fine. Non-interactive mode (copilot -p "...") also works fine. Only the automated interactive path is broken.

Affected version

GitHub Copilot CLI 1.0.70. (TUI banner reports v1.0.71)

Steps to reproduce the behavior

Minimal, dependency-free repro (Python stdlib only):

repro.py

import os, pty, time, select, fcntl, termios, struct, signal

pid, fd = pty.fork()
if pid == 0:
os.environ["TERM"] = "xterm-256color"
os.execvp("copilot", ["copilot"])

fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH", 40, 120, 0, 0))

def pump(t):
b = b""; end = time.time() + t
while time.time() < end:
r, _, _ = select.select([fd], [], [], 0.2)
if r:
try: b += os.read(fd, 65536)
except OSError: return b
return b

pump(10) # let the TUI boot

for name, seq in [("text", b"hola prueba"), ("enter", b"\r"),
("slash", b"/"), ("tab", b"\t"),
("arrow", b"\x1b[C"), ("ctrl-l", b"\x0c")]:
os.write(fd, seq)
print(f"{name:8s} -> {len(pump(2))} bytes of output")

os.write(fd, b"\x03") # Ctrl+C
print(f"ctrl-c -> {len(pump(3))} bytes of output")

Output:

text -> 0 bytes of output
enter -> 0 bytes of output
slash -> 0 bytes of output
tab -> 0 bytes of output
arrow -> 0 bytes of output
ctrl-l -> 0 bytes of output
ctrl-c -> 102 bytes of output <-- teardown sequences, process exits

Expected behavior

Bytes written to the PTY should be handled exactly as if typed: printable characters appear in the composer, Enter submits the prompt. This is what every other agent TUI I drive the same way does (Codex, for example, accepts the identical injected input).

Additional context

  • OS: macOS (Darwin 25.5.0), arm64
  • Node: v22.17.1 (installed via nvm), @github/copilot npm install
  • Shell: zsh

Things I ruled out:

  • Not a raw-mode problem. While the TUI is up, the PTY's termios is correctly in raw mode: ICANON=False, ECHO=False, ISIG=False, VMIN=1. Since ISIG is off, the working Ctrl+C must be handled by the application itself — confirming the read loop is alive.
  • Not a capability-negotiation deadlock. Copilot emits a kitty-keyboard query (CSI ? u), a theme query, alt-screen, bracketed paste (?2004h), mouse tracking and focus reporting (?1004h). Answering them (CSI ?0u, CSI ?997;1n, CSI ?62;1;6c) does not unblock input.
  • Not a focus problem. Sending focus-in (CSI I) after ?1004h changes nothing.
  • Not a paste-detection problem. Wrapping input in bracketed paste (ESC[200~…ESC[201~) changes nothing.
  • Not a "typed too fast" problem. Writing one byte at a time with 250 ms between characters changes nothing.
  • Not terminal-emulator specific. Same failure through a real terminal emulator (an Orca-managed pane) as through a bare pty.fork(). In the emulator case the injected string is even rendered appended to the footer line rather than into the ❯ composer, and Enter still submits nothing.
  • Not an injection-tooling problem. The identical injection path drives a plain shell and another agent's TUI correctly.

Debug log (copilot --log-level debug --log-dir ./logs) shows no input-related error at all. The only entries at the moment of the write are:

[INFO] Unregistering foreground session: d13a790d-…
[DEBUG] Broadcasting session lifecycle event: session.background for session d13a790d-…
[INFO] Registering foreground session: d13a790d-…
[DEBUG] Broadcasting session lifecycle event: session.foreground for session d13a790d-…

Impact: this makes the interactive TUI unusable from any agent-orchestration or automation harness. Current workaround is the non-interactive -p/--prompt mode, which loses the multi-turn session.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:input-keyboardKeyboard shortcuts, keybindings, copy/paste, clipboard, mouse, and text input

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions