Clone to your home folder, then run the bootstrap script:
git clone https://github.com/xavierforge/dotfiles.git ~/dotfiles
cd ~/dotfiles
./install.shMake sure your login shell is zsh (
echo $SHELL). If it isn't, switch withchsh -s "$(command -v zsh)"and reopen the terminal, otherwise.zshrcnever loads. macOS already defaults to zsh; many Linux distros don't.
install.sh links every config with GNU Stow and checks that every tool these
configs need is actually installed. Anything missing is listed by name, together
with the exact install command for this machine's package manager (Homebrew,
apt, pacman, dnf, zypper or apk), and the script offers to run it for you:
▶ Checking dependencies
⚠️ Missing tools: stow zsh fd chafa
sudo apt-get update && sudo apt-get install -y stow zsh fd-find chafa
Install them now with apt? [Y/n]
Answer n and nothing is installed; the configs are linked either way. Whatever
is still missing gets listed again at the very end of the run, so the list never
scrolls off the screen. It never installs a package manager for you.
./install.sh --install-deps # install what's missing without asking
./install.sh --no-install-deps # only report, never installDOTFILES_INSTALL_DEPS=<yes|no|ask> does the same for scripted runs. A run with
no terminal attached (piped, CI) never installs anything on its own — it just
prints the commands.
If Stow complains that a target already exists (e.g. you already have a
~/.zshrc), back up or remove that file first. Stow won't overwrite files it didn't create.
This repo carries configs for both terminal multiplexers and links only the one you pick:
./install.sh --herdr # herdr only (the default on a fresh machine)
./install.sh --tmux # tmux only
./install.sh --both # keep bothA plain ./install.sh keeps whatever is already linked, so running it as an
updater never switches multiplexers behind your back. On a fresh machine it
asks, and falls back to herdr when there is no terminal to ask on.
DOTFILES_MUX=<tmux|herdr|both> does the same job for scripted runs; a flag
wins over the variable.
Note that --both is not the same as passing nothing: no flag means "keep the
current setup", --both means "make it both", which re-links the multiplexer
you previously dropped.
Switching is non-destructive: it only removes symlinks that point into this repo. Your tmux plugins, herdr session files, and any real config file are left alone. The multiplexer you didn't pick is simply skipped in the Brewfile, so it never gets installed.
Install Homebrew once, then ./install.sh handles the rest
(the Brewfile also pulls in Ghostty and the Nerd Font on macOS).
Homebrew is not required — ./install.sh uses the distro's own package manager
(apt, pacman, dnf, zypper or apk) and asks before installing anything. To do it
by hand instead:
# Debian/Ubuntu
sudo apt install stow git zsh neovim tmux fzf ripgrep fd-find tree chafa zoxide
# Arch
sudo pacman -S stow git zsh neovim tmux fzf ripgrep fd tree chafa zoxide(Drop tmux if you use herdr; the script only checks for the multiplexer you
picked.)
Notes:
styluaanduvaren't in most distro repos, so the script only prints their commands:cargo install styluaand the uv installer.herdrisn't packaged by distros either. With Homebrew it comes from the Brewfile; without it the script offers to runcurl -fsSL https://herdr.dev/install.sh | sh(see Herdr below).- On Debian/Ubuntu the
fdbinary is namedfdfind. The script detects either name and, when onlyfdfindexists, links it to~/.local/bin/fdso the fzf integration finds it (.zshrcalready puts that directory onPATH).
cd ~/dotfiles
git pull
./install.sh # re-links new files + installs any new Brewfile deps
# (keeps your current tmux/herdr choice)Other handy commands:
brew update && brew upgrade # upgrade all Homebrew packages (macOS)
brew bundle cleanup # list packages no longer in the Brewfile
# add --force to actually uninstall them
stow --target ~/.config -D . # unlink everything (reverse of install)Only relevant if you picked tmux or both. Tmux plugins are managed by
TPM and are not tracked in this repo.
After the configs are linked, set it up once:
# 1. Clone TPM into the location tmux.conf expects
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm- Start tmux, then press
<prefix> + I(prefix isCtrl + S) to install every plugin listed intmux.conf. Use<prefix> + Uto update them later.
Herdr is the terminal workspace manager that is gradually
replacing tmux here. Its config is herdr/config.toml, and install.sh --herdr
links it to the path herdr reads: ~/.config/herdr/config.toml.
Herdr is managed by Homebrew (it lives in the Brewfile), so upgrade with
brew upgrade herdr. Do not use the built-in herdr update: that
self-updater is meant for the copy the official install script places in
~/.local/bin/herdr, and it will overwrite the brew-managed one. For the same
reason, the preview channel (herdr channel set preview) isn't reachable via
brew, which only tracks stable. If you really want preview, switch back to the
official installer:
curl -fsSL https://herdr.dev/install.sh | shAfter changing the config, reload the running server (no need to restart sessions):
herdr server reload-config
~/.config/herdr/also holds the socket, the logs, andsession.json, soinstall.shfirst creates that real directory withmkdir -pand lets Stow link onlyconfig.toml. Without that step, Stow would fold the whole directory into a single symlink pointing at this repo on a fresh machine, and runtime files would get written into your dotfiles.
The two multiplexers are an either/or (see Choosing tmux or herdr); everything else is always installed.
- Herdr (terminal workspace manager, gradually replacing tmux)
- Ghostty
- MesloLGS Nerd Font (required for p10k icons)
- Zsh
- Tmux
- tpm (plugin manager)
- NeoVim
- chafa (required for dashboard image rendering)
- Omarchy (only
hypr/bindings.lua, linked only when Omarchy is detected; see Hyprland / Omarchy)
When Neovim runs on a host you reached over ssh, markdown-preview.nvim
switches to tunnel mode automatically (it checks SSH_CONNECTION; a local
Neovim is unaffected): the preview server binds to 127.0.0.1:8765 on the
remote only, and the preview url is written to ~/.cache/mkdp-url there.
-
Open a tunnel from your local machine (the port must match the remote):
ssh -L 8765:127.0.0.1:8765 <ssh-host>
-
Run
:MarkdownPreviewon a markdown buffer in the remote Neovim. -
In another local terminal run
mdp <ssh-host>(a function from.zshrc). It reads the url over ssh and opens it in your default browser. For a host you use often,export MDP_HOST=<ssh-host>and then just runmdp.
To use a different port, set MKDP_PORT on the remote and use the same number
in the -L flag of step 1.
Only the customized bindings are listed. Native LazyVim / Ghostty / Tmux / Herdr defaults are not repeated here.
Only linked on an Omarchy machine (install.sh checks for /usr/share/omarchy,
or $OMARCHY_PATH, and skips hypr/ everywhere else). Omarchy's default
Super + arrow bindings stay as they are; these add Vim's h/j/k/l on top.
Plain Super + H/J/K/L is avoided on purpose: Windows intercepts some Super
combos (Win + L locks Windows), so Shift is added.
| Key | Action |
|---|---|
Super + Shift + H / J / K / L |
Focus window left / down / up / right |
Super + Ctrl + Shift + H / J / K / L |
Swap window left / down / up / right |
After editing, apply and validate with hyprctl reload && hyprctl configerrors.
| Key | Action |
|---|---|
Cmd + C / Cmd + V |
Copy / Paste |
Cmd + , |
Open config |
Cmd + Shift + , |
Reload config |
Cmd + Shift + O |
Toggle background opacity |
| Key | Action |
|---|---|
jk (insert) |
Exit to normal mode (vi-mode) |
Ctrl + P |
History search backward (prefix match) |
Ctrl + N |
History search forward (prefix match) |
t (command) |
Attach/create tmux session main |
The prefix is Ctrl + S, the same as tmux below, so the muscle memory
carries over between them. Each binding's tmux origin is recorded in the
# tmux: comment above it in herdr/config.toml.
| Key | Action |
|---|---|
<prefix> | |
Split pane left/right |
<prefix> _ |
Split pane top/bottom |
<prefix> c |
New tab |
<prefix> , |
Rename tab |
<prefix> r |
Enter resize mode (then h/j/k/l to adjust, Esc to leave) |
<prefix> R |
Reload config.toml |
Ctrl + h / j / k / l |
Switch pane (no prefix needed) |
<prefix> [ |
Enter copy mode |
Alt + 1 ~ Alt + 9 |
Jump straight to tab N |
Two differences from tmux:
- Resize is a mode, not a repeated press. In tmux you hit
<prefix>and then repeath/j/k/l; in herdr you enter the mode with<prefix> r, adjust, then leave withEsc. As a knock-on effect, reload moves from tmux's<prefix> rto<prefix> R(the herdr default). - Saving a session needs no keybinding. tmux-resurrect's
<prefix> Ctrl+S/Ctrl+Rare natively replaced by herdr's server/client architecture.
Pane switching with Ctrl + h/j/k/l needs no prefix, exactly like
vim-tmux-navigator.
The prefix is changed from the default Ctrl+B to Ctrl + S. Below,
<prefix> means the key pressed after a single prefix press.
| Key | Action |
|---|---|
<prefix> | |
Split pane left/right |
<prefix> _ |
Split pane top/bottom |
<prefix> h / j / k / l |
Resize pane (repeatable) |
<prefix> r |
Reload tmux.conf |
<prefix> Ctrl + S |
Save session (tmux-resurrect) |
<prefix> Ctrl + R |
Restore session (tmux-resurrect) |
Ctrl + h / j / k / l |
Seamless vim/tmux pane switching (vim-tmux-navigator) |
v (copy-mode) |
Begin selection |
y (copy-mode) |
Copy selection |
Leader is <space> (the LazyVim default).
| Key | Action |
|---|---|
jk (insert) |
Exit insert mode |
<leader>nh |
Clear search highlights |
| Key | Action |
|---|---|
<leader>sv |
Split vertical |
<leader>sh |
Split horizontal |
<leader>se |
Equalize splits |
<leader>sx |
Close current split |
| Key | Action |
|---|---|
Tab |
Next buffer |
Shift + Tab |
Previous buffer |
Ctrl + P |
Pick buffer |
<leader>X |
Close current buffer |
<leader>A |
Close all buffers except current |
| Key | Action |
|---|---|
S |
Start / expand selection |
Backspace |
Shrink selection |
| Key | Action |
|---|---|
]n / [n |
Next / previous test |
]N / [N |
Next / previous failed test |
| Key | Action |
|---|---|
<leader>cf |
Crate features popup |
<leader>cd |
Crate dependencies popup |
<leader>cH |
Open crate homepage |
<leader>cG |
Open crate repository |
<leader>cD |
Open crate documentation |
<leader>cC |
Open on crates.io |