Skip to content

Repository files navigation

Usage

Setup and periodic maintenance

ansible-playbook -l localhost[,otherhost,...] -K dotfiles-base.yaml

Just nvim

ansible-playbook -l localhost -t nvim -K dotfiles-base.yaml

Config overlays for distro-owned files

Most tracked files are symlinked straight into $HOME by the files role, so editing the live file edits the repo. That does not work for configs the distro also rewrites - Omarchy's update migrations mostly use mv, which replaces the file and destroys the symlink without saying so.

For those, ownership is split: the distro keeps its own base config untracked, personal settings live in a separate overlay file that is tracked and symlinked, and the overlays role asserts the single line that connects them. See roles/overlays/README.md for the mechanics and CHANGELOG.md for why.

Most tracked files do not need this. Direct symlinking is the default and covers the large majority of files/ - nvim, zsh, gh, yamllint, systemd units, gvim, alsa, pipewire and the rest. A file only becomes an overlay when something other than this repo also writes to it.

Four do today:

Where Base config (not tracked) Overlay (tracked here) Wired by
everywhere ~/.bashrc ~/.bashrc_jack group_vars/all.yaml
Omarchy ~/.config/tmux/tmux.conf ~/.config/tmux/local.conf roles/omarchy
Omarchy ~/.config/kitty/kitty.conf ~/.config/kitty/local.conf roles/omarchy

Hyprland is deliberately not in that table. Omarchy's hypr/input.lua, bindings.lua and looknfeel.lua are all-comment templates carrying no settings of their own, so they are symlinked directly like any other tracked file. An overlay there would buy nothing and would break omarchy menu's "input configuration" entry, which opens the base file. See roles/overlays/README.md for the deciding test.

Bash is the oldest of these and predates the pattern having a name: ~/.bashrc is seeded from /etc/skel and carries distro-specific setup, so the repo tracks .bashrc_jack and asserts one source line instead of owning the file. .bash_aliases_jack rides along, sourced by .bashrc_jack.

Only Omarchy needs distro-specific entries. On vanilla Arch, Debian and Ubuntu neither pacman nor apt writes into $HOME - base configs are seeded once from /etc/skel or by the app itself and never upgraded behind your back - so roles/arch and roles/debian carry empty manifests and exist as the extension point plus a symlink health check.

Day to day nothing changes: edit the overlay file at either path, git diff shows it, commit.

Rendered, not symlinked

A third case sits outside both mechanisms above: configs whose content varies by machine. A symlink cannot hold two values, so these are rendered from a template with per-machine variables.

roles/voxtype is the worked example. Two of its settings genuinely differ - the audio source (default on the laptop, the PipeWire echocancel sink on the desktop) and whether voxtype grabs the push-to-talk key itself or leaves it to the compositor, since Omarchy binds recording in Hyprland. Everything else is shared. Per-machine values live in voxtype_machines in group_vars/all.yaml, keyed on the real hostname; a machine with no entry takes the defaults.

Templating also happens to be more robust here than symlinking would be, because voxtype configure rewrites the config in place and would destroy a symlink.

The trade-off: a rendered file is generated, so editing it in ~/.config no longer edits the repo. Reach for this only when content genuinely varies per machine. Prefer a direct symlink, then an overlay, then files/hosts/, and only then a template.

Adopting this on another machine

The playbook deliberately does not reset distro base configs to stock - that is destructive and only you can tell a real customization from stale drift. Do it by hand, in this order.

On a non-Arch host (oracle, homebox) there is nothing to migrate. The arch and omarchy roles end immediately off their own distro. ~/.tmux.conf is still the base config there and now sources the shared overlay, so just run the playbook and confirm tmux still behaves:

ansible-playbook -l oracle dotfiles-base.yaml
tmux kill-server; tmux new -d \; show-options -g | grep history-limit   # expect 100000

On another Omarchy or Arch desktop:

  1. Snapshot first. These are one-way steps.

    omarchy snapshot create                     # Omarchy only; needs sudo
    cp -a ~/.config/{hypr,tmux,kitty} /tmp/preoverlay-backup/
  2. Diff your base configs against stock and copy anything you actually want into the overlay files. Anything not in an overlay is about to be lost.

    for f in tmux/tmux.conf kitty/kitty.conf hypr/bindings.lua hypr/input.lua hypr/looknfeel.lua; do
      echo "=== $f ==="
      diff -u "/usr/share/omarchy/config/$f" "$HOME/.config/$f"
    done

    Split what you find three ways: real customizations (move to the overlay), drift where you never refreshed against a newer default (drop), and settings the current default already matches (drop - a phantom override silently fights future upstream changes).

  3. Hand the base configs back to the distro. Each writes a .bak.<epoch> beside the original.

    for f in tmux/tmux.conf kitty/kitty.conf \
             hypr/bindings.lua hypr/input.lua hypr/looknfeel.lua hypr/hyprland.lua; do
      omarchy refresh config "$f"
    done
  4. Run the playbook. This symlinks the overlay files in and asserts the include lines. It is idempotent - a second run reports changed=0.

    ansible-playbook -l localhost dotfiles-base.yaml
  5. Verify.

    hyprctl reload && hyprctl configerrors        # expect no output
    omarchy menu keybindings --print | grep -i qute
    tmux kill-server; tmux new -d \; show-options -g | grep history-limit
    ~/.config/omarchy/hooks/post-update.d/10-dotfiles-overlay   # expect silence

    The hook printing re-asserted ... means an include line was missing; that is it doing its job, not an error.

  6. Delete the backups once you are satisfied, along with any orphaned pre-Quattro ~/.config/hypr/*.conf, which Hyprland no longer reads.

Bitwarden Secrets Manager sync

This repo now has a secrets role that restores these home-directory secrets from Bitwarden Secrets Manager:

  • ~/.ssh/id*
  • ~/.ssh/config*
  • ~/.config/keys/* except BWS_ACCESS_TOKEN

Recommended bootstrap token location

Recommended:

mkdir -p ~/.config/bitwarden-sm
chmod 700 ~/.config/bitwarden-sm
printf '%s\n' 'YOUR_BWS_ACCESS_TOKEN' > ~/.config/bitwarden-sm/access-token
chmod 600 ~/.config/bitwarden-sm/access-token

Backward-compatible fallback still supported:

  • ~/.config/keys/BWS_ACCESS_TOKEN

Recommendation: use one Bitwarden Machine Account per machine and grant each machine account access to the shared dotfiles project. That gives you per-machine revocation without changing the repo.

Push local secrets into Bitwarden

From the machine that already has the correct files:

script/sync_secrets_to_bws

That script will:

  • create the Bitwarden project dotfiles if needed
  • upsert matching files from ~/.ssh and ~/.config/keys
  • store each file as a Bitwarden secret keyed by its home-relative path

Pull secrets onto a new machine

  1. Clone this repo.
  2. Put a Bitwarden Secrets Manager access token at ~/.config/bitwarden-sm/access-token.
  3. Run the playbook:
ansible-playbook -l localhost[,otherhost,...] -K dotfiles-base.yaml

If you update secrets in the Bitwarden UI, just run the playbook again and the local files will be refreshed.

If you update secrets locally on a machine and want Bitwarden to become the source of truth again, run:

script/sync_secrets_to_bws

Recommendation: prefer editing in the Bitwarden UI for occasional changes, and use script/sync_secrets_to_bws when you intentionally want to publish the current machine state back into Bitwarden.

Start SSH agent and add key

eval $(ssh-agent)
ssh-add ~/.ssh/id_rsa

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages