17 Commits
Author SHA1 Message Date
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
thomas.koppandClaude Opus 5 3d1a8da9ef fix(nvim): make the colorscheme optional
Every nvim start on shron printed

  E185: Cannot find color scheme 'gruvbox'

because gruvbox is a vim-plug plugin and :PlugInstall has never run there - the
plugged directory does not exist at all. The config is checked out on all three
machines, so it cannot assume the plugins are present.

silent! is the idiomatic answer: the theme loads where it exists and is skipped
where it does not. The airline settings below need no such treatment; they are
plain variable assignments and are simply ignored when the plugin is absent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:45:53 +02:00
thomas.koppandClaude Opus 5 6999f19b0a fix: resolve powerline's tmux bindings instead of pinning a Python version
tmux.conf sourced
  /usr/lib/python3.11/site-packages/powerline/bindings/tmux/powerline.conf
which puts a Python minor version in a path. It was already wrong before this
repository touched anything: beastix runs 3.14, so tmux has been printing that
error there for however long. shron never had the problem because its own
tmux.conf had the line commented out - until the checkout replaced that file
with this copy, and every session there started with the error.

Replacing a deliberately disabled setting with a broken one is the worse of the
two outcomes, and it is exactly what "every machine carries every file" costs
when a file is not actually machine-neutral.

The path now comes from the module itself, so it survives Python upgrades, and
each step exits quietly if something is missing. The Mac has neither powerline
nor tmux and gets nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:42:19 +02:00
thomas.koppandClaude Opus 5 f2a8d4dec1 docs: describe the role layout and drop the -k from the installer
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>
2026-08-08 22:33:38 +02:00
thomas.koppandClaude Opus 5 6889d6f1da fix(mobile): restore the Mac's update alias
The base defines update only where yay exists. The Mac had its own, wrapping
brew update, upgrade, cask upgrade, greedy upgrade and cleanup, and it was lost
in the checkout.

It was the only real loss there. The eight macports aliases that also went are
no loss at all - MacPorts is not installed on that machine, so pc, pi, pli and
the rest all pointed at a command that does not exist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:31:24 +02:00
thomas.koppandClaude Opus 5 0bfef0662a fix: fall back to ys on any machine without powerlevel10k
The fallback was written for the server role only, so the Mac - which also runs
ys and also has no p10k - dropped through to oh-my-zsh's default theme instead.
A silent downgrade of the prompt on a machine that was working fine.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 22:29:32 +02:00
thomas.koppandClaude Opus 5 003ba4b390 feat(mobile): the Mac role, and role-dependent plugins
Looking at the actual machine turned up something the shared plugin list could
not express. The Mac loads macos, brew and dotbare; beastix and shron load
archlinux. One list filtered by availability - which is what the stub did -
would have dropped four plugins on the Mac without a word. Assembly moves into
05-pre-omz.zsh, which knows the role, and the availability filter stays on top
of it so a plugin that is not installed still cannot produce a warning at every
login.

.zprofile is added, and that is the whole point of the mobile role. The Mac
sets its PATH in .zshrc, so /opt/homebrew/bin exists for interactive shells and
for nothing else: "ssh mac brew --version" comes back empty, which during the
design phase was read as Homebrew not being installed. It is installed, with
178 formulae. Homebrew's shellenv belongs in .zprofile and now lives there; the
loop is inert on Linux, where neither prefix exists.

Carried over from the Mac: the Homebrew auto-update settings and bench(), which
runs bench inside the ERPNext compose stack.

PYTHONPATH pointed at /usr/lib/python3.9/site-packages there too - a Linux path
on macOS, so doubly wrong. All three machines had a variant of that line and
none of them is kept.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 14:11:58 +02:00
thomas.koppandClaude Opus 5 39f9d11200 feat(server): a deliberate powerlevel10k prompt instead of the wizard's
p10k is now installed on shron, so the red prompt the role split was built
around finally applies to the machine it was meant for. Cloned into
$ZSH_CUSTOM/themes rather than installed as a package: no root, nothing outside
the user's home, and undone by deleting a directory.

Without a configuration p10k runs its setup wizard on the first interactive
shell. Over SSH that is a login that sits there waiting for an answer, so the
server gets a written configuration and the wizard is disabled outright.

It is not a copy of beastix's. That one assumes a Nerd Font and a wide
terminal; a server is reached from whatever is at hand, so this uses ASCII,
one line, and a short segment list. user@host is always shown, on red - which
is the whole point.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 17:21:27 +02:00
thomas.koppandClaude Opus 5 4b38b80875 feat(server): carry shron's own configuration into the role file
Task 7 as planned would have checked out over shron and reviewed what was lost
afterwards. That is the wrong order for a machine whose .zshrc holds working
operational tooling: ipt-block, a CrowdSec whitelist helper, reboot_required,
the German locale and dircolors would all have been gone between the checkout
and the review.

Also found: shron runs ZSH_THEME="ys" and has no powerlevel10k. The theme
selection would have fallen through to oh-my-zsh's default, which is a
regression nobody asked for, so 05-pre-omz.zsh keeps ys where p10k is absent.
The red role colour is still set, but it is honest to say it does nothing there
until p10k is installed - the safeguard the role split was built around does
not currently apply to the one machine it was meant for.

05-prompt.zsh becomes 05-pre-omz.zsh: the theme was never the only thing that
has to precede oh-my-zsh. DISABLE_AUTO_UPDATE belongs there too - a server
should not go fetching updates on its own while somebody is logged in fixing
something - and the stub no longer sets the update mode itself.

update-blacklist is carried over with a note rather than silently: openbl.org
answers 301 and the curl call has no -L, so it has been reporting "Blacklist
download failed" for some time. CrowdSec covers that ground now, but the
iptables chain it created may still exist and is worth removing deliberately.

PYTHONPATH pointed at python3.4 on shron and at 3.9 on beastix. Neither
directory exists; neither is carried over.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:59:56 +02:00
thomas.koppandClaude Opus 5 fad8b8f78c fix: set the role colour after .p10k.zsh, and add the config alias
The colour was in 05-prompt.zsh, before oh-my-zsh. That is right for ZSH_THEME
and wrong for everything else: ~/.p10k.zsh assigns
POWERLEVEL9K_CONTEXT_BACKGROUND itself and is sourced from 30-path.zsh, so the
role colour was overwritten before the first prompt was drawn. The isolated
test missed it because the throwaway HOME had no .p10k.zsh; on the real machine
the desktop came up with 0 instead of blue.

Theme before oh-my-zsh, colour after .p10k.zsh - two different constraints that
happen to pull in opposite directions.

The config alias was missing entirely. Without it the bare repository has no
front end, which makes the whole arrangement unusable. Guarded on ~/.cfg
existing so the alias does not appear on a machine that has not been set up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:21:36 +02:00
thomas.koppandClaude Opus 5 b87975402d chore: confirm the server package list against shron
Re-read with a fresh session and identical to the previous day's snapshot, so
the caveat in the header is gone rather than carried around.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:17:46 +02:00
thomas.koppandClaude Opus 5 035c88c31c feat: package lists per role, with a check-and-install script
The lists are derived rather than typed. beastix has 512 explicit packages -
years of experiments among them - so taking that as "what this machine needs"
would be meaningless. curate.sh combines four usage signals, each of which
alone has a blind spot: shell history sees no GUI application, KDE's activity
database sees no chat client, autostart sees only what starts by itself, and
flatpak entries never appear in pacman -Qqe at all. That reduces 512 to 62.

The split follows the data: what beastix and shron both have becomes the base,
the rest of beastix becomes desktop, shron's own becomes server.

base-devel is one entry in the server list rather than its 26 members. It
stopped being a package group in 2022 - "pacman -Sg base-devel" now fails
outright - and is a meta package today. base, grub and linux-lts are dropped
entirely; they arrive with the operating system.

packages.sh never removes anything. Extras are reported and left alone, for
the same reason the BookStack playbook refuses to: on a server, individual
packages carry mail and web services. It avoids process substitution because
/bin/sh is dash on Debian and a POSIX-mode bash on macOS, and this has to run
on both.

Verified on beastix: 62 wanted, 0 missing, 450 extra reported and untouched;
install is a no-op.

The server list is a snapshot from 2026-08-06 and wants re-reading when shron
is reachable again - its login session has since expired.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 16:11:45 +02:00
thomas.koppandClaude Opus 5 d215dfefc5 feat: rebuild master from the live desktop, and add the KDE configuration
master still carried the 2021 tree. Task 6 does a checkout over $HOME, so nine
of those files would have overwritten the current configuration rather than
updated it - i3, sway, dunst, nvim, vim and tmux, all diverged by years. The
plan had no step for this; the design warned about it and then nothing
implemented the warning.

The nine are now taken from the live machine verbatim, and the 31 files with no
counterpart there are dropped. Everything remains on archive/2021-i3-sway.
README.md and .scripts/install.sh are kept despite having no live counterpart:
the first documents the repository and the second is what ls.shron.de/dotconf
serves, so deleting it would break that link.

Verified byte-identical to the live files afterwards, which is the point - a
checkout on this machine must change nothing.

KDE has been in daily use for a while with nothing backing it up. Eighteen rc
files and the nine autostart entries are added: window rules and shortcuts,
notification behaviour, the lock screen, and the panel layout in
plasma-org.kde.plasma.desktop-appletsrc. That last one is rewritten by
plasmashell whenever anything moves, so it will produce churn - kept anyway,
since a lost panel layout is the most tedious thing here to rebuild by hand.

.config/kdeconnect/ is excluded rather than added. It holds the device
certificate and its private key, and is pairing state rather than
configuration - the only place under .config that carries a secret.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:53:50 +02:00
thomas.koppandClaude Opus 5 ce560c315d feat: split zshrc into a stub and role-aware fragments
Load order is the substance of this change, and two attempts got it wrong in
the same way. oh-my-zsh consumes both the plugins array and the theme while it
is being sourced, so anything set afterwards is silently ignored. The plan had
plugins in the stub but the theme in the role file, which produced a shell
reporting ZSH_THEME=powerlevel10k while running without powerlevel10k at all -
132 of its functions missing and nobody any the wiser. Plugins and prompt are
now both resolved before oh-my-zsh, the latter in 05-prompt.zsh.

Portability is handled by asking whether a command exists rather than by
duplicating files per role. "alias ls='lsd'" turns ls into a broken command on
a machine without lsd, and the Mac is such a machine; the yay aliases and
helpers are gated the same way. That keeps one shared base instead of three
diverging copies.

The plan also guessed the plugin list as (git fzf). It is actually seven
entries, so five would have vanished - among them signal-keyring, which turned
out to be a local custom plugin present on this machine only. Naming it
elsewhere means an oh-my-zsh warning at every login, and its content is a
verbatim copy of the gnome-keyring block already in .zshrc, so it ran twice.
The inline block stays, in the desktop role; the plugin is dropped.

Dead code removed rather than carried over:
  - PYTHONPATH pointed at /usr/lib/python3.9/site-packages. Python here is
    3.14 and that directory does not exist.
  - XDG_SESSION_TYPE was forced to x11 and then tested for "wayland" six lines
    below, so that branch could never be taken. The variable belongs to the
    session; overriding it lies to everything that reads it.
  - drm() was defined twice, the first losing to the second on every start.
  - PATH carried ~/bin, ~/.scripts and /usr/X11R6/bin, none of which exist.
    Entries are added only if the directory is there.

Verified against the live configuration in an isolated ZDOTDIR: 277 aliases and
263 functions on both sides, none missing, and powerlevel10k loading for all
three roles with the intended colour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:41:52 +02:00
thomas.koppandClaude Opus 5 49357eced4 chore: ignore secrets, machine-local files and runtime state
The bare repo runs with status.showUntrackedFiles=no, so this is not about
quietening git status - it guards against an absent-minded "config add" over a
home directory full of credentials. It does not stop "config add -f"; nothing
here protects against intent.

mailsecrets.py is listed because that is the existing pattern: the waybar mail
module imports its IMAP credentials from it, and the file has never been
committed. That has held so far by discipline alone.

Private keys are excluded and public ones re-included. Verified with
check-ignore rather than assumed - reading its exit code alone is misleading,
since a matching negative pattern also exits 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 15:28:32 +02:00
thomas.koppandClaude Opus 5 b354c356ae docs: implementation plan for the multi-role layout
Nine tasks, each with the verification that has to pass before the next one
starts. The ordering is dictated by risk rather than convenience: the archive
branch first so the 2021 state is never at stake, beastix before the two remote
machines because it is the source, and the Mac last because it is the only
platform whose PATH problem cannot be reproduced locally.

Every task verifies against an isolated ZDOTDIR before the live .zshrc is
touched, and the two remote rollouts require a second SSH session to stay open.
A broken shell config on shron means no remote login on a production mail
server, so the role file is written before the checkout, not after - otherwise
the default applies and the server comes up on the desktop profile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-06 23:46:41 +02:00
thomas.koppandClaude Opus 5 94b6ba3c33 docs: design for multi-role dotfiles
The repository stopped matching reality in April 2021. It describes an i3/sway
desktop that no longer exists - the display menu drives xrandr outputs the
machine does not have - while .zshrc alone drifted by 360 lines. Checking out
master would overwrite five years of work rather than update anything.

Three machines, no shared base: beastix (Arch/KDE), shron (Arch, headless), a
Mac. Common .zshrc lines between all three: four.

Keeps the existing bare-repo-and-alias method. The role is resolved when the
shell starts, not when files are deployed, so no deployment tooling is needed
at all; every machine carries every file and sources one of them.

Package lists are derived from usage data - shell history, the KDE activity
database, autostart, flatpak - because each signal alone has a blind spot and
pacman -Qqe lists 512 packages including years of experiments. That yields 62.

Plain files and plain lists throughout, so a later move to home-manager stays
cheap.

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