My personal configuration files.
  • Lua 42.3%
  • Shell 41%
  • GLSL 16.6%
  • Assembly 0.1%
Find a file
Josh Quinlan 01a7060976
No real PII in repos; no policy comments in code
Dev bootstrap defaults had leaked a real identity into a
pseudonymous repo, and the fix initially arrived annotated with
a comment restating the rule. Both are now global rules: dummy
data everywhere, purged from history when leaked, and process
rules live here rather than in code comments.
2026-07-13 23:34:06 +01:00
linux/.config/bash Split into shared, macOS, and Linux stow packages 2026-07-08 21:09:44 +01:00
macos Alt-C and Ctrl-T listings via fd; drop custom Ctrl+F 2026-07-11 01:40:59 +01:00
shared No real PII in repos; no policy comments in code 2026-07-13 23:34:06 +01:00
README.md Alt-C and Ctrl-T listings via fd; drop custom Ctrl+F 2026-07-11 01:40:59 +01:00
setup_machine.sh Add ble.sh and fzf to the shell 2026-07-09 00:12:36 +01:00

Dotfiles

My personal dotfiles, managed with GNU Stow. The repo is split into three stow packages so macOS and Linux machines share what they can:

Package Contents
shared/ bash, git, nvim, ghostty, ansible, Claude, portable scripts
macos/ Hammerspoon, LaunchAgents, gnupg (PCSC), brew packages, scripts
linux/ Linux-only shell setup (grows as needed)

Files are stowed with per-file symlinks (--no-folding) so app state written next to stowed files never leaks into the repo. README.md and setup_machine.sh live outside the packages and are never stowed.

The shared .bashrc sources ~/.config/bash/os.sh, which the macos and linux packages each provide their own version of — OS-specific shell setup goes in there, not in the shared file.

New machine setup — macOS

  1. Clone the repo to the home folder:

    git clone ssh://git@forge.quinlan.cloud:2222/joshquinlan/dotfiles.git ~/.dotfiles
    
  2. Run ~/.dotfiles/setup_machine.sh. It is idempotent and handles:

    • Homebrew (installs if missing, works on Apple Silicon and Intel)
    • Stowing shared + macos into $HOME (--adopt means the repo always wins over any pre-existing files)
    • All packages, via get_packages.sh
    • macOS defaults (Hammerspoon config location)
    • Homebrew bash as the login shell
    • TouchID for sudo (/etc/pam.d/sudo_local)
  3. Open Neovim once — lazy.nvim installs itself and all plugins on first launch. Versions are pinned in lazy-lock.json.

New machine setup — Linux

No setup script yet (write one once the distro is known). Manually:

git clone ssh://git@forge.quinlan.cloud:2222/joshquinlan/dotfiles.git ~/.dotfiles
~/.dotfiles/shared/.local/bin/restow --adopt && git -C ~/.dotfiles checkout .

Then install the tools the configs expect: stow, nvim, lsd, most, gpg, gpg-tui, fzf, fd, termscp, and anything else the shell complains about. For ble.sh, either use the distro package or extract the prebuilt nightly tarball to ~/.local/share/blesh (see setup_machine.sh for the exact command; the bashrc also checks /usr/share/blesh).

Day-to-day

  • After adding or removing files in the repo, run restow — it stows shared plus the right OS package automatically. restow -n for a dry run; extra flags pass through to stow.

  • New files go in the most specific package that fits: shared unless it genuinely only makes sense on one OS.

Colour schemes

One palette rules every themed tool. The source of truth is shared/.config/themes/kanagawa.sh (hex values plus curated 256-colour approximations):

  • Runtime consumers (fzf, ble.sh) read the THEME_* variables directly; .bashrc sources the palette early.
  • File-based configs (lsd, termscp, urlscan, the Ghostty cursor shader) are rendered from shared/.config/themes/templates/ by running gen-theme. The generated files carry a GENERATED header and are committed; edit the template or the palette, never the output, then rerun gen-theme (needs envsubst, from the gettext package).

A new scheme is a new palette file defining the same variable set: source it from .bashrc and run gen-theme <name>.

Git identity

  • Default identity is Josh Quinlan <josh@quinlan.cloud>.
  • Repos with GitHub, GitLab, or sr.ht remotes automatically switch to the donquinleone identity via includeIfpriv.inc.

Gotcha: the global git config is itself a stowed file in this repo. Rebasing here checks out old commits, which silently reverts the global config mid-rebase (identity, signing key, everything). When rewriting history in this repo, set the identity explicitly:

GIT_COMMITTER_NAME="Josh Quinlan" GIT_COMMITTER_EMAIL="josh@quinlan.cloud" \
  git commit --amend ...

macOS Gatekeeper

Some apps refuse to open, claiming to be "damaged". That's Gatekeeper. Fix per app with:

xattr -cr /Applications/AppName.app