Trying to achieve the best reproducible setup for my personal and professional use
Automated setup for my various machines:
- Home (
home/): Uses Home Manager to create me a reproducible terminal for my use on Arch and WSL2. - System (
system/<System>/): Automatically installs system specific packages.- Arch: Ansible.
- Ubuntu-26.04 in WSL2: Shell script.
- Windows 11: PowerShell script per box (Gaming, Work), no
home/half. - SteamOS on the Legion Go S: shell script, no
home/half.
Every Linux path clones this repo into ~/Projects/dotfiles (load-bearing: home-manager
links ~/.config into it) and ends in homeConfigurations.ak. Windows and SteamOS do neither.
Arch
# skip this block if connected with Ethernet
iwctl
station list # if required to find your wifi device
station wlan0 connect <your_wifi_ssid>
exit
# phase 1: archinstall with system/Arch/archinstall.json (GRUB, locale, NetworkManager,
# zram, the packages phase 2 needs). Set Disk configuration (+ encryption) and
# Authentication (root password, user ak with sudo) in the menu, then Install.
curl -fsSLO https://raw.githubusercontent.com/antonkesy/dotfiles/main/system/Arch/archinstall.json
archinstall --config archinstall.json
# reboot, pull the stick, log in as the new user
# skip this block if connected with Ethernet
nmcli radio wifi on
nmcli device wifi list
nmcli device wifi connect "<SSID>" --ask
# phase 2: ansible (system half, every role) then home-manager
curl -fsSL https://raw.githubusercontent.com/antonkesy/dotfiles/main/system/Arch/bootstrap.sh | bashCopy ~/.ssh over and import the gpg key; the first git push / signed commit
asks for each passphrase once, see Keys.
tailscaled is enabled by ansible; join the tailnet once:
sudo tailscale upUbuntu-26.04 on WSL2
curl -fsSL https://raw.githubusercontent.com/antonkesy/dotfiles/main/system/Ubuntu-26.04-WSL2/bootstrap.sh | bashWindows 11
# Win+X > Terminal (Admin); Gaming or Work
irm https://raw.githubusercontent.com/antonkesy/dotfiles/main/system/Windows-11-Gaming/bootstrap.ps1 | iex
irm https://raw.githubusercontent.com/antonkesy/dotfiles/main/system/Windows-11-Work/bootstrap.ps1 | iexSteamOS on Legion Go S
# Desktop Mode > Konsole
curl -fsSL https://raw.githubusercontent.com/antonkesy/dotfiles/main/system/SteamOS-Legion-Go-S/bootstrap.sh | bashWrite the install ISO to a USB stick and boot:
# 1. download the latest ISO
curl -LO https://geo.mirror.pkgbuild.com/iso/latest/archlinux-x86_64.iso
# 2. find the stick -- pick the whole disk (e.g. sdX), not a partition (sdX1)
lsblk -d -o NAME,SIZE,MODEL,TRAN
# 3. make sure it is not mounted, then write the image
sudo umount /dev/sdX* 2>/dev/null
sudo dd if=archlinux-x86_64.iso of=/dev/sdX bs=4M status=progress oflag=syncwsl --install -d Ubuntu-26.04
wsl
# setup user with name `ak`The deck user has no password and the script needs sudo. Set one once in
Desktop Mode (Steam > Power > Switch to Desktop), in Konsole:
passwd| target | what it does |
|---|---|
make home |
build + activate homeConfigurations.ak |
make arch |
system half of an Arch machine (ansible, every role) |
make wsl |
system half of Ubuntu on WSL2, then switch (re-runnable) |
make lint |
every pre-commit hook on every file |
make test |
Arch playbook dry run in a container (docker) |
make clean |
build outputs, user-level nix garbage, AUR builds |
make use-ssh |
switch origin remote (and submodules) from https to ssh |
The SSH and GPG keys are the one thing this repo cannot carry, and nothing in it
installs them: copy ~/.ssh and ~/.gnupg across by hand, or re-import the gpg key
from a backup, then fix the modes -- 0700 on the directories, 0600 on the private
keys. Leave gpg.conf and gpg-agent.conf alone, home-manager owns those and
rewrites them on every make home.
gpg-agent (home-manager, home/modules/git.nix) caches the passphrase and prompts
in its own window rather than over a TUI: pinentry-gnome3, or on WSL pinentry-qt
through WSLg (WSL has no gcr prompter, gnome3 would fall back to curses). The first
git push and the first signed commit after a login ask once each; commit.gpgsign
is on, so a missing signing key only shows up as a failure at the first commit --
git config user.signingkey says which one git.nix expects.
The cache drops a key 8 hours after its last use and 24 hours after the unlock at
the latest. wsl --shutdown, gpgconf --kill gpg-agent or a make home that
restarts the unit clears it sooner; whichever client signs next asks again.
~/Nextcloud is a streamed WebDAV mount of http://lab:8080, not a sync folder --
home/modules/nextcloud.nix, no desktop client. Like the keys, the app password is
not in this repo, and without it the mount stays skipped:
install -d -m700 ~/.config/rclone && read -s "pw?Nextcloud app password: " && echo && rclone obscure "$pw" > ~/.config/rclone/nextcloud-app-password && unset pw && chmod 600 ~/.config/rclone/nextcloud-app-passwordStore it obscured: rclone misreads an app password as already-obscured otherwise.
- Arch / Ubuntu on WSL
- tmux + zsh + powerlevel10k
- LazyVim
- Hyprland + DankMaterialShell (DMS)
home/.config/dms/plugins.lock.json pins every plugin to a commit and
is tracked; the clones under plugins/ are gitignored. make home re-clones the
ones a machine is missing, and plugin_settings.json / settings.json enable them.
dms plugins install <id> # or the DMS settings GUI; rewrites the lockfile
dms plugins update # then commit the lockfileA private key it cannot read is retried in a loop. Its permissions are too open:
journalctl --user -u gcr-ssh-agent.service -b
chmod 600 ~/.ssh/<key>DMS runs as dms.service, which uwsm pulls in via graphical-session.target.
systemctl --user is-active graphical-session.target # inactive -> not a uwsm session
systemctl --user status dms.service
journalctl --user -u dms.service -bThe AUR package dms is a DLNA server, not DMS, and owns the same
/usr/bin/dms. If it is still installed, sudo pacman -Rns dms before make arch.
yay is built from source (the AUR yay, not yay-bin) against the pacman of
the day, so a pacman update can leave it stale:
yay: error while loading shared libraries: libalpm.so.XX: cannot open shared object file
make arch skips anything pacman -Q already reports, so it will not rebuild
yay on its own. Remove it first and let ansible build it again:
sudo pacman -Rns yay && make archUbuntu's system Python refuses pip install (PEP 668), and pipx is not
installed. Use uv (from the Nix profile) instead: each tool gets its own venv,
the CLI is linked into ~/.local/bin, no sudo:
uv tool install ffmpeg-quality-metrics
uv tool upgrade ffmpeg-quality-metrics
uv tool listPrefer a nixpkgs package in home/modules/ when one exists; uv tool installs
are not reproduced by make home.
If you get:
E: Release file for http://archive.ubuntu.com/ubuntu/dists/resolute-updates/InRelease is not valid yet (invalid for another 1h 9min 10s). Updates for this repository will not be applied.Check if your Windows time is up-to-date and sync if necessary.
Windows Terminal sends a plain Enter for Shift+Enter, so multi-line input in
Claude Code submits instead. Bind it to send ESC + CR:
-
Open Windows Terminal,
Ctrl+Shift+,to opensettings.json. -
Add to the
actionsarray:{ "command": { "action": "sendInput", "input": "\u001b\r" }, "keys": "shift+enter" } -
Save. Windows Terminal reloads the settings on its own.
