Skip to content

nixos, nix-darwin, homebrew, oh-my-zsh, dotbot, dotbins, macos, linux, submodules, zsh, bash, awesome modern CLI tools — no place like ~/

License

Notifications You must be signed in to change notification settings

basnijholt/dotfiles

Repository files navigation

🏠 basnijholt's dotfiles

A carefully designed cross-platform dotfiles configuration that powers my development environments across macOS  and Linux 🐧 systems. This repository represents years of refinement to create a consistent, modular, and reliable setup.

I run this configuration on at least 10 machines, including arm64 macOS, x86_64 and aarch64 versions of Ubuntu, Debian, DietPi, Raspberry Pi OS, NixOS, Pop!_OS, and even on my iPhone via iSH which emulates i386 Linux.

My main goal is to have consistency and a super smooth bootstrapping experience for new machines, and to have a consistent setup across all my devices.

Try out my setup in Docker without installing anything! 🐳 See this section. Want to install right away? Use the public branch for a sanitized version without private bits.

Note

I have maintained this repository since 2019-04 but started a new commit history when I made it public in 2025-04.

Note

Nearly all code snippets in this README are auto-generated by markdown-code-runner. Therefore, the code should be up-to-date.

✨ Features

  • Shell agnostic - Works with both zsh and bash
  • Cross-platform - Supports macOS and Linux
  • Modular design - Organized in independent, composable configuration files
  • Easy installation - Uses dotbot for automated symlink management
  • Binary management - Uses dotbins for CLI tools with automatic shell integration
  • Remote syncing - Includes scripts to sync dotfiles across machines
  • nix-darwin integration - Uses Nix for declarative macOS configuration

💖 My favorite things

There is a lot of stuff in this repository, but things I won't go without are:

  • I clone this repository and run ./install, and everything is set up automatically!
  • oh-my-zsh for all of the convenient default keybindings and plugins (yes, I know it's bloated and slow)
  • zsh-autosuggestions for command completion
  • starship for a beautiful prompt
  • dotbins for managing binaries
  • dotbot for managing symlinks and installing Python tools with uv
  • keychain for SSH key management
  • direnv for managing environment variables (especially for Python (uv and micromamba))
  • zoxide for jumping around directories (alternative to zsh-z)
  • Keyboard Maestro for keyboard shortcuts to switch between applications
  • zsh-syntax-highlighting for syntax highlighting
  • nix-darwin for declarative macOS configuration

Why not?

  • I don't use fish because I want to be fully compatible with bash, so therefore I use zsh as my main shell.
  • Why not X? I go over my design goals and decisions in this blog post.

🚀 Quick Start

Prerequisites

  • Git and Git LFS installed (on macOS brew install git git-lfs or apt install git git-lfs on Debian/Ubuntu)
  • SSH key set up with GitHub (submodules use SSH)
# Ensure your key is loaded in the agent
ssh-add -l >/dev/null 2>&1 || ssh-add ~/.ssh/id_ed25519

Install the Public Branch

If you’re not me and just want a clean version without private bits, use the always-up-to-date public branch. CI rebuilds it from main and removes anything listed in .publicignore, like the secrets submodule, personal machine configs, etc.

# Clone the sanitized branch with submodules (shallow)
git clone --depth=1 --branch public --single-branch \
  --recurse-submodules -j8 --shallow-submodules \
  [email protected]:basnijholt/dotfiles.git
cd dotfiles
./install

macOS Terminal Font

If prompt icons show as empty squares, install a Nerd Font and select it in Terminal.app:

brew install --cask font-fira-mono-nerd-font

Then in Terminal: Settings → Profiles → Text → Font → choose “FiraMono Nerd Font Mono”. The “Mono” variant forces single‑width glyphs so powerline/nerd icons align perfectly in Terminal.app.

Installation for me (@basnijholt)

First, you need to set up SSH authentication to access private submodules.

Using 1Password

Install 1Password and set up the SSH agent:

export SSH_AUTH_SOCK=~/Library/Group\ Containers/2BUA8C4S2C.com.1password/t/agent.sock
# Clone the repository with submodules
git clone --recurse-submodules -j8 [email protected]:basnijholt/dotfiles.git
cd dotfiles

# Run the installation script
./install

Trying with Docker

Note

Check out how minimal the Dockerfile really is, it only requires a barebones Ubuntu image and Git!

If you want to quickly try out this shell environment without installing it on your main system, you can use the provided Dockerfile:

# Build the Docker image
docker build -t dotfiles-env .

# Run the container and drop into the configured shell
docker run -it --rm dotfiles-env

This will give you an interactive Zsh session within an Ubuntu container, configured using these dotfiles.

Update Remote Machines

# Sync dotfiles to all configured remote hosts
./scripts/sync-dotfiles.sh

# Or install new configuration on remotes
./scripts/sync-dotfiles.sh install

🧩 Repository Structure

.
├── configs                          # Configuration files for various tools
│   ├── nixos                        # NixOS system configurations
│   ├── agent-cli                    # Agent CLI configuration
│   ├── amp                          # Amp Code settings
│   ├── atuin                        # Shell history management
│   ├── bash                         # Bash-specific configuration
│   ├── bat                          # bat pager configuration
│   ├── claude                       # Claude Code settings
│   ├── codex                        # Codex CLI configuration
│   ├── conda                        # Conda/Mamba configuration
│   ├── dask                         # Dask distributed computing
│   ├── direnv                       # Directory-specific environment setup
│   ├── gemini                       # Gemini settings
│   ├── git                          # Git configuration
│   ├── hypr                         # Hyprland window manager config
│   ├── hyprpanel                    # Hyprpanel configuration
│   ├── iterm                        # iTerm2 profiles
│   ├── karabiner                    # Keyboard customization for macOS
│   ├── keyboard-maestro             # Keyboard Maestro macros and configurations
│   ├── lazygit                      # lazygit configuration
│   ├── mako                         # Wayland notifications (mako)
│   ├── mamba                        # Mamba package manager settings
│   ├── nix-darwin                   # Nix configuration for macOS
│   ├── shell                        # Shell-agnostic configurations
│   ├── starship                     # Cross-shell prompt
│   ├── syncthing                    # File synchronization
│   ├── wezterm                      # WezTerm terminal configuration
│   ├── zellij                       # Zellij terminal multiplexer config
│   └── zsh                          # Zsh-specific configuration
├── Dockerfile                       # Docker container that runs this dotfiles configuration
├── LICENSE
├── README.md                        # You are here
├── install                          # Installation script
├── install.conf.yaml                # Dotbot configuration
├── submodules                       # Git submodules for external tools
│   ├── autoenv                      # Directory-based environments
│   ├── dotbins                      # Binaries manager in dotfiles
│   ├── dotbot                       # Dotfiles installation
│   ├── mechabar                     # Waybar + Rofi theme (Hyprland)
│   ├── mydotbins                    # CLI tool binaries managed by dotbins
│   ├── oh-my-zsh                    # Zsh framework
│   ├── rsync-time-backup            # Time-Machine style backup with rsync
│   ├── syncthing-resolve-conflicts  # Syncthing conflicts helper
│   ├── tmux                         # oh-my-tmux configuration
│   ├── truenas-zfs-unlock           # Unlock ZFS pools on TrueNAS
│   ├── zsh-autosuggestions          # Zsh autosuggestions plugin
│   ├── zsh-fzf-history-search       # Fuzzy history search
│   ├── zsh-syntax-highlighting      # Zsh syntax highlighting
│   └── zsh-z                        # Frecent directory jumper
└── uninstall.py                     # Uninstallation script

📋 Shell Configuration

The shell configuration is structured in a modular way under configs/shell/. The main entry point is main.sh which sources other shell-specific files in a specific order:

configs/shell
├── 00_prefer_zsh.sh       # ZSH auto-switching
├── 05_zsh_completions.sh  # ZSH completions setup
├── 10_aliases.sh          # Shell aliases
├── 20_exports.sh          # Environment variables
├── 30_misc.sh             # Miscellaneous settings
├── 40_keychain.sh         # SSH key management
├── 50_python.sh           # Python environment setup
├── 60_slurm.sh            # HPC cluster integration
├── 70_zsh_plugins.sh      # ZSH plugins setup
└── main.sh                # Main shell configuration file

This modular approach makes it easy to understand, maintain, and customize each aspect of the shell environment.

This setup allows my .zshrc to be as simple as:

# zmodload zsh/zprof # Uncomment for profiling

source ~/dotfiles/configs/shell/main.sh

# zprof # Uncomment for profiling

and .bash_profile to be:

source ~/dotfiles/configs/shell/main.sh

🔧 Key Components

Shell Integration

  • Zsh - Primary shell with Oh-My-Zsh, custom theme, and plugins
  • Bash - Fallback shell with compatible configuration
  • Automatic shell detection - Switches to Zsh automatically if available

Development Tools

  • Git - Comprehensive Git configuration with signing, aliases, and more
  • Python - Support for conda/mamba/micromamba environments
  • Direnv - Directory-specific environment variables
  • SSH - Key management with keychain integration

macOS Enhancements

  • nix-darwin - Declarative system configuration
  • Homebrew - Package management via Nix
  • Karabiner - Keyboard customization
  • iTerm2 - Terminal customization

Utility Scripts

The repository includes several useful utility scripts:

scripts
├── apt-update.sh                 # Debian/Ubuntu update: apt update/upgrade/autoremove/autoclean
├── commit.py                     # Generate a conventional commit message from staged changes
├── eqMac.py                      # Inspect macOS audio devices and defaults
├── eqMac.sh                      # Keep eqMac running via cron on macOS
├── fix_my_text_ollama.py         # Clipboard text grammar fix using a local Ollama model
├── git-fixup-file.sh             # Remove a file from commits since branching from main
├── nbviewer.sh                   # Share a Jupyter notebook via nbviewer (after upload)
├── post-clone.sh                 # Initialize submodules with LFS skip for mydotbins, then init rest
├── pypi-sha256.sh                # Print commands to update a conda-forge feedstock checksum
├── rclone.sh                     # Scheduled backups to Backblaze B2 (and rsync to TrueNAS)
├── remove-box.py                 # Strip box-drawing characters from copied code snippets
├── rpi                           # Raspberry Pi helper scripts (mount/unmount LUKS USB)
├── rsync-time-machine.sh         # Create incremental Time Machine-like backups using rsync
├── run.sh                        # Run a command from .dotbins platform bin directory
├── setup-atuin-daemon.sh         # Setup Atuin as a user systemd service
├── signature.html
├── sync-dotfiles.sh              # Push updater to hosts and trigger sync/install
├── sync-local-dotfiles.sh        # On a host: pull latest and optionally run ./install
├── sync-photos-to-truenas.sh     # Sync photos to TrueNAS server
├── sync-uv-tools.sh              # Globally install uv tools I frequently use
├── transcribe.py                 # Stream mic audio to a Wyoming ASR server (clipboard optional)
├── upload-file.sh                # Upload files to various paste/file hosts
└── voice_clipboard_assistant.py  # Voice command assistant for clipboard text via Ollama

🔨 dotbins Integration

This repository uses dotbins to manage CLI tools across platforms. The dotbins.yaml configuration defines both the tools to install and their shell integration:

tools_dir: ~/.dotbins

platforms:
  linux:
    - amd64
    - arm64
  macos:
    - arm64

tools:
  delta: dandavison/delta
  duf: muesli/duf
  dust: bootandy/dust
  fd: sharkdp/fd
  git-lfs: git-lfs/git-lfs
  hyperfine: sharkdp/hyperfine
  rg: BurntSushi/ripgrep
  yazi: sxyazi/yazi

  bat:
    repo: sharkdp/bat
    shell_code:
      bash,zsh: |
        alias bat="bat --paging=never"
        alias cat="bat --plain --paging=never"
  direnv:
    repo: direnv/direnv
    shell_code:
      bash,zsh: |
        eval "$(direnv hook __DOTBINS_SHELL__)"
  # ... and more

dotbins automatically:

  1. Downloads binaries for your platform
  2. Organizes them by OS and architecture
  3. Creates shell integration scripts with your custom aliases and initialization code
  4. Updates all tools with a single command

The generated shell script at ~/.dotbins/shell/zsh.sh is sourced in your shell configuration, making all tools immediately available with their proper setup.

See the output of dotbins status below:

✅ Loading configuration from: ~/.config/dotbins/config.yaml
                            ✅ Installed Tools Summary
┏━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Tool       ┃ Version(s) ┃ Platforms                             ┃ Last Updated ┃
┡━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ atuin      │ 18.10.0    │ linux/amd64, linux/arm64, macos/arm64 │ 13d          │
│ bat        │ 0.26.0     │ linux/amd64, linux/arm64, macos/arm64 │ 13d          │
│ delta      │ 0.18.2     │ linux/amd64, linux/arm64, macos/arm64 │ 75d17h       │
│ direnv     │ 2.37.1     │ linux/amd64, linux/arm64, macos/arm64 │ 28d5h        │
│ duf        │ 0.9.1      │ linux/amd64, linux/arm64, macos/arm64 │ 28d5h        │
│ dust       │ 1.2.3      │ linux/amd64, linux/arm64, macos/arm64 │ 28d5h        │
│ eza        │ 0.23.4     │ linux/amd64, linux/arm64              │ 28d5h        │
│ fd         │ 10.3.0     │ linux/amd64, linux/arm64, macos/arm64 │ 28d5h        │
│ fzf        │ 0.66.1     │ linux/amd64, linux/arm64, macos/arm64 │ 8d3h         │
│ git-lfs    │ 3.7.1      │ linux/amd64, linux/arm64, macos/arm64 │ 13d          │
│ hyperfine  │ 1.19.0     │ linux/amd64, linux/arm64, macos/arm64 │ 28d5h        │
│ keychain   │ 2.9.8      │ linux/amd64, linux/arm64, macos/arm64 │ 17m46s       │
│ lazygit    │ 0.56.0     │ linux/amd64, linux/arm64, macos/arm64 │ 1d2h         │
│ micromamba │ 2.3.3-0    │ linux/amd64, linux/arm64, macos/arm64 │ 13d          │
│ rg         │ 15.1.0     │ linux/amd64, linux/arm64, macos/arm64 │ 13d          │
│ starship   │ 1.24.0     │ linux/amd64, linux/arm64, macos/arm64 │ 8d3h         │
│ uv         │ 0.9.7      │ linux/amd64, linux/arm64, macos/arm64 │ 1d2h         │
│ yazi       │ 25.5.31    │ linux/amd64, linux/arm64, macos/arm64 │ 28d5h        │
│ zoxide     │ 0.9.8      │ linux/amd64, linux/arm64, macos/arm64 │ 28d5h        │
└────────────┴────────────┴───────────────────────────────────────┴──────────────┘


❌ Missing Tools (defined in config but not installed)
┏━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Tool ┃ Repository        ┃ Platform ┃ Architecture ┃
┡━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━━━━┩
│ eza  │ eza-community/eza │ macos    │ arm64        │
└──────┴───────────────────┴──────────┴──────────────┘

Tip: Run dotbins sync to install missing tools

🖥️ Platform-Specific Features

macOS

Before running Nix-darwin, set the hostname:

NAME="basnijholt-macbook-pro"
sudo scutil --set HostName $NAME
sudo scutil --set LocalHostName $NAME
sudo scutil --set ComputerName $NAME
dscacheutil -flushcache

The repository includes nix-darwin configuration for a reproducible macOS setup:

# Install Nix
curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install

# Apply nix-darwin configuration
nixswitch  # Alias for darwin-rebuild switch --flake ~/dotfiles/configs/nix-darwin

Homebrew packages

The nix-darwin configuration manages Homebrew packages declaratively. See the configs/nix-darwin/homebrew.nix file for the list of packages.

Linux

For Linux systems, the configuration automatically adapts to the available environment and provides compatibility with various distributions.

🔄 Syncing to Remote Machines

The repository includes scripts to easily sync your dotfiles to remote machines:

# Sync to all configured remote hosts
./scripts/sync-dotfiles.sh

# Install configuration on remotes (re-run dotbot)
./scripts/sync-dotfiles.sh install

🔐 Secrets Management

Sensitive information is stored in a separate private repository with additional encryption using GPG and git-secret. The structure is as follows:

secrets/             # Private git submodule
└── install          # Installation script for secrets

This submodule requires SSH authentication to access, which is why setting up SSH keys as described in the prerequisites is essential.

🔍 Customization

Pick one path:

  • Recommended (most users): start from the sanitized public branch — see “Install the Public Branch” above. It excludes private bits via .publicignore and the installer is auto-patched accordingly.
  • Advanced (maintainers/power users): start from main if you need the full repo and plan to manage your own secrets.

Steps common to both:

  • Update your details in configs/git/gitconfig-personal (copy from gitconfig-personal.example).
  • Adjust configs/shell/, install.conf.yaml, and submodules/dotbins/dotbins.yaml to taste.

Details: starting from main (advanced)

# Clone with submodules
git clone --recurse-submodules -j8 [email protected]:basnijholt/dotfiles.git ~/dotfiles
cd ~/dotfiles

# Remove the private secrets submodule (you won't have access)
git submodule deinit -f secrets || true
git rm -f secrets || true
git config -f .gitmodules --remove-section submodule.secrets || true

# Personalize Git (edit the file afterward)
cp configs/git/gitconfig-personal.example configs/git/gitconfig-personal

./install

📚 Additional Resources

📄 License

This project is open-source and available under the MIT License.

About

nixos, nix-darwin, homebrew, oh-my-zsh, dotbot, dotbins, macos, linux, submodules, zsh, bash, awesome modern CLI tools — no place like ~/

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published