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 markers —
AandBaround the prompt,Cwhen a command starts,Dwith its exit status when it finishes. - OSC 7 — the working directory reported on every prompt.
-
Command timing — used by the
durationsegment. -
Silent
cd— pressing c in the file tree writes a path to~/.cache/oxide/cd/<session>(one file per shell, keyed by theOXIDE_SESSIONvariable in its environment) and triggers a zle widget, whichcds 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 ownCandDmarkers, 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.