An opinionated, cross-platform machine bootstrap system and dotfiles manager for Linux, macOS, and Windows. It uses Ansible for Linux and macOS orchestration and Chezmoi for configuration management.
Warning
The bootstrap scripts install software and change system settings. Review the repository before running them. Fork and customize it if you want to use it as your own dotfiles setup.
Prerequisites: macOS needs Homebrew installed first; Windows needs winget (ships with App Installer on Windows 10/11). Linux needs only curl and sudo. Supported Linux platforms are Ubuntu, Fedora (including Fedora rebuilds such as Nobara), and Arch (including Manjaro and other ID_LIKE=arch derivatives).
Linux:
DOTFILES_REPO="https://github.com/Patruxs/dotfiles.git" \
bash -o pipefail -c 'curl -fsSL https://raw.githubusercontent.com/Patruxs/dotfiles/main/bootstrap.sh | bash'macOS:
DOTFILES_REPO="https://github.com/Patruxs/dotfiles.git" \
bash -o pipefail -c 'curl -fsSL https://raw.githubusercontent.com/Patruxs/dotfiles/main/bootstrap.sh | bash'Windows (PowerShell):
$env:DOTFILES_REPO = "https://github.com/Patruxs/dotfiles.git"
irm https://raw.githubusercontent.com/Patruxs/dotfiles/main/bootstrap.ps1 | iexBootstrap script
β
Detect OS and desktop, choose profile
β
Install packages and apps
β
Apply configs with Chezmoi
The bootstrap script detects your operating system and, on Linux, your desktop environment, then asks you to choose a personal or work profile. It then installs the selected packages and apps using Ansible on Linux and macOS, or PowerShell and Winget on Windows. Finally, Chezmoi applies your configs: shell, Git, tmux, and editors (Neovim, Zed) on Linux and macOS; Git, PowerShell, Neovim, and Zed on Windows. Desktop settings follow the detected desktop: a GNOME session gets the dconf preferences and Shell extensions stored under desktop_environment/gnome/, a KDE Plasma session gets the settings stored under desktop_environment/kde/, and anything else gets neither (the report says so).
By default a step that fails (an upstream installer that is down, a package that does not exist on this release) is skipped and the run keeps going. Every skipped failure, with its error output, ends up in ~/.dotfiles_setup_report.md, a Markdown report that is written on every run - even one that stops before Ansible starts - together with what was installed, what was skipped on purpose, and how to re-run. Pass --strict (or -SetupMode strict on Windows) to stop at the first failure instead. On Windows the configs are created as symlinks, which requires Developer Mode or an elevated shell (bootstrap checks this before applying). If OneDrive redirects your Documents folder, PowerShell loads its profile from OneDrive\Documents instead; link Documents\PowerShell there yourself.
| Document | What it covers |
|---|---|
| Architecture | How a setup run works, the model behind it, and why it is built this way |
| Adding a feature | Adding a tool, profile, or platform, as a checklist |
| Reference | Bootstrap flags, DOTFILES_* variables, and file formats |
| Customizing | Forking this and making it your own |
chezmoi add ~/.bashrc # Manage a new file
chezmoi update -v # Pull and apply latest changes
chezmoi diff # See what will change
chezmoi doctor # Troubleshoot issues
mise ls # Show the CLI tools mise manages and their versions
mise upgrade # Move every mise-managed tool to its latest releaseTo run the bootstrap script manually with a specific profile:
./bootstrap.sh --profile personalSetup detects the desktop environment (scripts/detect-desktop.sh: the running
session first, then this user's session processes, then the installed session
files when nothing is running) and applies only that desktop's settings when a
profile includes desktop_base. --desktop gnome|kde|none or
DOTFILES_DESKTOP overrides the detection, for example over SSH on a machine
that has both desktops installed. The setup report records which desktop was
chosen and why.
./scripts/detect-desktop.sh --explain # what setup will decide, and the evidencePreferences live in home/.chezmoidata/gnome_dconf.yaml and are applied with
dconf inside a running GNOME session. Shell extension state is captured into
desktop_environment/gnome/ and restored by the Ansible gnome role.
./scripts/gnome-extensions-sync.sh capture # machine -> repo, then commit
./scripts/gnome-extensions-sync.sh apply # repo -> machine
./scripts/gnome-extensions-sync.sh diff # what drifted since the last capture
./scripts/gnome-extensions-sync.sh check # exit 0 when already in synccapture writes two files: desktop_environment/gnome/extensions.dconf, a dconf dump of every
per-extension setting, and desktop_environment/gnome/extensions.yaml, the list of which extensions
are enabled and whether they come from extensions.gnome.org or a distro package.
apply downloads the missing extensions.gnome.org ones, loads the settings, then
enables them - log out and back in afterwards for GNOME Shell to pick them up.
Settings live in desktop_environment/kde/settings/, one INI fragment per KDE config file
(kwinrc, kxkbrc, powerdevilrc, ...), and are written key by key with
kwriteconfig6 by the Ansible kde role. KDE rewrites its config files itself,
so they are never symlinked by chezmoi; only the stored keys are touched and
everything else in the live file is left alone.
./scripts/kde-settings-sync.sh capture # machine -> repo, then commit
./scripts/kde-settings-sync.sh apply # repo -> machine
./scripts/kde-settings-sync.sh diff # what drifted since the last capture
./scripts/kde-settings-sync.sh check # exit 0 when already in synccapture copies a fixed list of KDE config files and drops the runtime state
KDE keeps in them (update stamps, window geometry, virtual desktop and screen
UUIDs, shortcuts still at their default). The display layout is machine state
and is not captured.
Panels are captured separately, through plasmashell's scripting API, because their config file is keyed by per-machine IDs:
./scripts/plasma-panels-sync.sh capture # machine -> desktop_environment/kde/panels.json
./scripts/plasma-panels-sync.sh apply # rebuild the panels from the file (needs a Plasma session)
./scripts/plasma-panels-sync.sh diff # what drifted since the last capture
./scripts/plasma-panels-sync.sh check # exit 0 when already in syncTwo more scripts back the stored settings. The plasma_addons feature runs
./scripts/plasma-addons-install.sh install to fetch the add-ons the settings
and panels enable (Krohnkite, the geometry change effect, Active Accent Frame,
KDE Control Station) from their latest upstream release; check and list
report what is installed. The jetbrains_mono_nerd_font feature runs
./scripts/nerd-font-install.sh install on Fedora and Ubuntu, which have no
Nerd Font package, to put JetBrainsMono Nerd Font into ~/.local/share/fonts
from the latest nerd-fonts release. The klassy_theme feature installs Klassy
itself - the window decoration, application style and global theme that
kwinrc and klassy/klassyrc select - from the distribution's own klassy
package where one exists, and otherwise from the upstream home:paulmcauley
repository on the Open Build Service.
gh auth login
docker login
ssh-keygen -t ed25519 -C "you@example.com"Fork or clone the repository, replace the owner-specific values, and select the software and configs you want. Follow the customization guide for the complete process.
Important
Never commit passwords, tokens, private SSH keys, or generated application state.
Chezmoi is set to mode = "symlink". Tracked files are symlinked directly into $HOME. Any edits made by applications modify the tracked file here.
Repository capabilities and profiles
The system is split into two primary profiles to keep work machines lean while fully tricking out personal machines.
| Feature / App Category | OS | Personal Profile | Work Profile | Description / Apps Included |
|---|---|---|---|---|
| Core CLI & Shell | Linux, macOS, Windows | β | β | System packages: git, curl, wget, unzip, gnupg, bash, neovim, ripgrep, jq, fzf, gh. tmux and btop on Linux/macOS only. mise tool list ( core_cli): lazygit, fd, bat, eza, zoxide, superfile, yazi, installed and upgraded from their upstream releases by mise on every platform. Configs: Multi-shell integrations ( bash, zsh, powershell), aliases, .gitconfig with GitHub CLI credential helper. The shell feature sets bash as the login shell on Linux and macOS. The starship_prompt feature installs Starship through mise and wires it into bash, zsh, and PowerShell with its default prompt (~/.config/starship.toml). |
| CLI tool manager | Linux, macOS, Windows | β | β | The mise feature installs mise (distro package on Arch, Homebrew on macOS, mise.run on Ubuntu and Fedora, winget on Windows). Every user-level CLI below is a line in home/dot_config/mise/conf.d/<feature>.toml, requested at latest; setup runs mise install and mise upgrade after the dotfiles are applied, and the shims directory is on PATH for non-interactive contexts. |
| Dev Tools & SDKs | Linux, macOS, Windows | β | β | Languages: nodejs, python3, gcc, go (plus POSIX UCRT on Windows). Package Mgrs: npm, python-pip (Linux), bun (the devtools mise tool list). Testing: playwright (the npm_global_tools mise tool list; needs the node this feature provides). |
| Security / Passwords | Linux, macOS, Windows | β | β | Bitwarden CLI (bw), from the bitwarden_cli mise tool list. |
| Desktop Base | Linux, macOS, Windows | β | β | Editors: VS Code, Obsidian (Zed is its own zed_editor feature, in both profiles). Utils: GitButler, LocalSend, Gear Lever (Linux), GParted (Linux), TreeSize (Windows), rofi and flatpak (Linux). |
| Modern Terminals | Linux, macOS, Windows | β | β | Warp Terminal. Ghostty on Linux and macOS (no Windows build). |
| Docker Ecosystem | Linux, macOS, Windows | β | β | Docker Desktop. A separate docker_engine feature exists for the native engine; no shipped profile selects it. |
| AI CLIs | Linux, macOS, Windows | β | β | claude, codex, agy, opencode, herdr, paseo, pi from the ai_clis mise tool list; droid from its vendor installer (skipped in automation). The personal profile adds llmfit through the llmfit mise tool list. |
| System & Desktop Configs | Linux, macOS, Windows | β | β | SSH host aliases. Linux-only: GNOME dconf preferences and Shell extensions, or KDE Plasma settings, for whichever desktop is detected; user-dirs.dirs (XDG dirs), auto-headphone-switch.service (Systemd, the audio_auto_switch feature, personal profile only), swap/low-memory tuning. |
| Fonts, Plasma add-ons & theme | Linux, macOS | β | β | JetBrainsMono Nerd Font (jetbrains_mono_nerd_font). On KDE Plasma, the plasma_addons feature installs Krohnkite, the geometry change effect, the Active Accent Frame decoration and the KDE Control Station widget from upstream, and the klassy_theme feature installs Klassy, the window decoration and application style the stored KDE settings select. |
| Heavy IDEs | Linux, macOS, Windows | β | β | JetBrains Toolbox, Kiro IDE. |
| Virtualization | Linux, macOS, Windows | β | β | Oracle VirtualBox. |
| Desktop Apps | Linux, macOS, Windows | β | β | Comm/Media: Telegram, Zoom, Spotify, OBS Studio. Work/Utils: Postman, ONLYOFFICE, Edge, Anki, Termius, Bazaar (Linux). System: nvtop (Linux), RevoUninstaller (Win). |
| Terminal toys | Linux, macOS | β | β | cmatrix (terminal_toys). |
Issues and pull requests are welcome. Read CONTRIBUTING.md and follow the Code of Conduct.
For security problems, follow SECURITY.md instead of opening a public issue.
Released under the MIT License.
