Dotfiles for fish, neovim, tmux, git and a niri desktop. Configs are linked into ~ with
GNU Stow; tools are installed with
mise. Runs on Arch (CachyOS), macOS, WSL2 and headless Linux servers.
base/ stow packages every machine gets: fish git nvim tmux starship lazygit ghostty
herdr claude ccstatusline mise sesh
desktop/ Linux desktop only: niri noctalia (v5, ~/.local/state/noctalia/settings.toml)
macos/ macOS only: karabiner
plugins/ Claude Code local plugin marketplace (referenced by path, not stowed)
memory/ Claude Code memories that hold on any machine; linked by `mise run memory`,
not stowed, since the target path is derived from the checkout's location
system/ root-owned files, mirroring /: greetd config, its PAM stack, the greeter's
greeter.toml. Installed by `mise run greeter`, not stowed
pkglist/ pacman / AUR / apt package lists
Brewfile Homebrew packages for macOS and WSL
mise.toml tasks (see below); mise-tasks/ holds the scripts
lib/ ui.sh (colours, Y/n prompt) and plan.sh (what a task would do), sourced by
the tasks; bootstrap.sh inlines its own copy since it runs before the clone
bootstrap.sh the one command: OS packages, clone, then `mise run setup`
.stowrc --target=$HOME --no-folding --dir=base
Each package mirrors ~: base/fish/.config/fish/... links to ~/.config/fish/....
Package READMEs: claude, ccstatusline,
memory,
git, nvim, karabiner.
A profile is the set of layers a machine links. It is detected automatically and can be
forced with DOTFILES_PROFILE=.
| Profile | Layers | Detected when |
|---|---|---|
base |
base | Linux without niri (servers), WSL |
desktop |
base + desktop | Linux with niri installed |
macos |
base + macos | macOS |
One command, on a fresh machine or an existing checkout, and safe to re-run:
curl -fsSL https://raw.githubusercontent.com/AH-Merii/SMS-Supercharge-My-Shell/main/bootstrap.sh | sh # fresh machine
./bootstrap.sh # existing checkoutbootstrap.sh installs git, stow, fish and mise with the OS package manager (Homebrew on
macOS and WSL), clones the repo to ~/SMS-Supercharge-My-Shell if needed, and runs
mise run setup: OS packages, symlinks, tools, plugins and, on the Arch desktop, the login
screen. Files already sitting where a link belongs are moved to <name>.bak, never
overwritten.
Nothing installs before you have seen it. Both steps print what they are about to do —
packages split into what is already installed and what is not, the stow layers and any
files that would be backed up, the missing mise tools — and ask Proceed? [Y/n], default
yes. setup asks once for all its steps; answering yes there also skips pacman's and
apt's own prompts, since the plan already named every package. paru is the exception: its
PKGBUILD review survives, because the plan never showed you a PKGBUILD.
./bootstrap.sh -y # accept everything, including paru's review
SMS_YES=1 mise run setup # same, for the setup half only
curl -fsSL <url> | sh -s -- -y # unattended, piped
mise run deps # any single task previews and asks too
NO_COLOR=1 mise run setup # plain textTwo things stay manual because they need you: chsh -s "$(command -v fish)" for the login
shell, and ggh op init (or ggh init) for git identity and commit signing. fish prints a
reminder until the latter is done.
| Task | What it does |
|---|---|
setup |
deps, link, tools, plugins, greeter, memory in order |
deps |
OS packages: pacman/paru on Arch, apt on Debian, brew bundle on macOS/WSL |
link |
Stow the layers for this profile; conflicting files go to .bak (STOW_FLAGS=-n to dry-run) |
unlink |
Remove those symlinks |
check |
Dry-run link |
tools |
mise install everything in the global mise config |
plugins |
fisher + fish plugins, TPM + tmux plugins |
greeter |
Arch desktop: greetd + noctalia-greeter as the login screen, synced to the Noctalia theme; a no-op elsewhere |
memory |
Link the portable Claude Code memories into this checkout's project directory, and add any missing MEMORY.md lines |
profile |
Print the detected profile |
Run with mise run <task>; mise tasks lists them. Every task except check and
profile previews what it would do and asks first; SMS_YES=1 skips the asking. The
preview code lives in lib/plan.sh and is shared, so a task's own preview and the
combined one setup prints cannot disagree.
- mise (
base/mise/.config/mise/config.toml) for anythingmise registry <tool>or agithub:/npm:/cargo:backend can install: runtimes (node, bun, go, rust, uv) and CLI tools (neovim, starship, ripgrep, fzf, ...). Same versions on every OS, no root needed.mise use -g <tool>edits the stowed file, so commit the result. pkglist/on Arch and Debian,Brewfileon macOS and WSL, for what mise cannot build: fish, stow, tmux, gnupg, luarocks, GUI apps and fonts. Desktop-only packages go inpkglist/arch-desktop.txt; AUR packages inpkglist/aur.txt.
Homebrew is not installed on Arch: brew shellenv would put its own python, perl and git in
front of pacman's.
.stowrc sets the target to ~, defaults the package dir to base/, and turns off folding
so directories in ~ stay real directories and runtime files (fish history, tmux plugins,
Noctalia's generated files) never land in the repo.
stow fish # link one base package
stow -d desktop niri # link a package from another layer
stow -D fish # unlink
stow -n fish # dry-runStow refuses to overwrite a real file. mise run link moves such files to <name>.bak
first; when calling stow by hand, move them aside yourself. Do not use --adopt, it copies
the old file into the repo.
- Arch desktop (CachyOS niri + Noctalia). GPU drivers come from the installer (
chwd); enable persistence withsudo systemctl enable nvidia-persistencedif wanted. Noctalia v5 keeps its settings in~/.local/state/noctalia/settings.toml, which the settings UI writes to; that file is a symlink intodesktop/noctalia, so GUI changes show up ingit statusand you commit the ones you mean to keep (noctalia config validatechecks it). Monitor names, wallpaper paths and battery device paths in it are machine-specific. niri includesnoctalia.kdl, which Noctalia generates from the theme templates;mise run linkcreates an empty placeholder for the first login. The login screen is greetd running noctalia-greeter (Wayland, no Xorg) instead of the installer's sddm.mise run greeterinstalls the files fromsystem/, flips the enabled display manager (effective at the next boot; sddm stays installed as the way back), and runsnoctalia msg greeter-syncso the wallpaper, palette and monitor layout match the desktop (restarting Noctalia once if it started before the greeter was installed, as it has on a fresh machine).settings.tomlkeeps that sync automatic and turns on Noctalia's polkit agent, which is what puts the sync's password prompt on screen./etc/pam.d/greetdcarriespam_gnome_keyring, so the login password still unlocks the keyring. - macOS. Homebrew installs the casks in the
Brewfile(ghostty, karabiner-elements, 1password, fonts). Add$(command -v fish)to/etc/shellsbeforechsh. - WSL2. apt covers the base packages, Homebrew supplies mise and a current fish. The
clipboard goes through
clip.exein fish and tmux automatically. - Servers.
baseprofile only; nothing desktop-related is linked or installed.
fish, with starship for the prompt and fisher
plugins from fish_plugins. Some commands are replaced outright:
| Command | Replacement |
|---|---|
cat |
bat |
grep |
ripgrep |
ls |
eza |
diff |
delta |
--help anywhere on a command line pipes that tool's help through bat, so it is coloured.
One scheme, One Dark, defined once: ghostty/themes/OneDark is the terminal's palette, and
every shell tool names its colours by palette slot rather than by hex. fish
(conf.d/07-theme.fish), fzf, starship, tmux, bat and delta all resolve through the
terminal, and eza, ripgrep, fd and git already did. Changing the scheme means changing that
one file (and neovim's colorscheme, which keeps its own truecolor palette). The slots carry
these roles:
| Slot | Role |
|---|---|
| 0 | surface grey, a step above the background: selection, current line |
| 8 | comment grey: comments, autosuggestions, fzf chrome |
| 9–15 | lighter tints of 1–7, so "bright" still reads as emphasis |
| 16 | orange: numbers and constants, starship's stash and rebase marks |
| 17–20 | diff backgrounds: removed, added, and the changed words in each |
| 21 | the background, for dark text on a coloured tmux tab |
bat's ansi-roles.tmTheme maps token roles to those slots and delta reads the same theme, so
cat, previews and diffs share the prompt's colours. bat only sees it through its cache,
which mise run link builds and mise rebuilds whenever it installs bat. Slots 16–21 exist only
in the ghostty theme: another terminal shows xterm's black and blues there.
hints (or Ctrl+?) opens a searchable cheatsheet of key bindings, abbreviations, aliases
and functions, all at once or one group per hotkey inside the picker; hints GROUP and
keys open on one group. Enter puts the highlighted name on the command line (a key binding
runs instead), Alt+Enter runs it.
Nothing is written by hand except the key bindings. Abbreviations show their expansion,
aliases their body, functions their description, and the preview adds the --help of what an
entry runs when that is safe to fetch on every cursor move. Bindings are read live from
bind --user, so the list cannot go stale; keys_bind KEY COMMAND LABEL [DETAIL...] binds
and describes in one call, and anything bound another way still shows, marked "no
description" and sorted first. fzf.fish's defaults are disabled in conf.d/20-fzf.fish and
re-bound there through keys_bind, as are fzf's own Ctrl+T and Alt+C. Each group is a
_hints_rows_GROUP function emitting the same row format, so a new group is one more of those.
$OS_KIND (linux, macos, wsl) is set once in conf.d/00-os.fish; Homebrew, the
1Password SSH agent socket and the clipboard command branch on it. conf.d/01-env.fish moves
gpg to ~/.local/share/gnupg and creates it, since gpg only auto-creates ~/.gnupg.