Nermal
Reference

Shell integration

What Nermalinjects into your shell, and what it buys you.

A terminal that only sees bytes cannot tell a prompt from output, or a finished command from a hung one. Nermal's shell integration closes that gap: the shell reports where prompts begin, what was submitted, what it exited with, and where it is.

You do not install it. It is injected when the pane's shell starts, and removes itself from the equation if you run the same shell elsewhere.

Which shells

ShellHow it is injected
zshA throwaway ZDOTDIR whose files source yours first, then Nermal's. Your Nermal_USER_ZDOTDIR is preserved.
bashAn rcfile that sources your own first.
fishA -C init command.
PowerShellAn encoded init command that wraps your existing prompt function and PSReadLine's line reader.
nushellA --config wrapper whose config.nu sources yours first, then adds Nermal's hooks. Local panes only.
WSL (Windows)The distro's shell is bootstrapped with the same scripts.
Remote panesThe same three POSIX shells, bootstrapped over the SSH connection. Toggle per profile with Settings → SSH → a profile → Advanced → Session → Shell integration.

Nermal_SHELL_INTEGRATION is set once it is active, and guards against a second injection when shells nest. It does not put the integration into a nested shell — shells you start yourself have none.

A shell launched with arguments you wrote — shell.args, or a custom_shells entry — is left alone, because Nermal's injection would conflict with the flags you chose. Arguments Nermal's own detection supplied (Git Bash's -i -l, a WSL row's --distribution) do not count, so those rows are still integrated.

What it reports

SignalSequenceUsed for
Prompt begins / input beginsOSC 133;A, 133;BThe prompt layer: suggestions, completion, multi-line editing
Command submittedOSC 133;CKnowing a command is running; agent detection on Windows, where ConPTY exposes no foreground process group
Command finished, with exit codeOSC 133;DThe "finished after 42s" notification, failure marks in history
Working directoryOSC 7New tabs and splits opening in the right place, the sidebar's repo grouping, the git branch readout
Editing mode (vi / emacs)OSC 133;VMatching Nermal's key handling to your shell's mode
Window titleOSC 0Tab labels. Only PowerShell is given this — zsh, bash, and fish already set a title of their own, and Nermalreads whatever they emit

What turns off without it

Run a shell Nermaldoes not integrate with, and everything below still works — it just falls back to less precise sources:

  • Ghost suggestions, the completion menu, and ⌃ R's fuzzy history
  • "Command finished" notifications and the failure marks in history search
  • Exact working-directory tracking

Panes, splits, scrollback, search, SSH, and the CLI are unaffected.

The working-directory fallback is worth knowing in detail, because it is not available everywhere. Where Nermalcan see the pane's processes it reads the foreground one's own working directory instead — a local pane on macOS or Linux, or a pane in a remote workspace, where the Nermal-server on that host does the reading. It is a poll, not a report: it is sampled while the pane is producing output, at most twice a second, so it can trail a cd until the pane writes something again. A local pane on Windows and a pane connected to an SSH host have no fallback at all — on the far end of an ssh there is no process table to read, so a shell that does not report its directory leaves the pane showing the last directory that did.

Shells you start yourself

The injection happens when the pane's shell is launched. Type zsh at a bash prompt — or bash, or sh, or docker exec … sh — and that second shell is a new process, launched by your shell rather than by Nermal. It emits no prompt marks and no OSC 7, and the pane keeps showing the directory the outer shell last reported until you exit back to it.

On your own machine this is usually invisible, because prompt frameworks report the directory themselves: oh-my-zsh does it from omz_termsupport_cwd in lib/termsupport.zsh. Over SSH it is not. That file returns early when SSH_CLIENT or SSH_TTY is set, so on a remote host a zsh you started by hand reports nothing at all, and neither does Nermal.

To get integration into that shell, make it the shell Nermalstarts:

  • A remote host. Nermalasks the host for $SHELL when it connects and bootstraps that shell, so chsh -s /bin/zsh (then reconnect) is what switches it. A login script under Advanced → Session that runs zsh does not — those lines are typed into the session after the shell is already up, so they nest like anything else. Neither does exec zsh from your .bashrc: it replaces the process Nermalset up.
  • A local pane. Set Settings → Terminal → Shell → Program (or shell in config), and leave Arguments empty — arguments you write turn the injection off.

If the Files panel stopped following a nested shell →

Per-pane history

When per_pane_history is on, the integration is also what makes it work. It runs after your own rc file — which is the only reason it can: $HISTFILE is yours to set, wherever you like, and nothing outside the shell knew where it pointed until then.

The sequence is: seed the pane's private file from your real history so it does not start blank, record how much was seeded, repoint $HISTFILE, and merge everything past that mark back when the pane closes.

More about history →

Remote shells

For a remote workspace or an SSH pane, the same scripts are sent over the connection at login, so a remote pane reports its cwd, exit codes, and prompt marks exactly like a local one. Turn it off for a particular host under that profile's Advanced → Session.

Sponsor