thomas.koppandClaude Opus 5 4594ad337a docs: the nvim plugins have to be installed, not worked around
silent! on the colorscheme stops nvim erroring on a machine where PlugInstall
has never run, but it does not give you gruvbox - it gives you the default
theme without saying so. That is a safety net for the gap between checkout and
install, not a fix.

Setting up a machine now lists both steps: packages.sh for the system packages
and PlugInstall for the ten nvim plugins. Also noted that firenvim reports "No
config detected" for every browser on a headless host, which looks like a
failure and is not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 23:55:23 +02:00

dotconfs

Configuration for three machines out of one repository: an Arch desktop, an Arch server and a Mac. The role is decided when the shell starts, not when files are deployed.

The bare-repository technique is from an Atlassian post: a git directory in $HOME/.cfg with $HOME as its work tree, driven by an alias. No symlinks, no extra tooling.

Roles

Role Machine Prompt
desktop beastix — Arch, KDE powerlevel10k, blue
server shron — Arch, headless powerlevel10k, ASCII, red
mobile the Mac — macOS, Apple Silicon ys, green once p10k is there

Red on the server is a guard, not decoration. shron carries mail, web and cloud, and the prompt should answer "which machine is this" before the next command is typed.

The role lives in ~/.config/dotconfs/role, one word, and is not tracked — a shared copy would defeat the purpose. Write it before the first login. Without it the shell falls back to desktop.

Layout

.zshrc                        stub: role, then oh-my-zsh, then the fragments
.zprofile                     login shells only; Homebrew's shellenv
.config/zsh/rc.d/
  05-pre-omz.zsh              theme and plugins - must precede oh-my-zsh
  10-aliases.zsh              shared
  20-functions.zsh            shared
  30-path.zsh                 shared
  50-desktop.zsh              exactly one of these is sourced
  50-server.zsh
  50-mobile.zsh
  90-local.zsh                machine-local, never committed
.config/zsh/p10k-server.zsh   the server's prompt, ASCII and font-agnostic
packages/                     one plain list per platform and role
.scripts/packages.sh          check | install
.scripts/curate.sh            derive a package list from usage

Every machine checks out every file. A KDE configuration on the server is a few inert kilobytes and costs less than the machinery needed to avoid it.

Load order

It matters, and getting it wrong fails quietly:

  1. powerlevel10k instant prompt — must be first, it may print
  2. role
  3. 05-pre-omz.zshtheme and plugins, because oh-my-zsh consumes both while it is being sourced. Set afterwards, they are ignored: an early attempt reported ZSH_THEME=powerlevel10k from a shell running without it.
  4. oh-my-zsh
  5. 10- to 40- — shared
  6. 50-<role>.zshthe prompt colour, because ~/.p10k.zsh assigns POWERLEVEL9K_CONTEXT_BACKGROUND itself and is sourced in 30-path.zsh
  7. 90-local.zsh — last, so it can override anything

Theme before oh-my-zsh, colour after .p10k.zsh. Two constraints pulling in opposite directions.

Portability

Anything that depends on a command is guarded by whether that command exists, rather than duplicated per role:

(( $+commands[lsd] )) && alias ls='lsd'

Without the guard, alias ls='lsd' turns ls into a broken command on a machine without lsd. The Mac is such a machine.

Plugins are assembled per role and then filtered by what is installed. Naming a plugin that is absent produces an oh-my-zsh warning at every single login.

Packages

Lists are plain names, one per line — data, not code, so they port to home-manager and environment.systemPackages almost unchanged.

.scripts/packages.sh          what is missing, what is extra
.scripts/packages.sh install  install what is missing

It never removes anything. Extras are reported and left alone: on a server, individual packages carry mail and web services.

curate.sh derives a candidate list from four usage signals, because each one alone is blind to something — shell history sees no GUI application, KDE's activity database sees no chat client, autostart sees only what starts by itself, and flatpaks never appear in pacman -Qqe. On beastix that turned 512 explicit packages into 62.

Secrets

Credentials live beside the code that reads them and are never committed. The waybar mail module imports from mailsecrets.py; .gitignore covers that, private keys, .netrc, .pgpass, and .config/kdeconnect/, which holds the device certificate.

Machine-local overrides and anything sensitive belong in .config/zsh/rc.d/90-local.zsh, which is sourced last and never tracked.

config add -f still bypasses all of it. The ignore list guards against carelessness, not intent.

Setting up a new machine

curl -Ls https://ls.shron.de/dotconf | /bin/bash

The installer clones into $HOME/.cfg, defines the alias and moves anything in the way to .config-backup. Write the role file before the first login:

mkdir -p ~/.config/dotconfs && echo server > ~/.config/dotconfs/role

Then, by hand:

config config --local status.showUntrackedFiles no
config checkout master

Then install what the configuration files expect but do not carry:

.scripts/packages.sh install                    # system packages for the role
nvim --headless "+PlugInstall --sync" +qall     # the nvim plugins

The nvim step matters more than it looks. gruvbox is a plugin, and until PlugInstall has run, nvim comes up in the default theme. The colorscheme line is wrapped in silent! so a fresh machine does not error before then — that is a safety net for the gap, not a substitute for installing them.

On a headless machine firenvim will report "No config detected" for every browser it looks for. That is expected and harmless.

Earlier revisions of this file used curl -Lks. The -k disables certificate verification against a host that has a valid certificate, removing precisely the protection that matters when piping a remote script into a shell. It is gone.

Day to day

config status
config add .zshrc
config commit -m "..."
config push

status.showUntrackedFiles=no keeps $HOME from drowning the output.

Servers pull over HTTPS rather than SSH: a machine that only consumes configuration has no business holding push credentials.

History

Everything before 2026-08-07 is on archive/2021-i3-sway. That tree described an i3/sway desktop that no longer exists — its display menu drove xrandr outputs the machine does not have — while the live files had moved on by years. master was rebuilt from the running configuration rather than merged with it.

S
Description
No description provided
Readme
243 KiB
Languages
Vim script 75%
Shell 25%