MoonshotAI / MoonshotAI/kimi-cli
Shell tool interactive commands cause terminal input corruption and hangs (missing PTY allocation)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 11.4k
- Forks
- 1.3k
- Avg merge
- 9h 47m
- Merged PRs (30d)
- 2
Description
Shell tool interactive commands cause terminal input corruption and hangs (missing PTY allocation)
Summary
The Shell tool explicitly closes stdin and does not allocate a pseudo-terminal (PTY). This breaks interactive commands (ssh-add, sudo, npm init, etc.) in a way that is worse than a clean failure — it creates a terminal input race condition where both the subprocess and Kimi CLI's prompt_toolkit fight over /dev/tty, causing characters to appear slowly or not at all.
Other CLI agents (Claude Code, Gemini CLI, Codex CLI) handle this correctly by either allocating a PTY for subprocesses or suspending their own input loop to yield the terminal to interactive commands.
Root Cause
In tools/shell/__init__.py:
process = await kaos.exec(*self._shell_args(command), env=get_noninteractive_env())
process.stdin.close() # <-- EOF immediately; no interactive input possible
The stdin.close() prevents clean interactive input. However, tools like ssh-add bypass stdin entirely and open /dev/tty directly via getpass(). This creates the following conflict:
| Layer | Reads from | Behavior |
|---|---|---|
ssh-add |
/dev/tty |
Puts terminal into no-echo mode, waits for passphrase |
| Kimi CLI (prompt_toolkit) | stdin (same terminal fd) | Also reading keystrokes for chat input |
| Result | Both race for the same bytes | Characters appear erratically or with extreme delay |
Reproduction
- Ensure
ssh-agenthas no loaded keys:ssh-add -D - In Kimi CLI, run:
Shell (ssh-add ~/.ssh/id_ed25519 && git push origin main) - Observe that
ssh-addprintsEnter passphrase for /Users/.../.ssh/id_ed25519: - Attempt to type the passphrase
- Expected: Clean interactive prompt where typing works normally
Actual: Each character takes 1–3+ seconds to appear; backspace is equally broken; the experience is unusable
Comparison with other CLI agents
| Tool | PTY allocation | Interactive subprocess behavior |
|---|---|---|
| Claude Code | ✅ Yes (pty.openpty or equivalent) |
Interactive commands work natively; agent yields terminal control |
| Gemini CLI | ✅ Yes | Same — interactive subprocesses receive clean TTY access |
| Codex CLI | ✅ Yes | Same |
| Kimi CLI | ❌ No (stdin.close()) |
Terminal input corruption; race between subprocess and prompt_toolkit |
Why this matters beyond "nice to have"
This is not just a missing feature — it is a reliability bug. The current behavior:
- Leaves zombie
ssh-addprocesses hanging on/dev/tty - Corrupts the terminal state (no-echo mode from
getpass()may not be restored if the subprocess is killed by timeout) - Makes Kimi CLI unusable for any workflow involving SSH passphrases,
sudo, or interactive CLI tools - Forces users to drop out of Kimi CLI into a native terminal for basic Git operations
Suggested fixes
Option A: Allocate a PTY for shell subprocesses (best)
Use pty.openpty() or equivalent when spawning shell commands. This gives the subprocess its own terminal device, eliminating the race with prompt_toolkit.
Option B: Suspend prompt_toolkit input during interactive commands
When a subprocess is detected reading from /dev/tty, temporarily suspend Kimi CLI's own input handling and yield terminal control. Resume when the subprocess exits. This is what git does during git commit with an editor.
Option C: Detect interactive commands and warn/block
If PTY allocation is architecturally difficult in the short term, detect when a subprocess opens /dev/tty (via tcgetpgrp or lsof monitoring) and immediately fail with a clear error:
"This command requires interactive input, which the Shell tool does not support. Please run it in a native terminal."
This prevents the current broken state where the command hangs for 60–120s and corrupts terminal input.
Related issues
- #1117 — Shell tool interactive input support (feature request covering the same surface area)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in tools/shell/init.py at the shell process creation and the immediate process.stdin.close() call. Reproduce the ssh-add scenario described in the issue, then trace how shell commands interact with prompt_toolkit and terminal input. Done means interactive commands no longer corrupt or hang terminal input, with behavior verified for the reported ssh-add workflow.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100