2026-10-15 10:24:18 +01:00
2026-10-28 21:22:27 +01:00
2026-10-13 21:21:36 +01:00
2026-10-19 08:17:24 +02:00
2026-09-27 15:21:54 +02:00
2026-09-23 21:49:06 +02:00
2026-09-26 21:54:01 +02:00
2026-09-25 14:26:30 +02:00

Dotfiles

Personal configuration files for an Arch Linux workstation (Hyprland + Neovim + VST plugin), managed with GNU Stow.

Layout

Directory Contents
basic/ Base system packages + the central theme (basic/.config/themes → ~/.config/themes: Catppuccin Mocha palette, current symlink, switch-theme.sh/sync-theme.sh). All other packages reference it instead of copying colors.
term/ Fish + kitty + starship + nvim + tmux + yazi + fastfetch + opencode terminal environment
hypr/ Hyprland compositor config + selectable Noctalia/Caelestia shell configs
kreation/ VST plugin (MT-PowerDrumKit.vst3)
local_ai/ Local AI / MCP tooling config
setup/ Install/setup scripts + package lists (one subdir per target, shared helpers in setup/lib/; not stowed)
test/ Docker test harness (lint + smoke tests)

Each top-level directory is a stow package. stow symlinks the files from the repository into your home directory (e.g. term/.config/... → ~/.config/...).

Prerequisites

  • Arch Linux (or a distro with pacman)
  • stow
  • Relies on git, sudo, curl

Quick start

# 1. Clone the repo
git clone https://github.com/<user>/dotfiles.git ~/.dotfiles
cd ~/.dotfiles

# 2. Install a target and symlink its files
make term       # terminal + fish + kitty + nvim
make hypr       # Hyprland + selectable Noctalia/Caelestia shells
make kreation   # VST plugin (also pulls in basic)

Run make <target> from the repository root. Each target first runs the relevant install script and then stows the package.

The install scripts require sudo and may prompt for your password.

Targets

Target What it does
make term Runs setup/term/setup.sh (installs terminal packages, sets fish as default shell, clones tmuxifier), then stow term. Pulls in basic.
make basic Runs setup/basic/setup.sh: enables multilib, updates the system, installs yay if missing, installs the setup/basic/packages.txt packages, and sets up Docker (enables/starts the service, adds your user to the docker group, verifies the service)
make hypr Runs make basic, installs Hyprland plus the Noctalia and Caelestia frontends, creates a local shell selection when needed, stows hypr, and runs the portal/file-association integration scripts
make kreation make basic, installs VST runtime, stows kreation
make buntes-monster Everything (basic + hypr + kreation), then wires up symlinks

Choosing between Noctalia and Caelestia

make hypr installs both desktop-shell frontends. Hyprland starts the one selected in ~/.config/hypr/env.lua:

return {
    shell = "noctalia", -- or "caelestia"
}

The local env.lua is created from env.example.lua on the first setup and is preserved on later runs. After changing the value, log out of and back into Hyprland; the running shell is not replaced live.

Caelestia requires the upstream AUR package quickshell-git; the release package quickshell must not be installed instead. Do not substitute CachyOS's noctalia-qs, even though it provides the virtual quickshell-git dependency: its Quickshell parser is not compatible with Caelestia. The package list uses the explicit aur/quickshell-git target because yay --aur alone may still select a repository provider. make hypr then replaces an existing noctalia-qs installation transactionally and verifies that /usr/bin/qs belongs to quickshell-git.

Managing terminal packages

The terminal package list lives in a single editable file:

setup/term/packages.txt

Add/remove packages on separate lines. Lines starting with # are ignored, and you can switch between package sources with section markers:

@pacman   # install via pacman (default)
@aur      # use yay's AUR mode; use aur/<pkg> for an explicit source
@npm      # install via npm -g

The default section is @pacman. The AUR helper yay is bootstrapped automatically by setup/basic/setup.sh.

What the install scripts do

  • setup/basic/setup.sh – enables multilib, updates the system (pacman -Syu), ensures yay is installed, reads setup/basic/packages.txt and installs all packages with --needed (skips already-installed ones), and sets up Docker (sudo systemctl enable --now docker, adds the current user to the docker group, checks the service). Idempotent and safe to re-run.
  • setup/term/setup.sh – reads setup/term/packages.txt and installs all packages (pacman/AUR via yay --needed, npm via sudo npm install -g), sets fish as the default shell (chsh), clones tmuxifier, adds the git yazi plugin (skips if already present), and runs sudo updatedb. Idempotent and safe to re-run.

Stow: resolving conflicts with existing paths

stow refuses to create a symlink where a real file or directory already exists on the target (your home directory). When you first set up a machine that already has configs in ~/.config, you typically see an error like:

WARNING: stowing term would cause conflicts:
  * existing target is neither a link nor a directory: .config/fish/config.fish

The recommended workflow is to back up the affected paths and remove them from the target location so stow can take over, then restore anything you want to keep as an overlay on top of the symlink. There are a few common approaches:

Point stow elsewhere so it only reports conflicts without touching anything, then handle the listed paths yourself:

# Dry-run to see exactly which paths conflict
cd ~/.dotfiles
stow --verbose --simulate term

# Inspect the conflicts, then back them up on the target side
mkdir -p ~/.config-backup
mv ~/.config/fish ~/.config-backup/fish      # example — repeat for each conflicting path

# Now stow can create the links
stow term

Afterwards you can restore your old configs on top of the symlinks if you want a custom overlay:

cp -r ~/.config-backup/fish/* ~/.config/fish/

The backup dir lives outside the stow packages, so stow never touches it.

2. Use --adopt with care

git stash        # only if you have uncommitted repo changes you want to keep
cd ~/.dotfiles
stow --adopt term
git checkout .   # discard any files that stow pulled into the repo

stow --adopt moves conflicting files from your home dir into the repository (overwriting what's stored there), then creates the symlink. This is convenient but destructive to the repo copy of those files — always review with a simulate run first and reset via git afterwards if you didn't intend to change the tracked config. Prefer approach #1 unless you deliberately want to recapture your live config into the repo.

3. Skip conflicts you don't manage in the repo

If a path simply shouldn't be managed by stow, use --ignore:

stow --ignore='\.config/(local|misc)' term

Testing

The test/ directory contains a Docker-based test harness that verifies the install scripts, the Makefile, and the stow packages.

There are two tiers:

Target What it does Docker required?
make test-lint Fast, offline integrity checks: bash -n syntax pass over every script, shellcheck (if installed), packages.txt marker validation, and Makefile ↔ script/stow-package name consistency. Catches typos like setup/basic/setuo.sh (missing /). No
make test-stow stow --simulate for every stow-able package; fails if a package the Makefile stows doesn't exist (e.g. stow nvim — nvim lives under term/). No
make test-shellcheck Runs shellcheck over all tracked scripts (shellcheck must be installed). No
make test-lint-docker Builds the /dev stage (archlinux:latest + shellcheck) and runs test/lint.sh inside it. Yes
make test-smoke Builds the /test stage, runs the container's dry probes (make -n over every target, stow --simulate over every Makefile-stowed package, test/lint.sh), and by default installs the real term pacman + npm packages (REAL_SMOKE=1) then verifies them. Every @pacman entry is also pre-resolved against the repo DB, and the install is re-run to prove idempotency. Yes
make test test-lint + test-smoke (the real install runs). Partially

Docker smoke details

make test-smoke                     # real pacman + npm install of the term packages + verify
make test-smoke REAL_SMOKE=0        # dry probes only (fast, no installs)
make test-smoke RUN_SMOKE=1 RUN_FULL=1   # + AUR + hypr/kreation/buntes-monster
make test-smoke SKIP_NET=1          # skip anything that contacts the network

The container:

  • uses archlinux:latest (the scripts assume Arch + pacman),
  • creates a non-root user (mathias, uid 1000) with passwordless sudo so the scripts don't hang on a password prompt,
  • mounts the live repo at /dotfiles (-v "$PWD":/dotfiles), so the tests always run against your current checkout,
  • stubs host-dependent commands as no-ops so nothing talks to a real systemd/dbus inside the container (systemctl, updatedb, kbuildsycoca6, dbus-update-activation-environment, chsh), and routes yay through pacman for the AUR-free smoke.

In the REAL_SMOKE=1 (default) install path, the harness additionally verifies the installed packages (test/verify_packages.sh):

  • every @pacman entry is confirmed via pacman -Q <pkg> (covers fonts, libs and python modules that ship no binary),
  • a curated mapping probes each package's binary with a real --version-style call (e.g. fish --version, nvim --version, ssh -V), failing if the binary is missing or does not report a version.

When in doubt: run stow --verbose --simulate <target> first — it prints what would happen (linking) without changing anything. Never rm -rf the ~/.config of something you still want to keep; move it to a backup directory instead.

S
Description
No description provided
Readme
65 MiB
Languages
Lua 50.8%
Shell 44.4%
Dockerfile 1.8%
Makefile 1.6%
CSS 1.4%