Portable workstation configuration for Debian and openSUSE, with separate profiles for i3 + XFCE services and KDE Plasma. Interactive work uses Zsh and Neovim. Automation uses Dash wherever the script can assume Dash is installed.
bootstrap deliberately uses /bin/sh: on openSUSE it must install Dash before
any #!/bin/dash program can start. Every other portable executable in this
repository uses /bin/dash.
git clone https://github.com/diogogithub/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
./bootstrap --profile i3-xfce --install --set-shellUse --profile kde, common, or minimal as appropriate. After bootstrap,
invoke ./apply and ./revert directly rather than sh ./apply; otherwise
openSUSE would deliberately run them under Bash instead of Dash.
Inspect first:
./bootstrap --profile i3-xfce --install --dry-run
./apply --profile i3-xfce --list-packagesPackage preferences are plain one-package-per-line files under:
config/packages/debian/
config/packages/opensuse/
The files are grouped into base.required, base.optional,
desktop.optional, i3-xfce.optional, upgrade.required, backup.required,
and keyd.required. Add or remove a line in the relevant distro file; comments
and blank lines are allowed. Stow profiles are equally simple lists under
config/stow-profiles/.
Required packages fail the install if unavailable. Optional packages are tried one at a time and never make the configuration unusable.
apply uses an allow-listed packages/ tree, GNU Stow --no-folding, and never
uses --adopt. Existing files and directory symlinks are moved to:
${XDG_STATE_HOME:-~/.local/state}/dotfiles/backups/<timestamp>/
The exact active profile and backup manifest are recorded. ./revert removes
only those Stow links and restores backups in reverse order. It refuses to
replace a file created after installation.
bootstrap:/bin/sh, because Dash may not exist yet;- apply/revert/private/system maintenance and desktop helpers:
/bin/dash; - secret auditing: Bash, because it intentionally uses extended tests and Git-oriented safety checks;
- interactive shell: Zsh;
- Bash remains a lightweight fallback, not the preferred login shell.
Standard commands keep standard semantics. cat, ls, and cd are not
replaced. Modern tools are exposed through their own names or safe helpers:
rg, fd/fdfind, fzf, bcat, eza, zoxide, direnv, and btop.
The tracked private/ directory is an ignored overlay. Only its README,
.gitignore, and harmless templates are public. Put real material in:
private/common/home/ # copied into $HOME
private/hosts/<hostname>/home/ # host-specific home overlay
private/common/gnupg/import/ # exported .asc keys to import
private/common/system/ # root overlay, explicitly allow-listed
private/hosts/<hostname>/system/ # host-specific root overlay
Apply it with:
./private-apply --agent auto
./private-apply --agent openssh --systemAgent modes are desktop, openssh, gpg, none, and auto. Desktop mode
leaves KDE/GNOME/XFCE integration alone. OpenSSH mode enables the repository's
systemd user socket. GPG mode enables the GnuPG SSH socket. The shell exports
SSH_AUTH_SOCK only when the selected mode requires it.
Never commit the ignored overlay. Keep the clone encrypted if it contains secret keys, and retain an independent offline copy.
System changes are opt-in:
./system-setup --upgrades securityDebian uses the native unattended-upgrades package and APT timers. security
limits origins to Debian Security; full additionally permits the current
stable and stable-updates suites. Major Debian release upgrades remain manual.
openSUSE Leap uses a systemd timer around zypper patch --category security, or
zypper update for full. Tumbleweed accepts only full and uses zypper dist-upgrade, matching the distribution's snapshot upgrade model. Snapper and
the ZYpp plugin are installed for pre/post package snapshots when the system has
a compatible Btrfs/Snapper setup.
Disable managed upgrades with:
./system-setup --upgrades offThe finalized keyd configuration is shared by the desktop and laptop and is
tracked at system/keyd/default.conf:
[ids]
*
[main]
capslock = layer(control)
ro = rightshift
leftcontrol = layer(hyper)
[hyper:C-A-M-S]
capslock = capslockInstall it and enable keyd with:
./system-setup --keyd onThe desktop keyboard detected by keyd monitor was:
BY Tech Gaming Keyboard 258a:010c:3d952825
The ABNT2 / ? key reports as ro, hence ro = rightshift. Effective
behaviour is Caps Lock as Control, ro as Right Shift, Left Control as a
Ctrl+Alt+Meta+Shift Hyper layer, and Left Control + Caps Lock as actual Caps
Lock.
On the laptop, Right Alt remains outside keyd and is configured as AltGr
through XKB:
./system-setup --xkb-abnt2 onThis persists the equivalent of:
sudo localectl set-x11-keymap br abnt2 "" lv3:ralt_switchFor only the current X11 session:
setxkbmap -layout br -model abnt2 -option lv3:ralt_switchrightalt = rightalt is deliberately not added to keyd, because it is a
no-op and does not establish AltGr semantics.
The repository does not configure a Btrfs send/receive replication
pipeline. Snapper provides same-filesystem rollback snapshots for compatible
openSUSE installations; those snapshots remain on the source filesystem and do
not independently protect against device loss. Portable, encrypted backups use
Restic instead.
Copy and edit the private templates:
private/common/system/etc/dotfiles-private/restic.env
private/common/system/etc/dotfiles-private/restic-password
Then install and initialize:
./private-apply --system
./system-setup --backups on --init-backupThe setup does not silently add third-party repositories. If restic is not
available from the repositories enabled on an openSUSE Leap installation,
install Restic from a source you trust before enabling the timers.
The daily timer backs up /etc, /home, /root, /usr/local, /srv, and
/var/backups, plus package/unit/filesystem inventories. This is encrypted
configuration-and-data recovery, not a block-level or bare-metal disk image.
Retention is 7 daily, 5 weekly, 12 monthly, and 3 yearly snapshots. A monthly
timer runs restic check and restores one configured path as a test. Edit
maintenance/restic/include and exclude before installation for
machine-specific datasets. Databases still require application-consistent dumps.
A future Btrfs-native backup mode would require a separately mounted Btrfs
destination and explicit source subvolume selection, then create read-only
snapshots and replicate them with btrfs send/btrfs receive. It should not be
enabled implicitly because it is filesystem-layout and destination specific.
Neovim uses Lua, Lazy.nvim, Mini.nvim, Fzf-lua, Gitsigns, Conform, VimTeX, and
native vim.lsp.start; language servers start only when installed. KDE never
links i3 or Picom. i3 starts only capability-detected XFCE support services.
Machine-specific monitor settings belong in ~/.config/i3/config.d/90-host.conf.
Before changing repository visibility or publishing substantial changes, scan the complete reachable history:
scripts/audit-secretsAlso review commit identities, historical filenames, deleted content, hostnames,
filesystem paths, and other machine-specific metadata. If a specific historical
path or value must be removed, use git filter-repo deliberately rather than
discarding the complete history.
Rotate any credential that was ever committed. Rewriting Git history cannot revoke a credential, and hosting caches or pull-request refs may retain old objects.
CI checks Dash syntax and ShellCheck, the Bash secret audit, Zsh, Lua, i3, systemd units, exact keyboard configuration, system-setup dry-runs, and real Stow round trips in Debian stable, openSUSE Leap, and openSUSE Tumbleweed containers.
MIT. See LICENSE.