The README still described the 2021 arrangement. It now documents the three roles, the rc.d layout and packages.sh, and spends most of its length on the load order - because that is where this fails quietly. Theme and plugins must precede oh-my-zsh, which consumes both while sourcing; the prompt colour must follow .p10k.zsh, which assigns it. Both were got wrong once, and the first produced a shell reporting ZSH_THEME=powerlevel10k while running without it. The installer line loses its -k. Disabling certificate verification against a host that has a valid certificate removes exactly the protection that matters when piping a remote script into a shell. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
5.6 KiB
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:
- powerlevel10k instant prompt — must be first, it may print
- role
05-pre-omz.zsh— theme and plugins, because oh-my-zsh consumes both while it is being sourced. Set afterwards, they are ignored: an early attempt reportedZSH_THEME=powerlevel10kfrom a shell running without it.- oh-my-zsh
10-to40-— shared50-<role>.zsh— the prompt colour, because~/.p10k.zshassignsPOWERLEVEL9K_CONTEXT_BACKGROUNDitself and is sourced in30-path.zsh90-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
Earlier revisions of this file used
curl -Lks. The-kdisables 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.