Inline shell mode (! commands) runs non-interactive zsh, breaking history, oh-my-zsh, and other interactive shell features

Resolved 💬 2 comments Opened Apr 1, 2026 by navarro165 Closed May 9, 2026

Summary

Claude Code's inline shell mode (\! <command>\) executes commands in a non-interactive zsh shell, which breaks a wide range of shell features that users rely on daily. This makes the inline shell mode feel unreliable compared to just opening a terminal.

Reproduction

! history
# omz_history:fc:13: no such event: 1

! hgrep somecommand
# omz_history:fc:13: no such event: 1

Any command that depends on shell history (including oh-my-zsh wrappers and aliases like hgrep) fails with this error.

What Breaks

Shell History

Running \! history\ or any history-dependent command fails:

omz_history:fc:13: no such event: 1

Root cause: Claude Code's shell snapshot deliberately sets HISTFILE="", SAVEHIST=0, and HISTSIZE=30 for isolation between commands. This has a critical side effect: oh-my-zsh only sets these variables when they are unset, so the snapshot's isolation values block oh-my-zsh from loading the user's actual history. The history builtin (wrapped by oh-my-zsh as omz_history) calls fc -l 1 internally — with no history loaded, event 1 doesn't exist and the command fails.

oh-my-zsh / zsh Interactive Features

  • hgrep (and similar history-search aliases that wrap fc) silently fail or error
  • Functions that check [[ -o interactive ]] to conditionally set up state won't initialize
  • Some prompt-related functions and completions break

Environment Variables Blocked by Snapshot

  • HISTFILE, HISTSIZE, SAVEHIST — pre-set to isolation values ("", 30, 0), preventing oh-my-zsh from applying user defaults
  • Any exports in .zshrc guarded by interactivity checks are skipped

Shell Snapshot Workaround Has Limits

Claude Code does create shell snapshots (e.g. ~/.claude/shell-snapshots/snapshot-zsh-*.sh) that capture functions and aliases from the user's environment. This works well — custom functions, aliases, etc. do load correctly. But it doesn't solve stateful or interactive-only features because each ! command still runs in a fresh, isolated, non-interactive shell with history stripped out.

Expected Behavior

Ideally, inline shell mode commands should run in an environment that matches the user's interactive shell as closely as possible — same HISTFILE, same shell options, same initialization path. At minimum:

  1. Load the user's actual history file so history, fc, and history-search tools work
  2. Respect HISTFILE / HISTSIZE / SAVEHIST from the user's shell config rather than overriding them with isolation values
  3. Optionally launch the shell as interactive (zsh -i) so that oh-my-zsh and similar frameworks initialize fully — though this comes with tradeoffs (slower startup, prompt rendering side effects) that may warrant making it opt-in

Environment

  • OS: macOS (Darwin 25.3.0)
  • Shell: zsh with oh-my-zsh
  • Claude Code: latest
  • History file: ~/.zsh_history (3,000+ entries, works fine in normal terminals)

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗