Fixing Cursor Agent Terminal Hangs: zsh, bash, fish Shell Solutions

One of the most common issues when using Cursor's Agent mode is terminal hangs. The agent terminal loads your shell configuration (.zshrc, .bashrc, .bash_profile, .config/fish/config.fish), and if these files contain interactive plugins like Oh My Zsh, Powerlevel10k, or custom prompts, the agent gets stuck waiting for user input. This guide provides proven fixes for all major shells.
Understanding the Problem
What Happens
- Cursor Agent opens a new terminal
- The terminal loads your shell configuration file
- Interactive plugins (Oh My Zsh, p10k, etc.) initialize
- Some plugins wait for user interaction
- The agent terminal hangs indefinitely
Common Culprits
| Shell | Config File | Common Hanging Plugins |
|---|---|---|
| zsh | .zshrc | Oh My Zsh, p10k, zsh-autosuggestions |
| bash | .bashrc, .bash_profile | bash-it, custom PS1 with git status |
| fish | ~/.config/fish/config.fish | Oh My Fish, fisher, custom prompts |
Solution 1: Environment Variable Detection (Recommended)
The cleanest solution is to detect when Cursor is running and skip interactive configuration.
For zsh (.zshrc)
Add this at the very top of your .zshrc:
# Skip interactive configuration for non-interactive shells
if [[ -n "$CURSOR_AGENT" ]] || [[ "$TERM_PROGRAM" == "cursor" ]] || [[ -n "$COMPOSER_NO_INTERACTION" ]]; then
# Minimal prompt for Cursor Agent
PS1="$ "
return
fi
# Your existing interactive configuration below...
# export ZSH="$HOME/.oh-my-zsh"
# source $ZSH/oh-my-zsh.sh
# etc.
For bash (.bashrc)
Add this at the very top of your .bashrc:
# Skip interactive configuration for Cursor Agent
if [[ -n "$CURSOR_AGENT" ]] || [[ "$TERM_PROGRAM" == "cursor" ]] || [[ -n "$COMPOSER_NO_INTERACTION" ]]; then
PS1="$ "
return
fi
# Your existing configuration below...
For bash (.bash_profile)
Same approach for .bash_profile:
# Detect Cursor Agent environment
if [[ -n "$CURSOR_AGENT" ]] || [[ "$TERM_PROGRAM" == "cursor" ]]; then
PS1="$ "
return
fi
For fish (config.fish)
Add at the top of ~/.config/fish/config.fish:
# Skip interactive configuration for Cursor Agent
if test -n "$CURSOR_AGENT"; or test "$TERM_PROGRAM" = "cursor"; or test -n "$COMPOSER_NO_INTERACTION"
function fish_prompt
echo '$ '
end
return
end
# Your existing configuration below...
Solution 2: Non-Interactive Shell Detection
Use POSIX-standard non-interactive shell detection:
Universal Approach (Works for bash, zsh)
# At the top of .bashrc or .zshrc
case $- in
*i*) ;;
*)
# Non-interactive shell (Cursor Agent)
PS1="$ "
return
;;
esac
# Alternative one-liner
[[ $- != *i* ]] && PS1="$ " && return
Solution 3: Minimal Agent Shell
Create a dedicated configuration for Cursor Agent:
Step 1: Create Agent Shell Config
# Create ~/.cursor-shell-rc
# This is a minimal RC file for Cursor Agent
# Basic PATH
export PATH="/usr/local/bin:/usr/bin:/bin:$HOME/.local/bin"
# Aliases that work without plugins
alias ll='ls -la'
alias ..='cd ..'
# Minimal prompt
PS1="\w $ "
Step 2: Point Cursor to Minimal Config
In Cursor Settings or .cursor/agent-config.json:
{
"terminal": {
"shell": "/bin/zsh",
"shellArgs": ["--rcs", "~/.cursor-shell-rc"]
}
}
Or set environment variable in Cursor:
{
"terminal.integrated.env.linux": {
"ZDOTDIR": "~/.cursor-zsh"
},
"terminal.integrated.env.osx": {
"ZDOTDIR": "~/.cursor-zsh"
}
}
Step 3: Create ~/.cursor-zsh Directory
mkdir -p ~/.cursor-zsh
cat > ~/.cursor-zsh/.zshrc << 'EOF'
# Minimal zsh config for Cursor Agent
export PATH="/usr/local/bin:/usr/bin:/bin:$HOME/.local/bin"
PS1="%1~ $ "
EOF
Solution 4: Plugin-Specific Fixes
Oh My Zsh
# In .zshrc - wrap Oh My Zsh loading
if [[ -z "$CURSOR_AGENT" ]] && [[ -z "$COMPOSER_NO_INTERACTION" ]]; then
export ZSH="$HOME/.oh-my-zsh"
ZSH_THEME="powerlevel10k/powerlevel10k"
plugins=(git zsh-autosuggestions zsh-syntax-highlighting)
source $ZSH/oh-my-zsh.sh
else
# Minimal config for Cursor
PS1="$ "
fi
Powerlevel10k (p10k)
# In .zshrc
if [[ -z "$CURSOR_AGENT" ]] && [[ -z "$COMPOSER_NO_INTERACTION" ]]; then
# Enable Powerlevel10k instant prompt
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi
# Load p10k configuration
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
else
# Skip p10k for Cursor Agent
PS1="$ "
fi
zsh-autosuggestions
# Only load in interactive shells
if [[ -o interactive ]] && [[ -z "$CURSOR_AGENT" ]]; then
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
fi
bash-it
# In .bashrc
if [[ -n "$PS1" ]] && [[ -z "$CURSOR_AGENT" ]]; then
export BASH_IT="$HOME/.bash_it"
source "$BASH_IT/bash_it.sh"
else
PS1="\w\$ "
fi
Oh My Fish
# In config.fish
if test -n "$CURSOR_AGENT"
# Skip OMF for Cursor Agent
function fish_prompt
echo (prompt_pwd) '> '
end
else
# Load Oh My Fish
if test -f $HOME/.local/share/omf/pkg/omf/functions/omf.fish
source $HOME/.local/share/omf/pkg/omf/functions/omf.fish
end
end
Solution 5: Timeout-Based Detection
Add a timeout to detect hanging prompts:
# In .zshrc or .bashrc
# If the shell takes too long to initialize, show a warning
__cursor_shell_timeout() {
local start_time=$(date +%s)
# Your normal config here
local end_time=$(date +%s)
local elapsed=$((end_time - start_time))
if [[ $elapsed -gt 3 ]] && [[ -n "$CURSOR_AGENT" ]]; then
echo "WARNING: Shell took ${elapsed}s to initialize. Consider optimizing your config."
fi
}
__cursor_shell_timeout
Solution 6: Cursor-Specific Environment Variables
Set these in Cursor's terminal settings:
In Cursor Settings (settings.json)
{
"terminal.integrated.env.linux": {
"CURSOR_AGENT": "1",
"COMPOSER_NO_INTERACTION": "1",
"PAGER": "cat",
"GIT_PAGER": "cat"
},
"terminal.integrated.env.osx": {
"CURSOR_AGENT": "1",
"COMPOSER_NO_INTERACTION": "1",
"PAGER": "cat",
"GIT_PAGER": "cat"
},
"terminal.integrated.env.windows": {
"CURSOR_AGENT": "1",
"COMPOSER_NO_INTERACTION": "1",
"PAGER": "cat",
"GIT_PAGER": "cat"
}
}
Testing Your Fix
Method 1: Simulate Agent Terminal
# Open a terminal with Cursor Agent environment
CURSOR_AGENT=1 COMPOSER_NO_INTERACTION=1 zsh -l
# If it loads quickly without prompts, your fix works
Method 2: Time Your Shell Startup
# Time zsh startup
time zsh -i -c exit
# Time bash startup
time bash -i -c exit
# Should be under 1 second for Agent environments
Method 3: Use Cursor's Built-in Terminal
- Open Cursor
- Open integrated terminal (
Ctrl +`) - Check if it loads without delay
- Run a simple command:
echo $CURSOR_AGENT
Debugging Shell Startup
Enable Debug Mode
# For zsh - trace startup
zsh -xv 2>&1 | head -50
# For bash - trace startup
bash -x -l 2>&1 | head -50
Profile Shell Startup
# For zsh
zsh -xv 2>&1 | ts '[%H:%M:%.S]' | head -100
# Check which lines take the longest
Quick Reference: Fix by Shell
zsh Fix Summary
# Add to TOP of ~/.zshrc
if [[ -n "$CURSOR_AGENT" ]] || [[ "$TERM_PROGRAM" == "cursor" ]]; then
PS1="$ "
return
fi
# Then your normal config
bash Fix Summary
# Add to TOP of ~/.bashrc
if [[ -n "$CURSOR_AGENT" ]] || [[ "$TERM_PROGRAM" == "cursor" ]]; then
PS1="$ "
return
fi
# Then your normal config
fish Fix Summary
# Add to TOP of ~/.config/fish/config.fish
if test -n "$CURSOR_AGENT"; or test "$TERM_PROGRAM" = "cursor"
function fish_prompt
echo '$ '
end
return
end
# Then your normal config
Common Mistakes
| Mistake | Why It Fails | Fix |
|---|---|---|
| Detection at bottom of config | Interactive plugins already loaded | Move detection to TOP |
Using $TERM instead of $TERM_PROGRAM | $TERM is xterm-256color | Use $TERM_PROGRAM or $CURSOR_AGENT |
Forgetting return or exit | Config continues loading | Always return after minimal setup |
| Only checking one variable | Cursor may set different vars | Check multiple variables |