New Ghostty splits/tabs/windows should open in the current working directory.
On some setups they open at / instead. This documents the root cause and a robust
zsh fix, including the subtle case where the pane is running a long-lived TUI such as
Claude Code.
- Host: ASUS Ascent GX10 (NVIDIA DGX Spark / GB10),
aarch64 - OS: Ubuntu 24.04, zsh + Prezto
- Terminal: Ghostty 1.3.1, launched as a systemd/GTK single-instance app
(
ghostty --gtk-single-instance=true), spawning the shell viash -c /usr/bin/zsh
Ghostty (window-inherit-working-directory = true, the default) tracks each surface's
working directory from the OSC 7 escape sequence the shell emits:
ESC ] 7 ; kitty-shell-cwd://<host><path> BEL
If the shell never emits OSC 7, Ghostty has nothing to inherit and falls back to the
directory the Ghostty process was started in — which for a systemd/desktop-launched
instance is /. Hence new panes open at /.
Ghostty ships zsh integration that emits OSC 7 automatically, injected by setting
ZDOTDIR to its integration dir. That injection is bypassed here because the shell is
started via sh -c /usr/bin/zsh (not launched directly by Ghostty), and its .zshenv
guard ([[ -o interactive ]] + a ${(%):-%x} self-path trick) doesn't resolve in this
setup. Net effect: the OSC 7 hook is never registered, so cwd is never reported.
Append to the end of ~/.zshrc (after Prezto/your prompt framework loads, so nothing
clobbers the hook):
# Report cwd to the terminal via OSC 7 so new Ghostty panes/tabs inherit the
# current directory. (Ghostty's own integration doesn't register on this host.)
autoload -Uz add-zsh-hook
_ghostty_osc7_cwd() { printf '\033]7;kitty-shell-cwd://%s%s\007' "${HOST}" "${PWD}" }
add-zsh-hook -Uz precmd _ghostty_osc7_cwd # every prompt
add-zsh-hook -Uz chpwd _ghostty_osc7_cwd # every cd
# Also report right before a command runs, so a long-lived foreground app
# (e.g. `claude`) that blocks the shell still leaves Ghostty an up-to-date cwd
# for panes/tabs opened while it runs.
add-zsh-hook -Uz preexec _ghostty_osc7_cwdOpen a new pane to pick it up (existing shells: source ~/.zshrc). It's harmless in
other terminals — they ignore the unknown OSC 7.
Ordinary commands (ls) finish instantly and drop you back at a prompt, so precmd
re-reports the directory constantly; whenever you split, you're standing on a fresh report.
A full-screen TUI like Claude Code never returns to a prompt — it holds the terminal
for the whole session, so the shell is blocked and sends no further OSC 7. New panes
opened during it can only inherit the last report made before it launched. preexec
guarantees that last report is emitted at the exact handoff instant, right before the app
takes over.
- OSC 7 (report cwd): never — so it does not overwrite Ghostty's stored directory
- No terminal reset (no
ESC cRIS, noESC[!psoft reset) — so it does not erase it - It does: enter the alternate screen (
?1049h), synchronized output (?2026h/l), mouse tracking, bracketed paste, focus reporting, Kitty keyboard protocol, and emits OSC 0 (title), OSC 8 (hyperlinks), OSC 9 (notification)
Conclusion: Claude Code is a well-behaved TUI that reports no directory and resets nothing.
The / fallback is purely the absence of a fresh cwd report while it holds the terminal —
which the preexec hook closes.
- Split / tab / new-window from within a pane → inherits that pane's cwd. ✅ Fixed.
- A brand-new window from the desktop icon / taskbar → doesn't inherit from any surface;
it uses the daemon's own cwd (
/). To make those start at home instead, set a fixed default in Ghostty config:working-directory = ~.
Emit OSC 7 from zsh on precmd + chpwd + preexec. The first two fix ordinary panes;
preexec fixes panes opened while a long-lived TUI (Claude Code) holds the terminal.