Skip to content

Installation

Get your development environment up and running in minutes.

One-Liner Install

The fastest way to get started:

bash
bash -c "$(curl -fsSL https://raw.githubusercontent.com/hyperb1iss/dotfiles/main/install_macos.sh)"

This script automates everything:

  1. Installs Xcode Command Line Tools (if needed)
  2. Sets up Homebrew (detects Apple Silicon vs Intel)
  3. Installs Git and other dependencies
  4. Clones the dotfiles repository to ~/dev/dotfiles
  5. Runs the full installation via make macos, an alias for make install
  6. Configures Zsh as your default shell

First Run If Command Line Tools aren't installed, the script will initiate the installation and exit. Complete

the GUI installer, then run the script again. :::

Manual Install

Prefer to see what's happening? Install step by step:

bash
# 1. Clone the repository
git clone https://github.com/hyperb1iss/dotfiles.git ~/dev/dotfiles
cd ~/dev/dotfiles

# 2. Initialize submodules (Dotbot, tpm)
git submodule update --init --recursive

# 3. Run installation
make install

make install composes base.yaml, os/macos.yaml, and role/desktop.yaml, which together install:

  • Homebrew packages via macos/brew.sh
  • Modern CLI tools (lsd, bat, fd, ripgrep, delta, zoxide)
  • Starship prompt
  • FZF (built from source via Go)
  • Symlinks for configs (zsh, nvim, tmux, git, starship)

make macos is kept as an alias and does the same thing.

Linux

Full Desktop Environment

For workstations with a full desktop:

bash
git clone https://github.com/hyperb1iss/dotfiles.git ~/dev/dotfiles
cd ~/dev/dotfiles
git submodule update --init --recursive
make full

make full runs the sudo tier first, then the composed install:

  • System-level configurations (requires sudo)
  • Desktop environment integrations
  • GUI tools and fonts
  • All shell utilities and CLI tools

Sudo Required The sudo tier runs as root. Review dotbot.d/os/linux-system.yaml first if you're cautious,

or run make install on its own to skip it entirely. :::

Minimal Server Setup

For headless servers or containers:

bash
git clone https://github.com/hyperb1iss/dotfiles.git ~/dev/dotfiles
cd ~/dev/dotfiles
git submodule update --init --recursive
make server

The server role includes:

  • Essential shell utilities only
  • No GUI tools or desktop integrations
  • Lightweight footprint
  • Perfect for SSH environments

Windows

Windows has its own entry point, install.ps1, which does everything the Makefile does everywhere else:

powershell
git clone https://github.com/hyperb1iss/dotfiles.git $env:USERPROFILE\dev\dotfiles
cd $env:USERPROFILE\dev\dotfiles
powershell -ExecutionPolicy Bypass -File .\install.ps1

Windows PowerShell 5.1 defaults to a Restricted execution policy on client editions, which refuses to run any script at all, so the bypass is how a fresh box gets through the first run. Once PowerShell 7 is installed and the policy is RemoteSigned, plain .\install.ps1 works.

In order, it initializes the submodules, installs the winget rows of packages.conf for the role, composes the dotbot layers, records the role in .dotfiles_role, and applies the one step that needs elevation.

One layer, on purpose

Windows composes dotbot.d/os/windows.yaml and nothing else. base.yaml and role/desktop.yaml link unix paths (~/.zshrc, ~/.bashrc.local, ~/bin) and shell out to bash for the SilkCircuit installer, so the Windows layer carries its own copy of the handful of links worth sharing: Neovim, the HyperShell profile, gitconfig, and the Claude Code status line. The HyperShell module directory is linked too, behind an if: guard, so a checkout made before that module landed skips the link instead of failing the whole dotbot run over it.

dotbot.d/private.yaml is skipped for the same reason, and the script says so when ~/dev/dotfiles-private is actually checked out. Every if: guard in it is a POSIX [ -f ... ] test and both of its shell steps are POSIX, while dotbot runs shell through cmd.exe on Windows. The Windows layer links ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md itself, with cmd-syntax guards.

-Role server narrows the winget package set and is what lands in .dotfiles_role. It does not change the layer list, because there is only the one.

Administrator

Elevation is detected once, never demanded. Setting the default WSL version is the only step that needs it, and an unelevated run skips that step by name and installs everything else. Run from an administrator prompt when you want it.

Flags

FlagWhat it does
-Role serverThe smaller winget set, for Windows Server
-SkipPackagesRelink and reconfigure without touching winget
-SkipSubmodulesLeave dotbot and tpm at the revision already checked out
-DryRunPrint every command, including the dotbot invocation, and stop

Nothing prompts, so the script runs headless. The exit code means something too: 1 when dotbot fails, 2 when there is no Python for it to run on.

WSL2

Windows Subsystem for Linux works great:

bash
# In your WSL2 terminal
git clone https://github.com/hyperb1iss/dotfiles.git ~/dev/dotfiles
cd ~/dev/dotfiles
git submodule update --init --recursive
make full

WSL-specific features are automatically enabled:

  • Path conversion utilities (wslpath wrappers)
  • Windows integration functions
  • Cross-platform clipboard support
  • Browser launching from WSL

Installation Targets

CommandLayers composedUse CaseSudo Required
make installbase + os/<uname> + role/desktop + host/privateAny desktop, macOS or LinuxNo
make serverbase + role/server + host/privateServers, containers, lightweightYes, packages
make fullThe sudo tier, then make installFull Linux/WSL desktopYes
make systemos/linux-system onlySystem files, no home changesYes
make privateprivate onlyRefresh the dotfiles-private bitsNo
.\install.ps1os/windows onlyWindows, the whole installOnly for WSL

make macos and make minimal still work; they are aliases for make install and make server.

Layers Compose Profiles no longer collide, so there is no state guard to fight: run make server on a box you

installed as a desktop and it succeeds instead of erroring. Dotbot only adds links, so the desktop links that role no longer installs are left in place; remove them by hand if you want the box genuinely lean. make install records the role it used in .dotfiles_role, which is what the shell reads to decide whether to load the heavier modules. :::

Override the detection when you need to, for example make install ROLE=server or make install HOST=hyperia.

What Gets Installed

Automatically Installed Tools

These are installed by the setup scripts:

Package Managers

  • Homebrew (macOS) — Via official install script
  • cargo (via rustup) — For Rust-based tools
  • winget (Windows), which ships with Windows 10 and 11 and needs no bootstrap

The package list itself is packages.conf at the repo root, resolved and installed by bin/pkg-sync. Run bin/pkg-sync list apt server to see exactly what a role gets, or add -n to an install to print the plan instead of running it.

winget rows live in that same file, carrying package ids rather than names because that is what winget install --id matches exactly. A fresh Windows box has no bash, so bin/pkg-sync.ps1 reads the manifest with the same grammar and install.ps1 calls it. Keeping the two readers honest is one command:

bash
diff <(bin/pkg-sync list winget desktop) <(pwsh -NoProfile -File bin/pkg-sync.ps1 list winget desktop)

bin/pkg-sync export winget desktop writes a winget import document to stdout if you would rather feed winget directly.

Modern CLI Tools

  • lsd — Better ls with icons
  • bat — Better cat with syntax highlighting
  • fd — Better find that's faster
  • ripgrep — Better grep that's blazing fast
  • delta — Beautiful git diffs
  • zoxide — Smarter cd that learns

Essential Utilities

  • Starship — Cross-shell prompt
  • fzf — Fuzzy finder (built from Go source)
  • tree — Directory tree viewer

Prerequisites (Must Exist)

These should already be on your system:

  • Git — For cloning and submodules
  • curl — For downloading installers
  • Make — For running installation scripts

On macOS, these come with Command Line Tools. On Linux, install via your package manager:

bash
# Ubuntu/Debian
sudo apt-get install git curl make

# Fedora/RHEL
sudo dnf install git curl make

# Arch
sudo pacman -S git curl make

Post-Installation

Reload Your Shell

bash
# Reload your config
source ~/.zshrc

# Or simply open a new terminal

Verify Installation

Check that everything loaded correctly:

bash
# Test shell utilities
type gwt        # Git worktree manager
type gadd       # Interactive git add

# Check modern tools
lsd --version   # ls replacement
bat --version   # cat replacement
fd --version    # find replacement
rg --version    # grep replacement

# Verify Starship prompt
starship --version

# Check Neovim (if installed)
nvim --version

You should see the Starship prompt with the SilkCircuit theme immediately.

Updating

Keep your dotfiles fresh:

bash
cd ~/dev/dotfiles

# Pull latest changes
git pull

# Update submodules
git submodule update --remote --recursive

# Or use the convenience command
make update

To re-apply configuration after updates:

bash
make install  # re-run the composed install

This is safe to run multiple times—it won't reinstall packages, just update symlinks and configurations.

Smoke Tests

The install runs against fresh machines in CI so a broken layer shows up on a pull request instead of the next time you set up a box.

bash
make smoke

That runs the same scripts CI does, from .github/smoke/. First it checks that make -n install composes the layers this OS expects, then it does a link-only pass over them: the layers go through Dotbot with --only clean create link against a temporary HOME, so nothing is downloaded and your real home directory is never touched. Then the container jobs run, if docker or podman is installed and its daemon answers. Without that it says what it skipped and still reports the rest.

Which layers each lane composes lives in one place, .github/smoke/layers.sh, so the workflow and make smoke cannot disagree about what they are testing.

The container jobs each build a machine from nothing. A bare ubuntu:24.04 or archlinux:latest image gets the handful of packages an install needs to start, an unprivileged user with passwordless sudo, and a copy of the checkout at ~/dev/dotfiles, which is where the shell configs expect to find it. Then:

JobWhat it proves
ubuntu-servermake server completes on Ubuntu, every link resolves, zsh -i and bash -i load their rc files
arch-serverThe same on Arch, through pacman instead of apt
ubuntu-desktop-linksThe desktop layers plus host/hyperia.yaml parse and link, without installing a graphical stack

The expected links are read out of the layer yaml as the test runs, so adding a link to dotbot.d/ needs no bookkeeping anywhere else.

What the matrix does not cover: the sudo tier (make system), Homebrew and the macOS defaults in os/macos.yaml, the private overlay, and the graphical Linux stack. The macOS job composes the layers and links them against a temporary HOME rather than installing, since a real macOS install means Homebrew and a long list of casks. Arch runs on an amd64 image, so make smoke emulates it on Apple Silicon and takes noticeably longer there than the Ubuntu jobs do.

make smoke stops at the first container job that fails. To rerun one on its own:

bash
./.github/smoke/run-container.sh arch-server

Set SMOKE_INTERACTIVE=0 to skip the interactive shell check, which is the one step that reaches the network after the packages land (Zinit clones its plugins on first run).

Troubleshooting

Homebrew Not Found (macOS)

If brew isn't in your PATH after installation:

bash
# Apple Silicon (M1/M2/M3)
eval "$(/opt/homebrew/bin/brew shellenv)"

# Intel Mac
eval "$(/usr/local/bin/brew shellenv)"

Then reload your shell or open a new terminal.

Zinit Errors

If you see Zinit plugin errors:

bash
# Reinstall Zinit
rm -rf "${HOME}/.local/share/zinit"
source ~/.zshrc  # Zinit will auto-install

Starship Not Showing

If the prompt looks plain:

bash
# Verify Starship is installed
which starship

# Check config exists
ls -la ~/.config/starship.toml

# Manually initialize (should be automatic)
eval "$(starship init zsh)"

FZF Not Working

If fuzzy finding isn't available:

bash
# Check if fzf is installed
which fzf

# If missing, install via Go
go install github.com/junegunn/fzf@latest

# Ensure Go bin is in PATH
export PATH="$HOME/go/bin:$PATH"

Uninstallation

The dotfiles use symlinks, so removing them is straightforward:

bash
# Remove symlinks (configs will revert to defaults)
rm ~/.zshrc
rm ~/.config/starship.toml
rm ~/.tmux.conf
rm ~/.gitconfig
rm -rf ~/.config/nvim

# Remove the repository
rm -rf ~/dev/dotfiles

# Remove Zinit and its plugins
rm -rf "${HOME}/.local/share/zinit"

Homebrew Packages This won't uninstall Homebrew packages or cargo tools. Remove those manually if needed:

bash
# List installed Homebrew packages
brew list

# Remove specific package
brew uninstall lsd bat fd ripgrep

Next Steps

Released under the MIT License