Oxide Terminal / docs
Docs / Using Oxide / Prompt & shell integration

Prompt & shell integration

Oxide can compile a powerline prompt from TOML segments and inject it into your shell — without ever writing to your dotfiles. Or it can stay out of the way entirely and leave starship exactly as it is.

Two independent switches

Key Default What it controls
shell.integration true The hooks: OSC 133 semantic markers, OSC 7 directory reporting, command timing, and the silent-cd widget the file tree uses.
prompt.enabled true Whether Oxide also builds and sets PROMPT. Turn it off to keep your own.

They're deliberately separate. integration = true with enabled = false is the setup for anyone already running starship, powerlevel10k, or a prompt they've spent years on: the file tree can still cd your shell, and your prompt is untouched.

[shell]
integration = true

[prompt]
enabled = false    # keep starship / p10k / your own

How injection works

Oxide writes generated scripts to ~/.cache/oxide/ on launch and points the child shell at them through the environment. Your real dotfiles are read, never modified.

zsh

Oxide sets ZDOTDIR to a shim directory containing its own .zshenv, .zprofile, and .zshrc. Each one restores ZDOTDIR to your real value, sources your counterpart file, and only then layers Oxide's init.zsh on top — so its precmd hook, and therefore PROMPT, wins over anything your config set. Once the rc files are done, ZDOTDIR is handed back to your own value, so subshells resolve normally.

bash

Oxide launches bash with --init-file pointing at a generated init.bash, which emulates the login profile chain first. Because --init-file and -l conflict, the login flag is dropped from shell.args for that invocation.

Other shells

fish, nushell, csh, and friends run completely normally — they just get no injection, and therefore no Oxide prompt, no OSC 133 markers, and no silent cd. Everything else in Oxide works regardless, including the file tree following your cd and the status bar's git state: those read the PTY's foreground process directly rather than asking the shell.

Opening a file in your editor still works too. Because only the shell knows what $EDITOR is, Oxide types a command to find out — and since the Bourne syntax it uses is a parse error in fish and the csh family, those shells get it handed to /bin/sh instead. The one requirement is that $EDITOR be exported (set -gx EDITOR nvim in fish), since a variable local to your shell isn't visible to /bin/sh.

What integration gives you

  • OSC 133 markersA and B around the prompt, C when a command starts, D with its exit status when it finishes.
  • OSC 7 — the working directory reported on every prompt.
  • Command timing — used by the duration segment.
  • Silent cd — pressing c in the file tree writes a path to ~/.cache/oxide/cd/<session> (one file per shell, keyed by the OXIDE_SESSION variable in its environment) and triggers a zle widget, which cds and redraws the prompt in place. Nothing is echoed and no command lands in your history.
  • Silent command runs — the same trick for commands only the shell can resolve. Opening a file from the tree, or cmd-, for your config, or a workspace's startup command, hands ~/.cache/oxide/run/<session> to a widget that runs it with the terminal attached, so a full-screen editor takes over the way it should while the command line itself is never shown or recorded in shell history. The widget emits its own C and D markers, so the run still shows in the command log with its exit status.

With prompt.enabled = false your own prompt is kept, so the markers can't ride inside it: the A marker is emitted by the prompt hook just before your prompt draws instead, and B (where input begins) is not emitted at all. Everything that keys off A — prompt jumping, workspace startup commands waiting for a ready shell — works either way.

Anatomy of the prompt

The prompt is a list of segments, each with a foreground color, a background color, and a bold flag, joined by a powerline separator drawn in the neighbouring colors.

[prompt]
enabled              = true
separator            = "\ue0b0"  # the powerline right arrow
end                  = "\ue0b0"  # closing glyph; defaults to `separator`
newline_before_input = false    # put the cursor on its own line

[[prompt.segments]]
kind    = "cwd"
fg      = "#11111b"
bg      = "#89b4fa"
bold    = true
options = { style = "truncate_to_repo", max_len = 40 }

Segments render in the order you declare them. Some hide themselves: git disappears outside a repository, exit_status when the last command succeeded (unless you ask otherwise), duration for anything under two seconds, env when the variable is empty.

Segment kinds

kind Options Renders
cwd style, max_len The working directory. style is "full" (~-abbreviated path), "truncate_to_repo" (path relative to the git root, prefixed by the repo name — the default), or "basename". Longer than max_len (default 40) is truncated from the left with an ellipsis.
git show_dirty, dirty_bg, ahead_behind A branch glyph (U+E0A0) and the branch name, or a short SHA when detached. With show_dirty the segment switches to dirty_bg when tracked files are modified; with ahead_behind it appends ⇡n and ⇣n against the upstream. Hidden outside a repo.
exit_status hide_on_success ✗ 1 for the last command's status. Hidden on success by default.
time format The clock, in strftime form — default "%H:%M".
duration How long the last command took, as 4.2s or 2m11s. Shown only past two seconds.
user The current username.
host The short hostname.
text text A literal string — an icon, a label, whatever you like.
env var The value of an environment variable, hidden when it's empty. The name must be alphanumeric or underscores.

Examples

Minimal: directory and branch

[[prompt.segments]]
kind = "cwd"
bg   = "#7d9bb8"
fg   = "#100d0c"

[[prompt.segments]]
kind = "git"
bg   = "#a6b86a"
fg   = "#100d0c"

With timing and a clock

[[prompt.segments]]
kind    = "duration"
bg      = "#e5a458"
fg      = "#100d0c"

[[prompt.segments]]
kind    = "time"
bg      = "#3a2e28"
fg      = "#a3938a"
options = { format = "%H:%M:%S" }

Two lines

newline_before_input = true puts your typing on its own line under the segments — handy with long paths.

[prompt]
newline_before_input = true

Without powerline glyphs

If you'd rather not depend on a Nerd Font, replace the separators with plain characters:

[prompt]
separator = " "
end       = "›"

The generated config file writes these as literal glyphs; TOML's \uXXXX escapes are equivalent and easier to read in a diff.

Applying changes

Prompt and shell settings are baked into the init script when a shell starts, so unlike fonts and colors they don't hot-reload. Open a new tab (cmd-t) to see the change; existing shells keep the prompt they were born with.

Oxide checks whether git is really available before using it in the prompt. On a Mac without the Command Line Tools, /usr/bin/git is an installer shim that would pop a GUI dialog from inside your prompt — Oxide detects that case and skips git entirely rather than trapping you in a dialog loop.