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.
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
Things I ruled out:
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.