[FEATURE] Add Interactive Shell Support to the Bash Tool via Pseudo-Terminal (PTY)
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet
- [x] This is a single feature request (not multiple features)
Problem Statement
Currently, the Claude Code Bash tool is incredibly powerful for executing non-interactive, stateless commands (ls, grep, cat, etc.). However, its capabilities are limited when a command requires real-time user interaction.
If a user asks Claude to run a command that spawns an interactive session—such as vim file.js, git rebase -i HEAD~3, npm init, or an interactive REPL like python—the Claude Code session will hang, wait for a timeout, or fail.
This forces the user to break their workflow:
- Exit or switch away from the Claude Code session.
- Open a separate terminal to run the interactive command.
- Complete the task.
- Return to Claude Code and manually provide context about what just happened.
This process is inefficient and, more importantly, it removes the interactive task from Claude's context. Claude has no awareness of the changes made in vim or the decisions made during a git rebase, limiting its ability to provide continuous, context-aware assistance.
Proposed Solution
I propose enhancing the Bash tool to support fully interactive shell commands by integrating a pseudo-terminal (PTY). This would allow Claude Code to spawn and manage interactive subprocesses, rendering their UI directly within the Claude Code REPL.
Ideal User Experience:
- A user prompts Claude:
> open src/app.ts in vim so I can make a quick edit. - Claude executes the tool call:
Bash(command="vim src/app.ts"). - The Claude Code REPL interface is temporarily replaced by a live, interactive
vimsession. The user sees the file content and can edit it using standardvimcommands. - To ensure user input is correctly routed, a keybinding (e.g.,
Ctrl+Fas used in Gemini CLI) could be used to "focus" the interactive terminal session. This would direct all subsequent keystrokes to thevimprocess instead of the Claude Code prompt. - When the user saves and exits
vim(e.g., with:wq), the interactive session terminates. - The user is returned to the standard Claude Code prompt.
- Claude receives a
ToolResultfrom theBashtool indicating that the command completed successfully (e.g.,exitCode: 0). Claude is now aware the file was edited and can proceed with the next step, like running tests.
This approach would leverage a library like node-pty to serialize the terminal state (text, colors, cursor position) and stream it to the user, creating a seamless, two-way interactive experience.
Alternative Solutions
- Current Workaround: The only current workaround is to perform interactive tasks in a separate terminal. The major drawback is the complete loss of context for Claude, which defeats the purpose of an integrated agentic workflow.
- Agent-Only Edits: One could argue that users should instruct Claude to perform all edits programmatically (e.g., using the
Edittool orsed). While viable for simple changes, this is clunky and inefficient for complex refactoring, multi-line edits, or tasks that are simply faster with a real editor. It also fails to solve the problem for other interactive tools likegit rebase -i,htop, or setup scripts.
Priority
Critical - Blocking my work
Feature Category
CLI commands and flags
Use Case Example
A developer is working on a new feature and has made several small, messy commits. They want to clean up their git history before opening a pull request.
- User Prompt:
> I need to clean up my last 3 commits. Start an interactive git rebase for me. - Claude Action: Claude understands the request and executes
Bash(command="git rebase -i HEAD~3"). - Interactive Session: The Claude Code REPL transitions into the editor defined by the user's git configuration (e.g.,
vimornano). It displays the list of commits for the rebase. - User Interaction: The user directly edits the text, changing
picktosquashfor two of the commits. They save and exit the editor. - Context Preservation: The user is returned to the Claude Code prompt. Claude receives the output from the git command (e.g., "Successfully rebased and updated HEAD.").
- Next Step: The user can now say,
> Great. Now push the changes to a new branch and create a PR.Claude has the full context that the rebase occurred and can proceed correctly.
Additional Context
- Precedent: This feature was recently introduced in the Google Gemini CLI (v0.9.0) and has proven to be a major enhancement for their shell integration. Their implementation demonstrates the technical feasibility and value of this approach.
- Reference: Google Developers Blog Post on Interactive Shell
- Technical Considerations:
- This would likely require the
node-ptylibrary or a similar PTY solution. - The terminal renderer would need to be updated to handle complex terminal UI escape codes for color and cursor positioning.
- A clear mechanism for focusing/unfocusing the interactive session is crucial to manage user input.
- This feature should integrate with Claude Code's existing permission system. A request to run
vimwould still be aBashtool call that requires user approval, but once approved, the session becomes fully interactive.
14 Comments
---
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Second this. Would also love to have a PTY implementation of plan mode that allows dynamic commenting/editing of plans.
This issue has been inactive for 30 days. If the issue is still occurring, please comment to let us know. Otherwise, this issue will be automatically closed in 30 days for housekeeping purposes.
I would love this. When I run into interactive prompts I have to go run them in a separate terminal and that means Claude doesn't have the context of what happened without manual copy/paste of specific info which can be tedious at times.
I could get by with bash mode just staying on until I dismiss it so Claude gets the context. That would be an easy win.
Hey team, adding another real-world use case that might help prioritize this.
Command:
gh pr checks <PR> --watch --fail-fastWhat happens: Each refresh cycle prints new lines instead of updating in-place, causing a "bleeding" effect where the terminal fills up with repeated output blocks.
Expected: The
--watchflag should refresh in-place using cursor control sequences.This is a pretty common workflow when waiting for CI checks to complete. Totally understand this requires proper PTY integration which isn't trivial - just wanted to add this as a concrete example of the impact.
Environment:
Appreciate all the work on Claude Code - it's been a game changer for my workflow despite this edge case. Happy to provide more details if helpful.
<img width="844" height="779" alt="Image" src="https://github.com/user-attachments/assets/bcd69c6f-8a2c-4605-a36f-e0af65826a19" />
Working Workaround: GUI Password Prompt Script
While waiting for native support, here's a working workaround using a shell script wrapper that provides GUI-based sudo authentication without exposing the password to Claude.
How It Works
zenity(GTK/GNOME) orkdialog(KDE) to display a native password promptsudo -Svia stdin pipe - never written to disk, never exposed to the AIThe Script (
~/.claude/scripts/sudo-prompt.sh)Configuration
``
bash
``mkdir -p ~/.claude/scripts
chmod +x ~/.claude/scripts/sudo-prompt.sh
~/.claude/settings.json:``
json
``{
"permissions": {
"allow": ["Bash(~/.claude/scripts/sudo-prompt.sh:*)"]
}
}
~/.claude/CLAUDE.md:``
markdown~/.claude/scripts/sudo-prompt.sh <command> [args...]## Sudo Commands
When a command requires sudo, use:
``Requirements
zenity(GNOME) orkdialog(KDE) installedsudo dnf install zenityorsudo apt install zenityThis keeps the password secure while enabling Claude to execute privileged commands with user consent via the GUI prompt.
Adding an AI-Friendly Design Perspective
Great issue! I'd like to add some thoughts on how PTY support could be designed to maximize value for AI-assisted workflows, not just human UX.
The Context Gap in Agentic Loops
When an AI agent executes a command that requires interaction, the current flow creates a fundamental context gap:
The AI can't see what answers were provided, understand the resulting configuration, or continue the workflow with accurate context. This forces users to manually bridge context between terminals.
Workflows Where This Matters
| Workflow | Context Lost |
|----------|--------------|
|
git rebase -i| Which commits were squashed/reordered ||
python -iREPL | Debugging sessions, experiments ||
npm init/pnpm create| Project configuration choices ||
vim/nvimedits | Manual code changes ||
psql/redis-cli| Database exploration results |Proposed API Design (AI-Friendly)
For maximum AI utility, consider a session-based API that allows programmatic interaction:
This would enable:
The tmux Proof of Concept
This pattern already works via tmux:
Native integration would be more reliable, but this demonstrates the concept is viable.
Summary
PTY support would close the context gap that currently forces users to manually bridge information between interactive sessions and AI assistants. Designing with AI observability in mind would maximize the value of this feature.
+1 for this feature! 🚀
For anyone looking for a solution to this right now — I built an open-source MCP server that addresses this: mcp-interactive-terminal
It gives AI agents real, persistent terminal sessions via node-pty + xterm-headless. You can open REPLs, psql, SSH, rails console, etc. and send multiple commands to the same session. Clean text output (same terminal emulator as VS Code), smart command completion detection, and a two-step confirmation flow for dangerous commands.
One command to install:
Works with Claude Code, Cursor, Windsurf, and any MCP client. Not a native Bash tool integration (that would still be great), but it covers the interactive use cases as an MCP server today.
+1 — Concrete use case: I want to run interactive TUI games (built with blessed/curses/raw stdin) directly inside Claude Code while waiting for long-running tasks. Think Chrome's dino game but in the terminal, playable without leaving the Claude Code session.
The fact that Gemini CLI already ships this in v0.9.0 makes this even more compelling. Would love to see Claude Code catch up on this front.
+1 for this. I'd like to add another concrete pain point caused by the same root issue: shell completions are entirely unavailable in the current one-shot, non-interactive bash mode.
Tools like
git,docker, andnpmall rely on completion scripts that are only loaded in interactive shells. Since the bash tool runs non-interactively, tab completions are silently absent — with no user-side workaround.PTY support as proposed here would solve this too, since completions work naturally in interactive shell sessions.
Environment:
Use case: Lightweight interactive prompts with
gumin slash commandsAdding a use case that's distinct from the full-TUI scenarios (vim, rebase) discussed above — lightweight interactive prompts mid-workflow using
gum.I maintain a set of shared slash commands (
.claude/commands/*.md) for team workflows:/local-review,/ship-it,/start-work,/lint,/test. Several of these need quick user input during execution:| Command |
gumsubcommand | Purpose ||---------|-----------------|---------|
|
/local-review|gum choose --no-limit| Multi-select which code review findings to fix ||
/ship-it|gum confirm| Confirm before force-pushing or creating a Linear issue ||
/start-work|gum filter| Fuzzy-search assigned Linear issues to pick one ||
/lint,/test|gum spin| Show a spinner while linters/tests run |Today, all of these fail with
open /dev/tty: device not configuredbecause the Bash tool runs without a controlling terminal. The fallback is text-based ("type F1, F3 or 'skip'"), which works but loses the interactive UX that makesgumvaluable.Why
gumis a compelling case for PTY support:Unlike vim or a REPL,
guminteractions are brief and self-terminating — the user makes a selection and the command exits. There's no long-running session to manage. This makes it a lower-complexity entry point for PTY support:gum choose/gum filter— present options, user selects, exitsgum confirm— yes/no, exitsgum input/gum write— collect text, exitsgum spin— show progress, exits when the wrapped command finishesgum table— display formatted data, exitsThese are exactly the kind of "focused interactive moments" that would benefit from a focus keybinding approach (like the
Ctrl+Fmentioned in the issue description) — the interaction is brief, the context return is immediate, and Claude doesn't need to interpret the terminal output.The broader pattern here: there's a growing ecosystem of terminal UI tools (
gum,fzf,skim,bat,glow) that enhance developer workflows but are completely inaccessible from Claude Code today. PTY support would unlock all of them.I built an open-source tool that solves this today as an external companion to Claude Code: https://github.com/nielsbosma/shellwright — a PTY session broker that any agent can shell out to (or a playwright for CLIs)
shellwright start --name build -- npm run build
shellwright wait build --for "Continue?" --timeout 30
shellwright send build "y"
shellwright read build --tail 10
It handles all the cases mentioned here — interactive prompts, password inputs, REPLs, TUI apps — with prompt detection, clean ANSI-stripped output, and cursor-based reads. Cross-platform (Windows ConPTY + Unix), daemon-backed so sessions persist across invocations.
Install: cargo install shellwright or npx shellwright
Would love feedback from anyone hitting this limitation.
Workaround for sudo-over-SSH without a PTY: global sudo timestamp + PreToolUse hook
Until PTY support lands, here's a workaround that lets Claude run
sudoin SSH+tmux workflows whereSUDO_ASKPASSGUI helpers can't work (no X display).Setup —
/etc/sudoers.d/claude-global-timestamp:timestamp_type=globalmakes sudo's credential cache per-user instead of per-tty. With that, authenticating in any terminal (Ctrl-Z suspend + parent shell, sibling tmux pane, or a second SSH session) caches credentials that Claude's Bash-tool subprocess can then reuse.Flow:
sudotool callsudo -n trueaskdecision and tells the user: "Ctrl-Z,sudo -v,fg, retry"sudo -kanywhere ends the sessionGotcha: Claude's
!command prefix does not give you a real tty — it runs through the same ttyless Bash-tool path, so plainsudostill fails there. Must use Ctrl-Z + fg, or a separate pane.Hook sketch (registered under
PreToolUse.Bash):Trade-offs vs alternatives:
| Approach | SSH-friendly | Auto-expires | User control |
|---|---|---|---|
| Full NOPASSWD | yes | no | weak |
| Narrow NOPASSWD | yes | no | rigid |
| SUDO_ASKPASS (GUI) | no | yes | per-cmd |
| Global timestamp + hook | yes | 20 min | strong |
Trust model: during the 20-minute window, any process running as the user can sudo without prompting — same practical boundary as the interactive shell you're typing in. Fine for single-user workstations with active supervision; not fine for multi-user or unattended agents.
Posting this because #1135 (where this would be most on-topic) is locked. Native PTY support (this issue) would make all of this unnecessary, but in the meantime this is a cleaner fallback than copy-pasting every sudo command.
I built an MCP that gives a complete, private, VT100-style pseudoterminal (and keyboard) to claude-code: https://github.com/xdrr/ptyai
You can try it out with:
npm install -g ptyaiIt works surprisingly well; in fact, I was shocked at how much better claude-code works when there's a full pseudoterminal available. It's almost as if Anthropic's models have the training and were just waiting for the tooling to support a terminal.
Rather than the session broker design @nielsbosma describes, the ptyai MCP lets the agent see and type everything that appears on the terminal verbatim. It has complete VT100 support and configurable gemonetry.
I added an install script so that users can completely replace the
Bash()tool with the ptyai MCP.claude-code doesn't need special prompting, it just instinctively knows how to use a terminal and goes about its business running all those interactive programs it could never run until now... Marvelous!