Solarized Dark terminal showing eza, bat, git-delta, fzf

Terminal — Getting Started & Cheatsheet

Solarized Dark default (switchable) · eza · bat · git-delta · difftastic · glow · vivid · procs · lnav · xh · slm · fzf · nvimpager · sandbox · vhs · basalt
view full screenshot

Getting started / what's installed

Brew packages (recently added)

ezals replacement with icons + git status
batsyntax-highlighted cat / man pager backend
git-deltagit diff/log/blame pager
difftasticsyntactic diff for ad-hoc compares (non-git)
glowrender markdown to ANSI (powers md)
vividgenerates LS_COLORS palettes
procsmodern ps replacement (Rust)
tailspinlive-log highlighter (tspin); Solarized via ~/.config/tailspin/theme.toml
lnavTUI log navigator; Solarized via built-in theme (see lnav section)
btopmodern top replacement; follows theme-set (10 themes, restart tier)
ctoptop-like container-metrics TUI (CPU/mem/net/IO; enter expands one; needs Docker daemon; raw, no alias)
gh dashGitHub TUI for PRs/issues/notifications (ghd abbr); Solarized via ~/.config/gh-dash/config.yml? help, s/S next/prev section, j/k rows, enter preview, o open in browser, r refresh, / filter, q quit
duainteractive disk-usage analyzer with TUI deleter (dua i; raw, no alias)
dufmodern df replacement (grouped, color-coded; raw, no alias)
dusttree-style du replacement (largest-first, bar graphs; raw, no alias)
xhmodern HTTP client (HTTPie-compatible CLI); Solarized via ~/.config/xh/config.json
fzffuzzy finder + Ctrl-R / Ctrl-T bindings

House rules (per CLAUDE.md)

What aliases you get

catbat --paging=never
lessfunction → bat wrapper (file = full decoration; pipe = --plain)
mdglow --style ~/.config/glow/glamour.json --width $COLUMNS (fish fn; wraps to pane width)
mdpmd -p (paged via $PAGER)
lseza --group-directories-first --icons
lleza -lh --git --icons --group-directories-first
lall -a
vim / vimdiffnvim (guarded on command -v nvim)
vicommand vim (legacy minimal vim, suppresses recursive alias)
psprocs (Solarized; PID asc; ps-like columns)
pshprocs --load-config ~/.config/procs/procs-heavy.toml (CPU desc, trimmed)
topbtop (modern colorful TUI, follows theme-set; command top for BSD top)

BSD \ls still works (escape skips alias) and uses OMZ's default LSCOLORS. Use command less to reach real less for less +F, -R, etc. command ps / \ps / /bin/ps reach legacy ps.

eza ls replacement

Most-used flags

ezasimple list (icons via alias)
eza -llong form
eza -lhlong + human sizes
eza -lashow hidden
eza --gitadd a git-status column
eza --tree -L 2tree view, depth 2
eza -s modifiedsort by mtime
eza -s sizesort by size
eza --group-directories-firstdirs on top (default in alias)

Recipes

ll -s modified -rmost recently changed first
ll --git-ignorehide gitignored files
eza -laT --git-ignore -L 3tree, hidden, no gitignored, 3 deep
eza -l --time-style=long-isoISO timestamps

Colors come from LS_COLORS (set by vivid). Icons need a Nerd Font in your terminal.

procs modern ps

Most-used flags

procsall your processes, Solarized columns, sort by PID
procs fishregex search across PID/User/Command (replaces ps | grep)
procs --treeparent/child tree view
procs --watchrefresh every 1s; --watch-interval N for custom
procs --sortd UsageCpusort by CPU descending (asc = --sorta)
procs --insert VmRssadd a column on the fly (kinds: procs --list)

Aliases & configs

psprocs (default Solarized view)
pshprocs --load-config ~/.config/procs/procs-heavy.toml (CPU desc, trimmed)
~/.config/procs/procs.tomldefault config (in-repo, symlinked)
~/.config/procs/procs-heavy.tomltrimmed columns + CPU-desc; loaded by psh

Both TOMLs duplicate their [style.*] blocks; procs --load-config replaces the whole config (no inheritance). Edit both when tweaking colors.

macOS caveat

procs on macOS only shows your own processes — Apple gates cross-user visibility behind elevated privileges. To see system daemons (the _appstore, _audiomxd, etc. that ps -ax shows), fall through to legacy: \ps -ax or command ps -ax.

Pipes strip color (color_mode = "Auto"). Prefer procs <pat> over ps | grep <pat> — same result, colors preserved.

Most-used invocations

lnav file.logopen one file (auto-tails new lines)
lnav dir/open every log file in a directory; merged by timestamp
cmd | lnavread from stdin (no positional arg)
lnav -n file.logheadless / no UI (useful for format debugging)

Files we ship

~/.config/lnav/configs/installed/solarized-dark.jsonactivates lnav's built-in Solarized Dark theme
~/.config/lnav/formats/installed/inngest.jsonJSON format for inngest-cli dev stdout
~/.config/lnav/config.jsonlnav's runtime mutable config (not in repo)

Add new formats by dropping a JSON file in formats/installed/ — the installed/ dir is symlinked from the repo, so no bootstrap.sh re-run is needed. (lnav owns the rest of ~/.config/lnav/.) Theme is lnav's built-in (palette matches bat / delta / procs / btop); we don't redefine slots.

Inside the TUI

qquit
e / Enext / prev error
w / Wnext / prev warning
/pat / nsearch / next match
:command prompt (e.g. :filter-in, :goto)
;SQL prompt — query log lines as a table (e.g. SELECT * FROM inngest_dev WHERE level = 'error')
t / itime histogram / global histogram view
TABswitch between log view and bottom prompt

Bottom status bar shows the matched format name (e.g. inngest_dev) when an installed format matches the file.

bat cat with syntax highlighting

Daily use

cat file.rbaliased to bat --paging=never
bat file.rbpaged, with line numbers + git gutter
bat -p fileplain (no decoration)
bat -A fileshow non-printables (whitespace, line endings)
bat -r 10:50 filerange lines 10–50
bat -l json dataforce language
bat --diff fileonly show modified hunks
man <cmd>uses bat -l man via $MANPAGER

Theme & introspection

bat --list-themesall themes
bat --list-languagessupported languages
bat --theme="Solarized (dark)"force theme
$BAT_THEMEenv override

$MANPAGER is set so man stays Solarized: sh -c 'col -bx | bat -l man -p --paging=always'. $MANROFFOPT=-c keeps ANSI sequences intact.

Inside the pager

Space / bpage down / up
/pat / nsearch / next match
g / Gtop / bottom
qquit

bat shells out to less by default — these are less keys.

less wrapper bat for files, plain for pipes

Why a function, not an alias

less is a fish function (in .config/fish/functions/less.fish) that delegates to bat. File arguments get bat's full decoration (line numbers, git gutter); piped input falls back to bat --plain so cmd | less doesn't get bat's STDIN header and stays clean.

$PAGER is not set to bat globally — git/delta and other tools manage their own pagers. The wrapper only shadows interactive less use.

Usage

less file.rbbat with full decoration (paged)
cat file | lessbat --plain (no header)
command less +F logreal less follow-mode
command less -Rreal less raw control chars

Inside the pager, all less keys work (Space/b, /pat, g/G, q) — bat shells out to less.

git-delta git diff pager

Where it kicks in

Wired through git config — anything that paginates a diff uses delta:

git diffside-by-side or unified, syntax-highlighted
git log -pcommit-by-commit diff
git show <rev>single commit
git blamestyled blame
git add -pinteractive — uses delta as the diff filter

Inside delta's pager

n / Nnext / prev file (navigate=true)
/ / ?search
Space / bpage down / up
qquit

Built on less, so less keys all work.

Useful flags

git diff --side-by-sidetwo-column layout
delta --lightforce light theme one-shot
delta --no-gitconfig --diff-highlightminimal preview
git -c core.pager=cat diffbypass delta one-shot

difftastic non-git diff

Where it kicks in

Aliased over diff for ad-hoc file compares outside git. Git diffs still flow through delta (see above) — the two cover different surfaces.

diff a bsyntactic, language-aware diff between two files
diff a/ b/recursive directory diff
diff old.json new.jsontree-sitter parses each side; structural moves are recognized

Bypass to legacy diff

command diff a bskip the alias (/usr/bin/diff)
\diff a bsame; backslash quotes the alias name
/usr/bin/diff a babsolute path bypasses $PATH

Non-interactive shells (scripts, Make, CI) never see the alias — fish aliases don't propagate to non-interactive shells.

Why no theme pin

Difftastic uses ANSI 16-color directly; it inherits the active terminal palette (Solarized Dark by default), so it auto-adapts with theme-set — nothing to wire.

Don't introduce delta, diff-so-fancy, or another diff renderer for non-git — they're line-based, not syntactic, and would duplicate what delta already does for git.

glow / md markdown renderer

The md function

md (a fish function, functions/md.fish) renders markdown to ANSI via glow with a pinned Solarized style, word-wrapped to the current terminal/pane width:

function md
    glow --style $HOME/.config/glow/glamour.json --width $COLUMNS $argv
end

glow reads the width once at launch (one-shot and pager modes render then exit), so the wrap reflects the pane size at the moment md runs — resize and re-run to re-flow. Piped output drops --width (glow.yml default) so redirected renders stay deterministic. bat / less / cat still show the source with syntax highlighting; md shows the rendered output (headings, lists, code-block themes).

Why --style, not glow.yml

glow on macOS reads its yaml from ~/Library/Preferences/glow/, not ~/.config/glow/. The function passes --style directly so the Solarized JSON in this repo (.config/glow/glamour.json) is used regardless.

Fenced code blocks inside markdown use chroma's solarized-dark theme to stay on-palette.

Usage

md README.mdrender to terminal
md -p README.mdpaged (uses $PAGER / less)
mdp README.mdsame as md -p (dedicated alias)
spec-last / plan-lastopen the newest .superpowers/specs|plans doc via mdp (creation-time sort; run from repo root)
md -w 100 README.mdoverride width (later flag wins)
cat foo.md | md -render from stdin
command glow ...bypass md (no --style/width)

Don't swap to mdcat / frogmouth without an explicit ask — mdcat was archived upstream 2025-01-10.

tailspin / tspin live-log highlighter

Daily use

tspin file.logopen file (paged via less)
tspin -f file.logfollow (live tail with highlights)
cmd | tspin -ppipe stdin, print to stdout (no pager)
tspin -e 'kubectl logs -f pod'run command, view paged output

No tail alias and no t shortcut — tail / tail -n stay vanilla. tspin's CLI isn't a tail superset (no -n), so wrapping tail would break common uses.

Theme — Solarized via theme.toml

tspin reads ~/.config/tailspin/theme.toml. It accepts ANSI color names only (red, blue, bright_red, …); Ghostty's Solarized Dark palette resolves them to hex via the canonical Solarized terminal mapping:

redred #dc322f
bright_redorange #cb4b16
bright_magentaviolet #6c71c4
bright_greenbase01 #586e75
bright_cyanbase1 #93a1a1

Severity (error / warn / info / debug) is shipped as [[keywords]] blocks — tspin has no built-in groups for them.

What gets highlighted

Schema: github.com/bensadeh/tailspin/blob/main/src/theme/mod.rs. Override anything with extra [[keywords]] or block-level entries.

xh modern HTTP

Most-used invocations

xh GET httpbin.org/getbasic GET; pretty-prints JSON in Solarized colors
xh POST httpbin.org/post name=aliceJSON body via key=value shorthand (no --data)
xh -a user:pass api.example.combasic auth (HTTPie-compatible flag)
xh --download urlsave body to a file (filename inferred)
xhs api.github.com/zenHTTPS-default companion binary (no https:// needed)
xh --style=monokai GET …override the default Solarized theme per-invocation

Why a config file (and what's in it)

Solarized is pinned via ~/.config/xh/config.json:

{"default_options": ["--style=solarized"]}

xh --style accepts auto, solarized, monokai, fruity. xh renders through syntect — the same library family as bat — so highlighting matches the rest of the Solarized Dark setup.

No alias here. Aliases in this repo are reserved for swapping commands; default flags belong in config files.

Coexistence with curl

curl is unchanged. Scripts, CI, and any non-interactive use keep calling curl verbatim. xh/xhs are the interactive surface only.

Don't alias curl to xh, and don't introduce an http/https alias either — the binary's own name is the only entry point.

basalt Obsidian vault TUI

What / how installed

basaltstandalone TUI for the Obsidian vault (~/code/notes) — browse & read notes in a bare terminal, works over SSH; same .md files as the app
installmise github:erikjuhani/basalt, prebuilt binary (tag_regex pins the TUI crate — the repo also tags basalt-core); no brew, no Rust toolchain
confignone shipped — raw defaults; colors ride the ANSI palette, so theme-set applies for free. Dataview/.base views stay in the Obsidian app

Keys (defaults)

?help modal — live keymap for the current pane
j / k / Entermove / open (vault splash & note explorer)
ttoggle explorer sidebar
Tabswitch pane
Ctrl+otoggle outline pane
Ctrl+gvault selector
Ctrl+Alt+eedit note in vi (in-TUI editing is experimental, off)
Ctrl+Alt+oopen note in the Obsidian app
qquit

slm local LLM prompt

Usage

slm <prompt words>one-off completion from args
cat file | slmprompt from stdin
cat err.log | slm explain thisargs = instruction, stdin = material (joined)
slm -m <id> …override model for this call
slm -s "translate to French" …set the system prompt
slm -hhelp

Env & notes

SLM_URLbase URL (default http://localhost:1234/v1)
SLM_MODELdefault model (qwen/qwen3.5-9b); persist via set -Ux
SLM_SYSTEMdefault system prompt (terse built-in otherwise)
SLM_MAX_TOKENScompletion token cap (default 512)

Talks to LM Studio's OpenAI-compatible endpoint via curl (keyless). Pins reasoning_effort: "none" + a token cap so qwen's thinking can't run away. Server isn't always-on — start the LM Studio app (or lms server start). 9B model: quick & local, not authoritative.

hyperfine command benchmarking

Most-used invocations

CommandWhat it does
hyperfine 'cmd'10 runs, no warmup, summary with mean/stddev
hyperfine --warmup 3 'cmd'discard 3 warmup runs first (cache, JIT)
hyperfine 'a' 'b'A/B compare; prints "X is N× faster than Y"
hyperfine -N 'cmd'skip shell wrapper; measure binary directly
hyperfine --export-markdown out.md 'cmd'share results in markdown

When to reach for it vs time

time (/usr/bin/time) is the right tool for one-shot wall-clock measurements — scripts, CI, "did this finish quickly?". Reach for hyperfine when you want warmups, multiple runs, variance characterization, or A/B comparison.

Deliberately not aliased to time — semantics differ. See CLAUDE.md for the catalog-rejection rationale.

Caveats

First run includes filesystem cold-cache effects. Use --warmup N or --prepare 'sync' to control. macOS purge needs sudo if you want to flush page cache between runs.

vivid & LS_COLORS

What & how

vivid generates a LS_COLORS string from a named palette. .config/fish/conf.d/10-colors.fish exports it on startup:

command -v vivid >/dev/null 2>&1 && \
  export LS_COLORS="$(vivid generate solarized-dark)"

Both eza and GNU ls read $LS_COLORS. BSD ls uses $LSCOLORS (different format) — left at OMZ default.

Tweak / preview

vivid themeslist available palettes
vivid generate molokaitry another palette one-shot
echo $LS_COLORS | tr ':' '\n'inspect current rules
vivid -m 8-bit generate solarized-dark256-color mode (24-bit is default)

Solarized-dark is the pinned palette — switching is OK to try, but persist anything else only after asking.

atuin shell history

Shell key bindings

Ctrl-Ratuin history picker — full screen-aware popup with scope cycling
Upfish native history-search (atuin's up-arrow binding disabled via --disable-up-arrow)

Cycle scope inside the picker with Ctrl-R: global → session → workspace. Default scope is global (every command in reach without cycling); workspace is the current git repo (skipped outside a repo).

Inside the picker

Enterpaste selected command to commandline (does not run)
Tabrun selected command immediately
Ctrl-Rcycle scope (global → session → workspace)
Ctrl-Stoggle exact / fuzzy match
Ctrl-N / Ctrl-Pnext / prev match (arrows work too)
Escreturn typed query to the prompt (exit_mode = "return-query"); Ctrl+C / Ctrl+D discard
cwd:.filter syntax — restrict to current directory

Notes

exit codefixed-position column between datetime and command — raw integer (-1 = "completion never recorded"; 0 = success; anything else = the actual exit code), coloured green/red
~/.local/share/atuin/history.dbsqlite store; machine-global, outside the repo
fish_historystill recorded in parallel; revert by deleting 45-atuin.fish
atuin import fishone-time backfill from existing fish history

Config in .config/atuin/config.toml. Theme is default — auto-adapts to whatever Ghostty's 16-color palette is via ANSI refs, same trick as FZF_DEFAULT_OPTS.

fzf fuzzy finder

Shell key bindings

Ctrl-RREPLACED by atuin — fzf no longer owns Ctrl-R
Ctrl-Tfile picker → inserts paths at the cursor
Alt-Ccd into directory under cursor (left-Option in Ghostty; right-Option still types Polish)

Tab-complete works through fzf for kill **<Tab>, cd **<Tab>, ssh **<Tab>, etc.

Inside the prompt

Ctrl-J / Ctrl-Knext / prev item
Tab / Shift-Tabmulti-select
Enteraccept
Esc / Ctrl-Ccancel
'fooexact match (single-quote prefix)
!foonegate
^foo / foo$prefix / suffix anchor
foo | barOR

Common one-liners

vim $(fzf)pick a file, open in vim
git checkout $(git branch | fzf)branch picker
fd | fzf --preview 'bat --color=always {}'live preview
history | fzfmanual history search

FZF colors are pinned to Solarized via set -gx FZF_DEFAULT_OPTS in .config/fish/conf.d/40-plugins.fish.

Themes & fonts theme-set / font-set

Switch the theme

theme-set <name> (fish function) flips a machine-local active-theme symlink and re-themes every hot-path + file-viewer tool live. Solarized Dark is the bootstrap default.

theme-set solarizedSolarized Dark (default)
theme-set mocha / frappe / latteCatppuccin Mocha / Frappé / Latte (Latte = only light theme)
theme-set draculaDracula
theme-set gruvboxGruvbox
theme-set tokyo-nightTokyo Night Storm
theme-set nordNord
theme-set rose-pine / rose-pine-moonRosé Pine / Moon
theme-setshow current theme + when it was set
theme-set --stats [--all]per-theme usage report (active time, %, switch count, last set)

10 themes total. The switch is live — open terminals, tmux, and nvim follow on next prompt / reload.

Switch the font

font-set <name> [<weight>] [<size>] flips a machine-local Ghostty font include; ghostty +reload applies it live. JetBrains Mono is the bootstrap default.

font-set jetbrainsdefault family
font-set <name> boldalso set weight (per-font advertised weights)
font-set <name> "" 15keep weight, set size 15
font-set <Tab>completion lists all 17 Nerd Fonts
font-setshow current font (family + weight + size) + when set
font-set --stats [--all]per-font usage report

17 switchable Nerd Fonts. Omit weight/size to keep the current value. No tmux/nvim/bat coupling — font is Ghostty-only.

What follows the theme

Follow theme-set: bat, git-delta, difftastic, glow/md, vivid/LS_COLORS, eza, fzf, atuin, Ghostty, starship, lnav, gh-dash, tmux, nvim, btop.

Stay Solarized Dark: procs, tailspin (tspin), xh.

fzf + atuin + difftastic auto-adapt via ANSI palette refs (no per-theme file). tmux sources the active palette; nvim reads it at startup. See CLAUDE.md → "Switchable themes".

Send the theme to the phone

moshi-theme (fish function) exports a theme to the Moshi iPhone terminal as a Moshi-v1 payload. No args = the active theme-set theme.

moshi-themeactive theme → tappable moshi:// deep link + moshi-theme:… string on the clipboard
moshi-theme <name>any of the 10 themes (Tab-completes)
moshi-theme --qrscannable QR in the terminal (phone camera → Moshi import)

Import is manual on the phone (Settings → Theme → Import theme). Payloads are committed moshi-<slug>.json artifacts — re-run scripts/build-moshi-themes.py after theme changes (needs Ghostty.app).

nvimpager global $PAGER

Where it kicks in

nvimpager is the global $PAGER (set in .config/fish/conf.d/00-env.fish, guarded on command -q nvimpager). Anything that paginates through $PAGER gets smooth, colored, theme-following paging — e.g. glow's markdown ANSI or --help piped to a pager.

man ($MANPAGER = bat) and git (core.pager = delta) keep their own pagers — nvimpager only owns the generic $PAGER slot.

Config & scroll

nvimpager loads its own ~/.config/nvimpager/init.luanot the full nvim config. It reuses nvim's lazy snacks.nvim for smooth scroll (existence-guarded, so a fresh machine still pages without animation) and applies the active theme-set colorscheme.

cmd | nvimpagerpage any stdin (colored)
qquit (nvim normal-mode keys inside)
/pat / nsearch / next match

Smoke: scripts/test-nvimpager.sh.

sandbox isolated Linux container

What it is

sandbox (bin/sandbox, Mac-side) runs untrusted CLI/TUI inside an isolated Linux container that bakes the portable dotfiles subset. Use it to try a sketchy tool, an npx one-off, or an AI agent without exposing the Mac home.

sandbox create <name>provision a new sandbox
sandbox <name>attach to an existing one (errors if absent)
sandbox reup <name> [flags]recreate with new flags, keep the volume

Two modes

containerno host mounts — untrusted-safe; rebuilds on content-hash mismatch
machineOrbStack mounts the Mac home — trusted only

Active Mac theme is baked in and re-applied on entry. Secrets are injected at runtime, never baked. The build needs GITHUB_TOKEN.

Scope & verify

Bakes the Brewfile minus tmux/ruby/procs, plus wt. In-container theme switcher, tmux, sesh, gh, bd, font-set, vhs are out of scope. nvimpager is the one non-mise tool (built from source on Linux).

Smoke: scripts/test-sandbox.sh (also CI: .github/workflows/sandbox.yml, arm64).

vhs terminal recorder

What it is

vhs (Brewfile) renders a scripted terminal session to GIF/WebM from a .tape file — deterministic terminal demos without screen-recording by hand.

vhs demo.taperender a tape to its output files
vhs new demo.tapescaffold a starter tape
vhs record > demo.tapecapture keystrokes into a tape

In this repo

Tape sources live in docs/tapes/<name>.tape; outputs (.gif + .webm) are written alongside and committed. Build all via scripts/build-tapes.sh.

Recording env (theme/font/size) is locked at the top of each tape — vhs spawns its own ttyd, not Ghostty, so it doesn't inherit your live theme-set / font-set choice.

Bootstrap a new machine

Full new-machine setup is in README.md → "Setup (new machine)". The steps below are the terminal-relevant subset.

# 1) Brew packages
brew bundle --file=$PROJECTS_HOME/dotfiles/Brewfile

# 2) Symlinks (idempotent)
$PROJECTS_HOME/dotfiles/bootstrap.sh

# 3) Wire delta into git (one-time, global)
git config --global core.pager delta
git config --global interactive.diffFilter "delta --color-only"
git config --global delta.navigate true
git config --global delta.line-numbers true
git config --global delta.syntax-theme "Solarized (dark)"

# 4) Verify
brew bundle check --file=$PROJECTS_HOME/dotfiles/Brewfile --verbose
echo $LS_COLORS | head -c 80      # should not be empty
git log -p | head                 # should look styled