GitHub - b-slim/.dotfiles: .dot files to carry around · GitHub
Skip to content

b-slim/.dotfiles

Folders and files

Repository files navigation

Dotfiles

Personal configs for Neovim, tmux, zsh, git, Ghostty, and Claude Code — with deploy scripts for local macOS and remote Linux VMs.

Contents

File Deploys to Description
zshrc ~/.zshrc Zsh: history, completion, autosuggestions, fzf, zoxide, aliases, functions
starship.toml ~/.config/starship.toml Starship prompt: directory, git status, language versions
ghostty.conf ~/.config/ghostty/config Ghostty: font, catppuccin-mocha theme, zsh integration, Option-as-Alt
gitconfig ~/.gitconfig Git: delta diff pager, aliases, sensible defaults
gitconfig.local ~/.gitconfig.local Default identity (LinkedIn) + includeIf for ~/perso/
gitconfig.personal ~/.gitconfig.personal Personal identity (Apache) for ~/perso/ repos
gitignore_global ~/.gitignore_global Global gitignore: macOS, editors, secrets, build artifacts
ssh_config.custom ~/.ssh/config.custom SSH: route git@github.com to personal key for ~/perso/
nvim_init.lua ~/.config/nvim/init.lua Neovim: markdown editing, folding, TOC sidebar, render-markdown
tmux.conf ~/.tmux.conf Tmux: Ctrl+Space prefix, mouse, vim navigation, 50k scrollback
statusline-command.sh ~/.claude/statusline-command.sh Claude Code statusline: git branch, token usage, cost, model
claude-settings.json ~/.claude/settings.json Claude Code: statusline config + allow/deny permissions
Brewfile All Homebrew packages, installed via brew bundle
macos-defaults.sh macOS system settings: keyboard, trackpad, Finder, Dock, screenshots
bin/tmux-sessionizer ~/.local/bin/tmux-sessionizer Fuzzy-pick a repo/worktree under ~/work or ~/perso → tmux session
deploy-dotfiles-local ~/bin/deploy-dotfiles-local Deploy all configs to local macOS
deploy-dotfiles ~/bin/deploy-dotfiles Deploy configs to remote Linux VMs via SSH

Setup

First-time install (macOS)

git clone git@github.com:b-slim/.dotfiles.git ~/.dotfiles && ~/.dotfiles/deploy-dotfiles-local

This clones the repo and immediately deploys everything: installs all packages via Homebrew, symlinks all configs, installs Neovim plugins.

Or step by step:

git clone git@github.com:b-slim/.dotfiles.git ~/.dotfiles

# Preview what will happen without touching anything
~/.dotfiles/deploy-dotfiles-local --dry-run

# Deploy (symlinks configs, installs packages via Brewfile)
~/.dotfiles/deploy-dotfiles-local

# Also apply macOS system settings (keyboard, Dock, Finder)
~/.dotfiles/deploy-dotfiles-local --macos-defaults

Configs are symlinked by default — git pull in ~/.dotfiles keeps everything up to date automatically.


deploy-dotfiles-local

Options

Flag Description
(none) Symlink all configs — stays in sync with git pull
--copy Copy files instead of symlinking
--dry-run Preview all actions without making any changes
--macos-defaults Also run macos-defaults.sh (keyboard, Dock, Finder, screenshots)
--help Show usage

What it deploys

  1. Homebrew — installs if missing
  2. Brewfilebrew bundle --no-upgrade (all packages at once)
  3. zshrc~/.zshrc
  4. starship.toml~/.config/starship.toml
  5. ghostty.conf~/.config/ghostty/config
  6. gitconfig~/.gitconfig
  7. gitignore_global~/.gitignore_global
  8. gitconfig.local~/.gitconfig.local (LinkedIn default + includeIf ~/perso/)
  9. gitconfig.personal~/.gitconfig.personal (bslim@apache.org)
  10. ssh_config.custom~/.ssh/config.custom (chmod 600)
  11. nvim_init.lua~/.config/nvim/init.lua
  12. tmux.conf~/.tmux.conf + reload if tmux is running
  13. statusline-command.sh~/.claude/statusline-command.sh (chmod +x)
  14. claude-settings.json → merged into ~/.claude/settings.json via jq
  15. bin/*~/.local/bin/ (e.g. tmux-sessionizer)
  16. Headless Neovim — nvim --headless "+Lazy! sync" +qa
  17. ~/bin/ — symlinks for both deploy scripts

Existing regular files are backed up as .bak before being replaced.

After deploying

source ~/.zshrc                             # load zsh config in current session
deploy-dotfiles-local --macos-defaults      # optional: apply system settings

Zsh

Features

Feature Details
History 100k entries, deduplication, shared across sessions, timestamps
Completion Case-insensitive, colored, cached, interactive menu
autosuggestions Fish-like inline suggestions — to accept
syntax-highlighting Command coloring as you type (must be sourced last)
fzf Ctrl+R history, Ctrl+T files, Alt+C dirs — with bat previews
zoxide z <partial> jumps to frequent dirs, replaces cd
Starship Single-line prompt: dir + git branch/status + language versions
eza Better ls with icons, git status, tree view
bat Better cat with syntax highlighting, used as fzf preview

Aliases

Alias Expands to
v / vi / vim nvim
ll eza -lah --icons --git
lt eza --tree --icons -L 2
cat bat --paging=never
gs git status -s
ga / gaa git add / git add --all
gc / gcm git commit / git commit -m
gp / gpl git push / git pull
gd / gds git diff / git diff --staged
glog git lg (pretty graph log)
lg lazygit
j <dir> zoxide jump
.. / ... / .... cd up 1 / 2 / 3 levels
brewup brew update && brew upgrade && brew cleanup
path Print $PATH one entry per line
cleanup Remove .DS_Store and ._* files recursively
flushdns Flush macOS DNS cache

Functions

Function Description
fv fzf → pick file → open in nvim (with bat preview)
fcd fzf → pick directory → cd into it (with eza tree preview)
fgl fzf → browse git log → show diff for selected commit
wt fzf → pick a worktree of the current repo → cd into it
wtnew <branch> [path] Create worktree for branch (existing or new) as sibling of repo → cd into it
wtrm fzf → pick a worktree → remove (refuses main, prompts to confirm)
mkcd <dir> mkdir -p + cd in one step
extract <file> Extract any archive (tar.gz, zip, bz2, 7z, …)
serve [port] Start a Python HTTP server in the current dir (default: 8000)
topcmds Show the 10 most used shell commands

Local overrides

Machine-specific config (work proxies, private env vars, etc.) goes in ~/.zshrc.local — sourced at the end of .zshrc, not tracked in this repo.

Building muscle memory

zshrc.local.example contains nag wrappers that print a hint when you reach for an old command, then run it anyway so nothing breaks:

cp ~/.dotfiles/zshrc.local.example ~/.zshrc.local
source ~/.zshrc
Old habit Nag fires New habit
cd <path> yes z <partial>
find yes fd
grep yes rg
man <tool> yes tldr <tool>

Remove each wrapper once it feels automatic. Delete ~/.zshrc.local when done.


Git

Config highlights

Setting Value
Diff pager delta — syntax-highlighted, side-by-side, line numbers
Editor nvim
Default branch main
Push default current + auto setup remote
Fetch Prune deleted remote branches automatically
Rebase Auto-stash before rebase
Rerere Remember and reuse conflict resolutions
Branch sort Most recently active first
Diff algorithm histogram (better than default Myers)

Aliases

Alias Command
git lg Pretty graph log (all branches)
git lgs Pretty graph log (current branch)
git st git status -s
git aa git add --all
git cm git commit -m
git amend git commit --amend --no-edit
git undo Reset last commit, keep changes staged
git new git checkout -b
git brd git branch -d
git sa Stash including untracked files
git sp git stash pop
git changed Files changed in last commit
git file-log Full log for a specific file (git file-log -- path)
git aliases List all configured aliases

Identities

Two identities switch automatically based on directory:

Directory Name Email
Everywhere (default) Slim Bouguerra sbouguerra@linkedin.com
~/perso/** Slim Bouguerra bslim@apache.org

Wired up via includeIf "gitdir:~/perso/" in ~/.gitconfig.local. Verify the active identity in any repo:

git config user.email

SSH

~/.ssh/config is managed by LinkedIn and cannot be modified directly. Personal SSH config lives in ~/.ssh/config.custom (included by the managed config).

ssh_config.custom configures:

Match host github.com user git
    IdentityFile ~/.ssh/personal_github_b-slim
    IdentitiesOnly yes
    IdentityAgent none

This routes git@github.com connections to the personal SSH key when working in ~/perso/, keeping it separate from LinkedIn's SSH agent.


Ghostty

Setting Value
Font JetBrainsMono Nerd Font Mono, size 14, thickened
Theme catppuccin-mocha
Shell integration zsh — cursor shape per mode, prompt marks, title updates
Option as Alt Enabled — required for zsh word nav (Alt+.) and fzf (Alt+C)
Scrollback 100,000 lines
Window padding 10px horizontal, 8px vertical
Titlebar style Tabs
Cursor Block, no blink
Copy on select Disabled
Mouse hide While typing

macOS Defaults

Run via deploy-dotfiles-local --macos-defaults or directly:

~/.dotfiles/macos-defaults.sh

Keyboard

Setting Value Default
Key repeat rate 2 6
Initial repeat delay 15 25
Press-and-hold accent menu Disabled Enabled
Auto-correct Disabled Enabled
Smart quotes / dashes Disabled Enabled
Auto-capitalize Disabled Enabled
Auto-period on double-space Disabled Enabled
Full keyboard access (Tab in dialogs) All controls Text fields only

Trackpad

Setting Value
Tap to click Enabled

Finder

Setting Value
Show hidden files Yes
Show all file extensions Yes
Show path bar Yes
Show status bar Yes
Default view List
New window target Home folder
Folders on top when sorting Yes
Warn on extension change No
.DS_Store on network volumes Disabled
.DS_Store on USB volumes Disabled
Disk image verification Disabled (faster mounting)

Dock

Setting Value
Auto-hide Enabled
Auto-hide delay 0s
Auto-hide animation 0.2s
Show recent apps No
Icon size 48px
Minimize into app icon Yes
Mission Control animation 0.1s

Screenshots

Setting Value
Save location ~/Desktop/Screenshots/
Format PNG
Drop shadow Disabled

Other

App Setting
Activity Monitor Show all processes, sort by CPU
TextEdit Default to plain text, UTF-8

Some settings (keyboard, trackpad) require a logout/restart to take full effect.


Homebrew Packages

All packages are defined in Brewfile. Install everything:

brew bundle --file=~/.dotfiles/Brewfile
Package Description
zsh-autosuggestions Fish-like inline suggestions
zsh-syntax-highlighting Command coloring as you type
fzf Fuzzy finder
starship Shell prompt
zoxide Smarter cd
git Version control
git-delta Syntax-highlighted diffs
lazygit TUI git client
gh GitHub CLI
neovim Text editor
tmux Terminal multiplexer
bat Better cat
eza Better ls
fd Better find
ripgrep Better grep
sd Better sed
jq / yq JSON / YAML processors
bc Calculator (Claude statusline)
tldr Concise man pages
htop Process monitor
watch Run command repeatedly
font-jetbrains-mono-nerd-font Terminal font with icons
ghostty Terminal emulator
mosh Better SSH — survives sleep/wake and network roaming
colima Lightweight Docker daemon (replaces Docker Desktop)
docker Docker CLI
docker-compose Multi-container apps
lazydocker TUI for Docker
dive Inspect Docker image layers
kubectl Kubernetes CLI
k9s Kubernetes TUI
kubectx Switch cluster contexts and namespaces fast
jenv Java version manager (per-directory via .java-version)
maven Build tool
temurin@21 Eclipse Temurin JDK 21 (current LTS)
temurin@17 Eclipse Temurin JDK 17 (previous LTS)

SSH

~/.ssh/config.custom configures:

Setting Value Effect
ControlMaster auto All hosts Reuses existing TCP connection — subsequent SSH to same host is instant
ControlPersist 10m All hosts Keeps the master connection alive 10 min after last session
ServerAliveInterval 60 All hosts Sends keepalive every 60s — prevents idle disconnects
Personal key github.com git Routes to ~/.ssh/personal_github_b-slim

mosh — use instead of ssh for remote VMs. Survives sleep/wake, network switches, and high latency:

mosh user@vm1          # instead of ssh user@vm1

Docker

Colima provides the Docker daemon without Docker Desktop.

colstart               # start Docker daemon
colstop                # stop it

Aliases

Alias Command
dps / dpsa docker ps / docker ps -a
di docker images
dex <ctr> <cmd> docker exec -it
dlf <ctr> docker logs -f
drm / drmi docker rm / docker rmi
dcup / dcdown docker-compose up -d / down
dclogs docker-compose logs -f
lzd lazydocker TUI
dive <image> Inspect image layers

Kubernetes

Aliases

Alias Command
k kubectl
k9 / k9s Kubernetes TUI
kctx <ctx> kubectx — switch cluster context
kns <ns> kubens — switch namespace
kgp / kgpa get pods / get pods --all-namespaces
kgs / kgd / kgn get services / deployments / nodes
klf <pod> kubectl logs -f
kex <pod> <cmd> kubectl exec -it
kdp / kds describe pod / describe service

Java / jenv

jenv manages which JDK is active globally or per directory.

Plugins enabled by deploy script

Plugin What it does
export Sets JAVA_HOME automatically when JDK switches
maven Makes mvn use the jenv-selected JDK
gradle Makes gradle use the jenv-selected JDK

Per-directory switching

Drop a .java-version file in any repo to pin its JDK:

jvl 17          # writes .java-version = 17 in current dir
jvl 21          # switch to 21 for this project
jvs             # list all registered JDKs
jvg 21          # set global default

Commit .java-version to the repo so every developer gets the same JDK automatically.

Maven aliases

Alias Command
mvnci mvn clean install -T4 (4 threads)
mvncp mvn clean package
mvnt mvn test
mvnst mvn install -DskipTests
mvntree mvn dependency:tree

Neovim

Markdown-focused configuration with lazy.nvim plugin manager.

Plugins

Plugin Purpose
vim-markdown Folding, syntax
render-markdown Rich in-buffer rendering
outline.nvim TOC sidebar panel
nvim-treesitter Syntax parsing

Keymaps

Leader key is Space.

Key Action
<Space>t TOC in quickfix
<Space>o TOC sidebar panel
<Space>ff Toggle fold under cursor
<Space>fu Open one fold under cursor
<Space>fU Open all nested folds under cursor
<Space>fa Fold all
<Space>fo Unfold all
<Space>f1 / f2 / f3 Fold to level 1 / 2 / 3
]] Jump to next heading
[[ Jump to previous heading
gx Open URL under cursor in browser
<Space>mr Toggle render-markdown

Tmux

Setting Value
Prefix Ctrl+Space
Mouse support Enabled
Scrollback 50,000 lines
Pane navigation Prefix + h/j/k/l (vim-style)
Alt navigation Alt+h/j/k/l (no prefix needed)
Sessionizer Prefix + f — fuzzy-pick repo/worktree → switch session
Color 24-bit (true color)

Sessionizer (per-project tmux sessions)

bin/tmux-sessionizer turns "switch to project X" into one keystroke. Each repo / worktree under ~/work or ~/perso becomes its own persistent tmux session — keeping shell history, running dev servers, and editor state isolated per project.

Key Where Action
Prefix+f Inside tmux Open picker → switch-client to the chosen session (creates it if needed)
Ctrl+f Plain shell Open picker → attach to the chosen session (creates it if needed)

Picker scope: every git worktree list of every git repo found as a direct child of ~/work or ~/perso. Non-repo dirs (heap dumps, archives, etc.) are filtered out. Roots are configured at the top of bin/tmux-sessionizer.

Ctrl+f shadows zsh's default forward-char — right-arrow does the same thing.

Session names come from basename of the worktree path, with ., :, and spaces replaced by _ (tmux name restrictions). So ~/work/trino-fix-LTS-bug/ becomes the session trino-fix-LTS-bug.


Worktree + Sessionizer workflow

The wt* functions and tmux-sessionizer are designed to work as one system: one git worktree = one directory = one tmux session. No context-switching cost, no stash dance, no re-running dev servers.

The functions, at a glance

Command What it does
wtnew <branch> Create a worktree as a sibling of the current repo (../<repo>-<branch>) and cd into it. Creates the branch if it doesn't exist.
wtnew <branch> <path> Same, but at an explicit path.
wt fzf-pick any worktree of the current repo → cd into it.
wtrm fzf-pick a worktree → confirm → git worktree remove it (refuses the main worktree).
Ctrl+f / Prefix+f Picker across all repos+worktrees under ~/work and ~/perso → tmux session.

Example 1 — Start a new feature branch alongside the main checkout

You're in ~/work/trino on main with uncommitted exploratory work you don't want to disturb. You need to start a clean branch for fix-LTS-cache-miss:

cd ~/work/trino
wtnew fix-LTS-cache-miss
# → creates branch + worktree at ~/work/trino-fix-LTS-cache-miss
# → cd's you there

# Hit Prefix+f (or Ctrl+f from a plain shell), pick the new worktree
# → you're now in a dedicated tmux session named `trino-fix-LTS-cache-miss`

The main ~/work/trino worktree is untouched — its dev server keeps running in its own session. Switch between them with Prefix+f any time.

Example 2 — Review a teammate's PR without trashing your in-flight work

A PR review request lands while you're mid-feature. Don't stash; don't switch branches in place — make a throwaway worktree:

cd ~/work/trino
git fetch origin pull/8421/head:pr-8421     # fetch the PR ref as a local branch
wtnew pr-8421                                # worktree + cd
# Prefix+f → pick the new session, build/test there
# When done:
wtrm                                         # fzf-pick pr-8421 → confirm → gone
git branch -D pr-8421                        # drop the branch too

Your original feature session is exactly where you left it — same editor state, same dev server, same shell history.

Example 3 — Jump between projects without losing state

You're deep in a Trino debugging session. Slack pings about a claude-assistant doc fix:

Prefix+f → type "assist" → Enter

Lands you in the claude-assistant session (creates it on first jump). Fix, commit, push. Prefix+f → "trino" → Enter, and you're back exactly where you were.

This is the main reason the sessionizer exists: context-switch cost = one fuzzy match.

Example 4 — Clean up after a feature ships

cd ~/work/trino                              # back in the main worktree
git worktree list                            # see what's still around
wtrm                                         # fzf-pick the merged worktree → remove

wtrm refuses to remove the main worktree, and if you happen to be standing in the worktree you're removing, it cds you back to main first. Branches stick around after wtrm — delete them separately with git branch -d <name> if you're done with them.

When to use wt vs Ctrl+f / Prefix+f

Want to… Use
Switch to another worktree of the current repo, in the current shell wt (just cds — no tmux)
Jump to any project (different repo, different worktree) with a dedicated tmux session Ctrl+f (plain shell) or Prefix+f (in tmux)
Create a new worktree from scratch wtnew <branch>
Tear one down wtrm

Tips

  • Naming: wtnew feature/foo-bar sanitizes the slash → directory is ../<repo>-feature-foo-bar. The branch keeps its slash.
  • First-time setup on a new VM: ensure ~/work (and/or ~/perso) exists before the picker has anything to show. The sessionizer silently produces nothing if both roots are missing.
  • Adding more roots: edit ROOTS=(...) at the top of bin/tmux-sessionizer and redeploy.
  • Existing branch: wtnew <existing-branch> checks out the existing branch instead of creating a new one — useful for resuming abandoned work.

Claude Code Statusline

Displays in Claude Code's terminal:

  • Directory (robbyrussell-style green arrow)
  • Git branch with dirty indicator
  • Token usage — color-coded: green <50%, yellow 50–79%, red ≥80%
  • Estimated session cost (based on per-model pricing)
  • Active model name
  • Agent name (when running a subagent)
  • Keyboard shortcuts reference line

Installed to ~/.claude/statusline-command.sh. Settings in ~/.claude/settings.json.


Claude Code Permissions

Allowed

  • File operations: Read, Edit, Write
  • Shell utilities: ls, cat, grep, find, head, tail, diff, sort, awk, sed, cut, tr, xargs, tree, etc.
  • Git: all git commands
  • Build tools: gradle, ./gradlew, npm
  • Languages: python, python3, java
  • GitHub CLI: gh pr, gh api, gh issue, gh search, gh auth
  • Kubernetes: kubectl get, kubectl describe, kubectl logs
  • MCP tools: mcp__captain__*, mcp__glean_default__*

Denied

  • Sensitive files: .env, .pem, .key, .p12, .pfx, .keystore, .netrc, .pgpass
  • Credential dirs: ~/.datavault, ~/.azure, ~/.azure-devops, ~/dev.src
  • Destructive git: git push --force, git reset --hard, git clean -f
  • Destructive shell: rm -rf /
  • Network tools: ssh, scp, nc, netcat, telnet
  • WebSearch

Deploy to Remote VMs

# Single host
deploy-dotfiles user@vm1

# Multiple hosts
deploy-dotfiles user@vm1 user@vm2 user@vm3

What it does per host

  1. Installs/updates Neovim if missing or below v0.8.0 (user-local to ~/.local/, no sudo)
  2. Deploys nvim_init.lua~/.config/nvim/init.lua
  3. Deploys tmux.conf~/.tmux.conf + reloads if running
  4. Deploys statusline-command.sh~/.claude/ (chmod +x)
  5. Merges claude-settings.json~/.claude/settings.json via jq
  6. Installs Ghostty terminfo (xterm-ghostty) from local machine if available
  7. Runs headless Neovim to auto-install plugins via lazy.nvim

Prerequisites on remote VMs

  • git, curl (Neovim install), jq (settings merge), bc (statusline cost calc)
  • A Nerd Font in your terminal (for icons)

About

.dot files to carry around

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

Contributors