Skip to content

Run terminal surfaces under zmx via a Ghostty command-wrapper#368

Merged
sbertix merged 2 commits into
mainfrom
sbertix/cwd-inheritance
Jun 1, 2026
Merged

Run terminal surfaces under zmx via a Ghostty command-wrapper#368
sbertix merged 2 commits into
mainfrom
sbertix/cwd-inheritance

Conversation

@sbertix
Copy link
Copy Markdown
Collaborator

@sbertix sbertix commented May 30, 2026

Problem

Terminal surfaces run under zmx for session persistence. The surface command was set to zmx attach <id>, which had two side effects:

  • It overrode the user's Ghostty command config, so a custom default shell (e.g. command = /opt/homebrew/bin/nu) was ignored and $SHELL ran instead (Closes Using custom shell in Supacode #362).
  • Ghostty's shell detection and integration targeted zmx instead of the real shell, so OSC 7 working-directory reporting only worked if the user's own shell config emitted it. When it did not, the tracked pane cwd went stale and new splits inherited the wrong directory.

Fix

Add a command-wrapper option to GhosttyKit and use it instead of overriding command:

  • Interactive surfaces leave command unset and pass zmx attach <id> as a command-wrapper. Ghostty resolves and integrates the real shell (or the user's configured command), applies the macOS login(1) wrapping, then the wrapper argv is prepended to the result. The shell behaves exactly as it would without zmx, and zmx wraps the whole thing for persistence.
  • Blocking-script surfaces opt out via a per-surface disable_shell_integration, preserving their self-managed OSC 133 mechanics.
  • Explicit-command (script) surfaces continue to wrap the command string directly.

The GhosttyKit change ships as an out-of-tree patch (patches/ghostty-command-wrapper.patch) applied to the pinned submodule at build time by scripts/build-ghostty.sh and reverted on exit. The submodule pin tracks upstream; there is no fork. The feature is generic and upstreamable.

Result

  • Split cwd inheritance stays live regardless of the user's shell or rc, because Ghostty integrates the real shell and OSC 7 flows again.
  • A custom Ghostty command (e.g. nushell) is honored under zmx. Fixes Using custom shell in Supacode #362.

Notes

  • The previous shell-integration = none override is removed, since Ghostty now integrates the real shell rather than the zmx command.
  • wait-after-command is left at Ghostty's default for interactive surfaces, so a pane closes on shell exit (matching stock Ghostty).

…ull integration

Surfaces used to be launched by handing Ghostty `command = "zmx attach <id>"`,
which overrode the user's `command` config and made Ghostty's shell detection
and integration target zmx instead of the real shell. The fallout: OSC 7 cwd
reporting stopped working unless the user's own rc emitted it (so split cwd
inheritance went stale), a custom `command` (e.g. nushell) was ignored, and the
macOS login(1) treatment was lost.

Add a `command-wrapper` option to GhosttyKit (a small out-of-tree patch applied
to the pinned submodule at build time; the pin is never moved and no fork is
created). The wrapper's argv is prepended to the command Ghostty resolves after
shell resolution, shell integration, and the macOS login(1) wrapping, so the
resolved shell runs as a child of the wrapper.

Supacode now leaves `command` unset for interactive surfaces and instead passes
`zmx attach <id>` as the wrapper. Ghostty resolves and integrates the user's real
shell exactly as it would without zmx (honoring `command` and `shell-integration`
config), login(1) preserves the integration env via `-p`, and zmx wraps the whole
thing for session persistence. Explicit commands (scripts) keep wrapping the
command string as before. The global `shell-integration = none` override is
dropped, since Ghostty now integrates the real shell rather than the zmx command.

scripts/build-ghostty.sh applies patches/*.patch to the submodule working tree
before building and reverts on exit, so the submodule stays clean and pinned to
upstream. A patch that no longer applies fails the build loudly.
@sbertix sbertix requested a review from khoi May 30, 2026 01:21
@tuist
Copy link
Copy Markdown

tuist Bot commented May 30, 2026

🛠️ Tuist Run Report 🛠️

Builds 🔨

Scheme Status Duration Commit
supacode 2m 33s eb460e8d5

# Conflicts:
#	supacodeTests/ZmxClientTests.swift
@sbertix sbertix merged commit 9639276 into main Jun 1, 2026
2 checks passed
@sbertix sbertix deleted the sbertix/cwd-inheritance branch June 1, 2026 01:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Using custom shell in Supacode

1 participant