Appearance
Shell Integration
Otty injects small shell hooks that emit OSC 133 (FTCS) prompt marks. These power command outlines, working-directory tracking, and exit-status indicators.
📸 TL;DR
Our recommendation is to keep this default value: enabled.
Supported shells
- zsh
- bash
- fish
Auto-detected from $SHELL. Other shells work as terminals but don't get the integration features.
What's emitted
| Sequence | When | Why |
|---|---|---|
OSC 133 ; A | Right before drawing the prompt | Marks prompt boundaries |
OSC 133 ; B | After the prompt, before input | Distinguishes prompt from typed input |
OSC 133 ; C | When the command starts running | Output begins here |
OSC 133 ; D ; <exit> | When the command finishes | Records exit status |
OSC 7 ; file://<host><cwd> | At every prompt | Tracks pane cwd |
Otty consumes these to build per-pane outlines and gutter indicators. See Outline.
Features that rely on it
Otty is a perfectly good terminal without shell integration — but the features below are driven by the marks above, so they go dark (or fall back to a guess) when it's off. Each one is flagged in Settings: turning it on while integration is disabled still saves the setting, but pops a warning that it won't do anything until you switch integration back on.
Command status — OSC 133 ; C / D ; <exit>
- Outline & command navigation — the per-pane command list and jump-to-prompt. See Outline.
- Exit-status gutter dots — the green / red status marker beside each command.
- Tab badges — When Command Finishes and When Command Fails dots on the tab.
- Command notifications & sounds — Notify on Command Finish, Notify on Error Exit, Beep on Error Exit.
- On-device autocomplete learning — only commands that exit
0are learned. - Re-run processes on session restore — restoring what was running needs the command-start mark.
Working directory — OSC 7
- Inherit working directory for new tabs, splits, and windows.
- Auto-record visited folders — the database behind Frequent Folders (
otty jumpand Open Quickly's Folders tab).
Prompt boundary — OSC 133 ; B
- Autocomplete — inline ghost text and the candidate panel locate the prompt from the input mark. Without it they fall back to a ~1s timer and lose accuracy.
Injected wrappers
edit/view/jump/learnshell functions (the Omitottyprefix option) and any custom aliases.- SSH integration — the
sshwrapper that forwards env, installs terminfo, and enables remote file/git access.
Everything else — terminal bell, app notifications (OSC 9 / 777), and code-agent badges (delivered over IPC) — works regardless.
How it loads (and how to audit it)
The integration scripts ship as readable, code-signed files inside the app bundle, so you can read exactly what Otty runs in your shell before trusting it:
Otty.app/Contents/Resources/shell-integration/
├── otty-integration.zsh # the zsh payload (OSC 133, ssh wrapper, …)
├── otty-integration.bash
├── otty-integration.fish
├── zsh/.zshenv # zsh loader (ZDOTDIR entry)
└── fish/vendor_conf.d/otty-shell-integration.fish # fish loaderNothing is synthesized at runtime or written to a hidden temp file — these are the actual scripts, signed and notarized with the app.
How they reach your shell depends on the shell, and is controlled entirely by the Settings → Shell → Shell Integration toggle:
- zsh — Otty points
ZDOTDIRat its bundledzsh/dir for the session it launches. That.zshenvimmediately restores your realZDOTDIR, runs your own.zshenv, then loads Otty's payload on the first prompt (so its marks win over plugin managers). Your~/.zshrcand other dotfiles are not edited. - fish — Otty prepends its bundled dir to
XDG_DATA_DIRS, so fish auto-loads thevendor_conf.dentry, which then removes that dir again so child processes don't inherit it. Yourconfig.fishis not edited. - bash — bash has no clean per-spawn auto-load, so Otty adds a small, clearly-marked block to
~/.bashrc(and a~/.bash_profileshim) that sources the bundled payload only when launched by Otty. The block is inert in other terminals and removed when you turn the toggle off.
tmux is the one exception for zsh/fish: a tmux server captures its environment once at start, so the ZDOTDIR / XDG_DATA_DIRS injection can't reach panes it later spawns. When tmux is installed, Otty additionally adds the same guarded managed block to your zsh/fish rc so tmux panes still get the integration. Turning the toggle off removes every block.
Opting out
Everywhere — Settings (no config file needed). Open Settings → Shell → Shell Integration and turn off Provide Shell Integration. Otty pops a Turn off shell integration? confirmation, then removes the line it added to your shell startup files (the bash block and any tmux managed blocks) and stops the per-session ZDOTDIR / XDG_DATA_DIRS injection for zsh and fish. Prompt marks, command status, CWD tracking, the edit/view/jump wrappers, custom aliases, and SSH integration go dark in every Otty shell. Toggle it back on anytime — the same dialog re-installs everything. This is the same shell-integration switch you'd set in your config file, so the two stay in sync.
Per-shell — in your rc file. Leave integration on globally but skip it for one shell by exporting, before Otty's payload loads:
bash
export OTTY_DISABLE_INTEGRATION=1Per-window — by launching with the flag:
bash
otty open --no-integrationVerifying
In an integrated shell:
bash
echo "marks: $OTTY_INTEGRATION"
# marks: 1Or watch the Outline gutter — it only renders when marks arrive.
See also
- Outline — jumping between commands.
- Files and Links — path detection (works without integration).