An Arch Linux + SwayFX desktop, Catppuccin-themed end to end, with one-command dark/light switching across every app and a declarative package list that rebuilds the whole environment on a fresh machine. Managed as plain git with $HOME as the work tree — no symlinks, no framework.
| Catppuccin Mocha (dark) | Catppuccin Frappé (light) |
|---|---|
![]() |
![]() |
- Whole-desktop theme switching — one darkman toggle re-themes Sway, Waybar, foot, Neovim, tmux, rofi, mako, swaylock, GTK3, and Qt. Running apps update live: foot via
SIGUSR1, Neovim over RPC, Sway/Waybar reload. - Tracked configs never churn — theme hooks write only to an untracked state dir (
~/.local/state/theme/) that the static configsinclude/source. Toggling themes produces zero git diff. - Declarative packages — metapac owns the package list; every entry in
groups/shared.tomlsays which config needs it.bootstrap-packagesprovisions a fresh Arch install,pkgsynckeeps it converged. - Three-tier config layering — public (this repo) → private (separate repo, same work tree) → local (untracked). The same tiers exist for packages (
shared.toml/private.toml/local.toml) and shell snippets (~/.zshrc.d/,~/.zprofile.d/). - 40 ms zsh startup (measured, warm cache) with mise, zoxide, fzf+fd, autosuggestions, syntax highlighting, substring history search, and a 120k-entry shared history — no plugin manager, everything from pacman.
- SwayFX niceties — blur, rounded corners, shadows, per-monitor Waybar, six screenshot bindings (region/window × clipboard/disk/annotate), staged idle→lock→suspend, systemd
sway-session.targetintegration. - Waybar with hand-rolled widgets — water-intake counter, dark/light toggle, btrfs health, weather, pending pacman updates; CPU/memory/network/bluetooth modules click through to
htop/nmtui/bluetui/netscannerin a floating terminal. - Lean Neovim — lazy.nvim with a deliberately small plugin set (catppuccin, snacks.nvim, treesitter, lspconfig+mason, blink.cmp, which-key) plus opencode.nvim wired to a running agent.
| Path | What lives there |
|---|---|
.config/sway/ |
SwayFX config; config.d/ holds theme includes, per-monitor Waybar launch, clipboard manager |
.config/waybar/ |
Bar config + Catppuccin palettes (widget scripts) |
.local/lib/sway/ |
Idle/lock chain, rofi launchers, cliphist picker, display presets, screenshot geometry |
.local/share/dark-mode.d/, light-mode.d/ |
darkman theme hooks, one script per app |
.config/foot/, tmux/, mako/, rofi/, swaylock/ |
Themed app configs (each includes its file from ~/.local/state/theme/) |
.config/nvim/ |
Neovim: init.lua + lua/{options,keymaps,plugins,theme}.lua |
.zshrc, .zprofile |
Shell; both source *.d/ dirs for private/machine-local snippets |
.config/metapac/ |
Declarative package groups |
.claude/skills/system-upgrade/ |
Claude Code skill that runs the full upgrade: Arch news, AUR diff review, metapac update-all, .pacnew merges, breakage fixes, and pinned packages (IgnorePkg) that each record why they are pinned and when to lift the pin |
.local/bin/ |
swm (Sway launcher), wsudo (GUI-as-root), pkgsync, bootstrap-packages, the git-shared/git-private repo wrappers |
Two bare repositories share $HOME as their work tree:
| Wrapper | Repo | Contents |
|---|---|---|
git-shared |
this one (GitHub) | public-safe desktop/WM/shell config |
git-private |
self-hosted | mail/calendar stack, anything personal |
Each wrapper is a single exec:
exec git --git-dir="$DIR/.gitshared" --work-tree="$HOME" \
-c core.excludesFile="$DIR/gitignore-shared" "$@"core.excludesFile points git at the repo's own ignore source (gitignore-shared): deny-all (*), then explicit ! whitelists (parent dirs first, then the file). A file is tracked only if deliberately opted in, and neither repo sees the other's rules. Day to day it's plain git behind an alias: gits status, gits add, gits commit.
This is a personal config, not a distribution. Read what you're about to run. It assumes Arch Linux, and
bootstrap-packagesinstalls ~90 packages including AUR builds (SwayFX among them).
On a fresh Arch install:
git clone --bare https://github.com/thewebmasterp/dotfiles.git ~/.local/share/gitReposDirs/.gitshared
cd ~
git --git-dir ~/.local/share/gitReposDirs/.gitshared --work-tree "$HOME" checkout
~/.local/bin/bootstrap-packages # pacman prereqs → yay → metapac → everything elseIf checkout complains about existing files (a distro-default .zshrc, say), move them aside and re-run. Log in on a TTY and start the session with swm; from then on gits manages config and pkgsync converges packages.
Everything is plain files at the paths listed above, so extraction is copy-paste:
- The theme-switching system: copy
.local/share/{dark,light}-mode.d/, installdarkman, and make each app's config include its file from~/.local/state/theme/the wayfoot.ini(include),tmux.conf(source-file), andsway/config(include) do. Hooks are independent — take only the apps you use. - The bare-repo + whitelist mechanism: copy
.local/bin/git-sharedand start your owngitignore-sharedfrom mine (keep the leading*). It's three lines; no symlinks, no copying, no framework. - Declarative packages:
.config/metapac/+.local/bin/pkgsync+bootstrap-packageswork standalone; the annotation-per-package convention is the useful part. - Single widgets (
.local/lib/waybar/*.sh), the screenshot bindings, or the zsh setup — all self-contained.
- The private overlay: mail/calendar/contacts stack and other personal config. This repo alone still yields a complete working desktop.
- Hardware-specific config: display profiles and per-machine packages live in the private/local tiers — supply your own.
- A plugin manager or framework for zsh or tmux — plugins come from pacman and are sourced directly.
MIT.

