Multi-Laptop macOS Bootstrap: Migrating Dotfiles to a Versioned Git Repository

Two machines, one source of truth: a reproducible dotfiles repository makes adding a second workstation a two-command operation.
Multi-Machine Setup Series (recommended reading order): Part 1: Migrating off Dropbox | Part 2: Multi-Laptop Bootstrap | Part 3: Security Audit
1 Introduction
Post 64, ‘Migrating Off Dropbox: Beyond Dotfiles’, covers migrating project content, shell history, and large binaries off cloud sync into a three-layer framework. This post picks up where that one ends: the dotfiles layer. After the Dropbox migration, every alias, every shell function, every launchd scheduled job, and every editor setting lives in ~ as plain files, but with no .git folder, no version history, no diff capability, and no rollback mechanism.
The design for a better arrangement already existed. Post 24, ‘Creating a GitHub Dotfiles Repository’, laid out the correct architecture: a standalone ~/dotfiles git repository outside any cloud-sync path, an install.sh that creates symlinks with timestamped backups, platform detection via $OSTYPE, a Brewfile, and an .env.local pattern for secrets. That post was written and published in February 2026 but never executed against the actual configuration.
This post documents the audit that identified three concrete blockers preventing multi-laptop deployment, and the migration procedure that resolves them. It extends post 24’s design with five additions: launchd plist parameterisation, a pipx tool manifest, a vim plugin-manager strategy, an explicit sensitive-files inventory, and migration steps from the current half-installed state.
1.1 Motivations
- The
tnincident (ased -i.bakagainst a cloud-mounted path truncated a production script to zero bytes) demonstrated that cloud sync is not a substitute for version control; git is the correct synchroniser. - Setting up a second MacBook without a deployment mechanism means manually recreating months of accumulated configuration from memory, which is both error-prone and time-consuming.
- Hardcoded absolute paths in scripts and launchd plists break silently on any machine where the directory layout differs even slightly from the primary machine.
- Sensitive files (
~/.aws,~/.ssh,~/.gnupg) live adjacent to tracked dotfiles with no formal inventory and no explicit decision about what belongs in git versus what must remain local. - Understanding the gap between a written architecture and an executed one is itself useful: post 24’s design was sound but several category errors (vim plugin bundles treated as config, runtime caches mixed with user config) were only visible during an actual audit.
1.2 Objectives
- Identify every file that must be tracked, excluded, or handled via a separate secrets mechanism, producing an explicit inventory.
- Create
~/dotfilesas a git repository outside any cloud-sync path, structured per post 24’s layout, and push it to a private GitHub repository. - Write and test
install.shwith--dry-runsupport, launchd__USER__substitution, and per-file symlinks for~/bin. - Verify that a clean bootstrap (on a fresh user account or VM) runs without hardcoded-path failures, undefined variable errors, or leaked secrets.

2 What is a Dotfiles Repository?
A dotfiles repository is a version-controlled directory that stores shell configuration files, editor settings, and system scripts in a form that can be deployed to any new machine with a single command. The analogy to application source code is direct: just as application code can be cloned and built on a fresh server, a dotfiles repository can be cloned and installed on a fresh laptop.
The concrete benefit is reproducibility. Without a dotfiles repository, two machines diverge the moment one is customised. With one, the command git clone git@github.com:rgt47/dotfiles ~/dotfiles && cd ~/dotfiles && ./install.sh brings a new laptop to the same state as the primary machine, minus secrets that must be installed by a separate mechanism.
3 Prerequisites
This post assumes:
- Operating system: macOS 13+ (Ventura or later); the architecture extends to Ubuntu 22.04+ with minor adjustments
- Hardware: Apple Silicon or Intel Mac (the scripts are architecture-agnostic)
- Already installed: git, Homebrew, zsh 5.9+, pipx (for Python CLI tools)
- Background knowledge: comfort editing dotfiles, writing bash scripts, and running shell commands; familiarity with post 24’s design
- GitHub account: with SSH access configured (the repository must be private; never use a public repository for dotfiles)
- Time required: 3-4 hours for the initial migration; 30 minutes to bootstrap subsequent laptops
For those starting from scratch rather than migrating, post 24’s step-by-step walkthrough is the right entry point. This post assumes post 64’s Dropbox migration has been completed and that shell configuration files now live in ~ as plain, unversioned dotfiles.
4 Audit Findings: Three Blockers
Before writing any code, an audit of ~/bin, ~, ~/.config, and ~/.local identified three issues that must be resolved before dotfiles can safely be exported to a second machine.
4.1 Blocker 1: No Version Control
The shell configuration living in ~ has no .git directory. There is no history, no diff capability, and no rollback. As the tn incident showed (covered in post 64), filesystem-level recovery is not guaranteed for in-place edits; git is the only reliable mechanism.
The repository must live at ~/dotfiles, outside any cloud-sync path. Git writes constantly to .git/index, .git/HEAD, and .git/refs/...; a cloud provider syncing those writes simultaneously causes race conditions that corrupt the index and can truncate files to zero bytes. The ~/dotfiles directory is local to each machine; git itself (with GitHub as the remote) is the synchroniser.
4.2 Blocker 2: Hardcoded Absolute Paths
Every script in ~/bin/launchd/, the launchd plists, the cdpath in .zshrc, and the vz alias hardcode machine-specific absolute paths. On a second laptop with even a slightly different directory layout, every such reference fails silently.
The fix is a single environment variable sourced from ~/.zshenv:
# ~/.zshenv
export DOTFILES="${DOTFILES:-$HOME/dotfiles}"
export PRJ_ROOT="${PRJ_ROOT:-$HOME/prj}"Every script and config then references $DOTFILES and $PRJ_ROOT rather than literal paths.
4.3 Blocker 3: Sensitive Files Without an Inventory
Confirmed sensitive items in ~:
~/.aws AWS credentials (plaintext)
~/.docker registry tokens
~/.env project secrets
~/.gnupg private keys
~/.npmrc npm registry token
~/.password-store pass database (encrypted)
~/.ssh SSH private keys
~/.vpn VPN configuration
These must never be committed to git, even in a private repository, because they appear in every cloned working tree and persist in history forever. A .gitignore written before the first git add is the only reliable control; after the first commit, sensitive data requires a full git filter-repo rewrite and credential rotation.
5 Installation: Creating ~/dotfiles
The migration proceeds in three phases: copy, restructure, and commit.
5.1 Phase 1: Copy Existing Content
# Create the new home outside cloud sync
mkdir -p ~/dotfiles
cd ~/dotfiles
mkdir -p shell git editors system config bin launchd packages secrets
# Shell configuration: drop leading dots
cp ~/.zshrc shell/zshrc
cp ~/.zshenv shell/zshenv
cp ~/.gitignore_global git/gitignore_global
cp ~/.lintr lintr
cp ~/.mbsyncrc mbsyncrc
# bin scripts: copy real files (not symlinks)
cp -RL ~/bin/* bin/
rm -f bin/*.bak.*
# XDG configs (selective; leave runtime state behind)
for d in ghostty kitty karabiner gh rclone mutt nvim; do
[ -d ~/.config/$d ] && cp -R ~/.config/$d config/$d
doneDo not copy ~/.config/vim/ (22M of downloaded plugin bundles), ~/.config/coc/ (1.6M of language-server cache), or any directory under ~/.config/ that contains runtime state rather than user configuration. These will be regenerated on each laptop by the plugin manager.
5.2 Phase 2: Write .gitignore Before git init
This step is not optional. Write the .gitignore file before the first git add. One commit with a credential in history requires a full rewrite.
# Sensitive directories: NEVER commit
secrets/*
!secrets/README.md
**/.env
**/.env.local
**/.env.*.local
**/credentials*
**/*.pem
**/*.key
**/id_rsa*
**/id_ed25519*
# Per-machine state
*.backup.*
.DS_Store
.zsh_history
.viminfo
.zcompdump*
# Plugin manager output (regenerated at install time)
config/vim/bundle/
config/vim/plugged/
config/nvim/plugged/
config/nvim/coc/
5.3 Phase 3: Commit and Push
cd ~/dotfiles
git init
git add .
git status # review carefully before committing
git commit -m 'initial dotfiles import'
gh repo create rgt47/dotfiles --private --source=. --pushReview git status output before committing. If any file in the listing looks sensitive, add it to .gitignore and re-check before proceeding.
6 Configuration
6.1 install.sh
The installer creates symlinks from ~/dotfiles into $HOME, handles launchd plist parameterisation, and installs packages via Homebrew and pipx. A --dry-run flag prints every action without executing it.
#!/bin/bash
# install.sh: deploy dotfiles into $HOME via symlinks.
# Idempotent: existing files are backed up with a timestamp
# suffix before being replaced.
set -euo pipefail
DRY_RUN=0
[[ "${1:-}" == "--dry-run" ]] && DRY_RUN=1
DOTFILES="$(cd "$(dirname "$0")" && pwd)"
log() { echo "[INFO] $*"; }
warn() { echo "[WARN] $*" >&2; }
do_or_say() {
[[ $DRY_RUN -eq 1 ]] && echo "[DRY] $*" || "$@"
}
link_file() {
local src="$1" dest="$2"
if [ -e "$dest" ] && [ ! -L "$dest" ]; then
warn "$dest exists, creating backup"
do_or_say mv "$dest" \
"${dest}.backup.$(date +%Y%m%d_%H%M%S)"
fi
do_or_say mkdir -p "$(dirname "$dest")"
do_or_say ln -sfn "$src" "$dest"
log "Linked $src -> $dest"
}
# Shell, git, editors -----------------------------------------------
link_file "$DOTFILES/shell/zshrc" "$HOME/.zshrc"
link_file "$DOTFILES/shell/zshenv" "$HOME/.zshenv"
link_file "$DOTFILES/git/gitconfig" "$HOME/.gitconfig"
link_file "$DOTFILES/git/gitignore_global" "$HOME/.gitignore_global"
link_file "$DOTFILES/editors/vimrc" \
"$HOME/.config/vim/vimrc"
# XDG configs -------------------------------------------------------
for d in "$DOTFILES"/config/*/; do
name="$(basename "$d")"
link_file "$d" "$HOME/.config/$name"
done
# ~/bin scripts: per-file symlinks (not a top-level link) -----------
do_or_say mkdir -p "$HOME/bin"
for f in "$DOTFILES"/bin/*; do
link_file "$f" "$HOME/bin/$(basename "$f")"
done
# launchd plists: substitute __USER__ then install ------------------
do_or_say mkdir -p "$HOME/Library/LaunchAgents"
for plist in "$DOTFILES"/launchd/*.plist; do
name="$(basename "$plist")"
target="$HOME/Library/LaunchAgents/$name"
do_or_say sed "s|__USER__|$USER|g" "$plist" > "$target"
log "Installed $target (with __USER__ -> $USER)"
done
# Package managers --------------------------------------------------
if command -v brew >/dev/null 2>&1; then
do_or_say brew bundle \
--file="$DOTFILES/packages/Brewfile"
fi
if command -v pipx >/dev/null 2>&1 && \
[ -f "$DOTFILES/packages/pipx-tools.txt" ]; then
while read -r tool; do
[[ -z "$tool" || "$tool" =~ ^# ]] && continue
do_or_say pipx install --force "$tool"
done < "$DOTFILES/packages/pipx-tools.txt"
fi
log "Install complete. Manual follow-ups:"
log " - Copy shell/env.local.example to ~/.env.local"
log " - Restore ~/.aws, ~/.ssh, ~/.gnupg from secure storage"
log " - Reload launchd: launchctl bootstrap gui/\$UID \
~/Library/LaunchAgents/*.plist"
log " - Restart shell: source ~/.zshrc"The full source is at analysis/configs/install.sh.
Three deviations from post 24’s original install.sh deserve explanation:
--dry-runflag: prints every operation without executing, allowing review before the first real run on a new machine.- XDG-config and
~/binloops: a new helper script or config directory is picked up automatically without editinginstall.sh. - launchd
__USER__substitution: macOSlaunchddoes not expand~in plist files, so absolute paths are required; the installer writes the substituted plist to~/Library/LaunchAgents/rather than tracking the substituted form in git.
6.2 Makefile
.PHONY: install update lint backup test help
help:
@echo "Targets:"
@echo " install create symlinks; install brew/pipx packages"
@echo " update git pull, then re-run install.sh"
@echo " lint shellcheck bash; zsh -n zsh scripts"
@echo " backup snapshot current dotfiles"
@echo " test install.sh --dry-run plus lint"
install:
./install.sh
update:
git pull origin main
./install.sh
lint:
find bin -type f -name '*.sh' -exec shellcheck {} \;
find shell -type f -exec zsh -n {} \;
backup:
@d=backups/$$(date +%Y%m%d-%H%M%S) && mkdir -p "$$d" && \
for f in .zshrc .zshenv .gitconfig .vimrc; do \
[ -e "$$HOME/$$f" ] && cp "$$HOME/$$f" "$$d/"; \
done
test:
./install.sh --dry-run
$(MAKE) lint
The full source is at analysis/configs/Makefile.
6.3 Capturing Package Manifests
Before the first push, capture the current toolchain so that a new laptop gets the same packages:
brew bundle dump \
--file=~/dotfiles/packages/Brewfile --force
# pipx tools
pipx list --short \
| awk '{print $1}' > ~/dotfiles/packages/pipx-tools.txt
7 The Migration Procedure
With ~/dotfiles populated and committed, deploy to $HOME:
cd ~/dotfiles
./install.sh --dry-run # review all planned actions
./install.sh # executeAfter the installer runs:
Reload launchd agents:
launchctl bootstrap gui/$UID \ ~/Library/LaunchAgents/*.plistRestart the shell:
source ~/.zshrcVerify a sample alias or function resolves correctly.
To bootstrap a second laptop:
git clone git@github.com:rgt47/dotfiles ~/dotfiles
cd ~/dotfiles && ./install.shThen manually restore ~/.aws, ~/.ssh, and ~/.gnupg from secure storage (1Password, pass, or hand-transfer). These are never in git; the installer prints a reminder.
8 Verification
# 1. Confirm symlinks are in place
ls -la ~/.zshrc ~/.gitconfig ~/.config/ghostty
# 2. Check that DOTFILES and PRJ_ROOT resolve correctly
echo "$DOTFILES"
echo "$PRJ_ROOT"
# 3. Verify launchd jobs loaded without error
launchctl list | grep local.
# 4. Confirm pipx tools are installed
pipx list --short
# 5. Dry-run passes cleanly on the current machine
cd ~/dotfiles && make testStep 5 (make test) runs install.sh --dry-run and make lint, which exercises shellcheck against every script in bin/. A clean run with no warnings confirms the repository is in a deployable state.
9 Daily Workflow
After setup, the dotfiles repository becomes a standard git project.
| Command | Action |
|---|---|
cd ~/dotfiles && git diff |
Review uncommitted config changes |
make test |
Lint + dry-run before committing |
make install |
Re-link after adding a new config file |
make update |
Pull from GitHub and re-run install |
make backup |
Snapshot current ~ dotfiles |
brew bundle dump --force |
Refresh Brewfile after new installs |
pipx list --short > pipx-tools.txt |
Update pipx manifest |
The repository should be managed like any other codebase: commit small changes, test before pushing, and keep commit messages descriptive enough to understand what changed and why.
10 Things to Watch Out For
Write
.gitignorebeforegit init, not after. If any sensitive file is committed even once, it must be removed withgit filter-repoand every credential it contained must be rotated. There is no lighter-weight remediation.Do not place the dotfiles repo inside Dropbox, iCloud, or Google Drive. Git writes to
.git/index,.git/HEAD, and ref files continuously; a cloud provider racing to sync those writes can corrupt the index or truncate files to zero bytes. This is the same failure mode as thetnincident (2026-05-03).The launchd
__USER__substitution writes to~/Library/LaunchAgents/, not back to the repo. If you edit a plist in~/dotfiles/launchd/and re-runinstall.sh, the substituted file is overwritten in place. Nevergit addthe file from~/Library/LaunchAgents/; always edit the template in~/dotfiles/launchd/.vim plugin bundle directories must not be tracked. The 22M
~/.config/vim/directory is almost entirely downloaded plugin code managed by vim-plug or Vundle. Track only thevimrcand the plugin manifest; the installer should run the plugin manager on first boot. The same applies to~/.config/coc/(1.6M of language-server cache). Add both to.gitignorebefore the first commit.~/binmust be a real directory populated by per-file symlinks, not a symlink to any directory outside$HOME. A top-level symlink to an absolute path dangles silently on any machine with a different directory layout. The installer creates individual symlinks from~/dotfiles/bin/<script>to~/bin/<script>.Test
install.sh --dry-runon a non-primary user account before running it on a second laptop. The first dry-run on a fresh environment will surface hardcoded paths and assumptions invisible on the primary machine. Identify and fix them before the real bootstrap.
11 Uninstall / Rollback
To remove the dotfiles installation and restore the previous state:
# 1. Reverse the symlinks (restores any .backup.TIMESTAMP files)
for f in ~/.zshrc ~/.zshenv ~/.gitconfig ~/.gitignore_global; do
backup=$(ls "${f}.backup."* 2>/dev/null | tail -1)
if [ -L "$f" ] && [ -n "$backup" ]; then
rm "$f" && mv "$backup" "$f"
fi
done
# 2. Remove ~/bin per-file symlinks (leaves non-symlinked files)
find ~/bin -maxdepth 1 -type l -delete
# 3. Unload launchd agents
launchctl bootout gui/$UID \
~/Library/LaunchAgents/local.*.plist
# 4. Remove the installed plists
rm ~/Library/LaunchAgents/local.*.plist
# 5. Remove the ~/dotfiles repo (optional)
rm -rf ~/dotfilesIf the .backup.TIMESTAMP files were not created (first-run on a machine with no prior dotfiles), step 1 produces empty symlinks that must be removed manually. The --dry-run flag on install.sh shows exactly which files would be backed up before the real run.

12 What Did We Learn?
12.1 Lessons Learnt
Conceptual Understanding:
- A dotfiles repository is the source code for a development environment. Like application code, it should live in git, be tested before deployment, and have a migration path for breaking changes.
- Cloud-sync and git are fundamentally different synchronisation mechanisms with conflicting write patterns. Using cloud storage as a substitute for git version control is not a safe design; it provides neither the branching, diffing, nor rollback capabilities of git, while adding race-condition risk.
- The distance between a written architecture and an executed one accumulates debt. Post 24’s design was correct, but the gap between the written plan and the actual filesystem meant three months of configuration changes had no version history.
- An explicit inventory of sensitive files, written before the first
git add, is a one-time cost that prevents a very expensive recovery. Credential rotation after an accidental commit is not hypothetical; it has happened to experienced engineers.
Technical Skills:
- The
link_filepattern (back up existing files with a timestamp, then create a symlink) makesinstall.shidempotent and re-runnable without destroying local changes. - The
__USER__substitution pattern for launchd plists is a clean solution to the constraint that macOSlaunchddoes not expand~in plist files. - A
--dry-runflag in shell scripts (print every action without executing) is low-cost to implement and essential for validating an installer on a production machine before committing. - Separating package manifests (
Brewfile,pipx-tools.txt,nvim-plugins.lua) from the install script means adding a new tool requires one line in a manifest file, not an edit to the installer logic.
Gotchas and Pitfalls:
- The order of operations matters:
.gitignorebeforegit init,git statusreview beforegit add,--dry-runbefore the real run. Any of these steps skipped creates a problem that is harder to fix than to prevent. - Runtime caches and downloaded plugin code are frequently mixed with user configuration in
~/.config. The rule is: if a directory would be regenerated by running a tool, it is not user configuration and must not be tracked in git. ~/binas a top-level symlink to an absolute path works on the primary machine but produces a dangling symlink on any other machine. The per-file symlink pattern is more verbose but correct across environments.- The
rcloneconfiguration file (~/.config/rclone/rclone.conf) contains OAuth tokens and must be scrubbed of credentials before it is committed, even to a private repository.
12.2 Limitations
- Single-user scope:
install.shdeploys to$HOMEand makes no attempt to set up system-level configuration (/etc/,/usr/local/, or system-wide launchd daemons). - macOS-centric launchd: the launchd plist handling is macOS only. A Linux equivalent using systemd user units would require a parallel code path that this version does not provide.
- No conflict resolution: if
install.shis run on a machine that already has dotfiles managed by a different tool (e.g., chezmoi or GNU Stow), the backup-and-replace strategy may interfere with that tool’s state. - Secrets workflow is manual: the installer prints a reminder to restore
~/.aws,~/.ssh, and~/.gnupg, but provides no automation. On a new laptop, secret restoration remains a manual step that must be performed correctly. - Plugin manifest not yet complete: the vim plugin manifest (
editors/vimrc+ apackages/nvim-plugins.luamanifest) is planned but not yet written. The 22M plugin bundle is excluded from git, which means the firstvimlaunch on a new machine will require a manual:PlugInstall.
12.3 Opportunities for Improvement
- Add a
bootstrap.shthat installs Homebrew and git before cloning the dotfiles repo, making the first command on a truly fresh laptop a singlecurl | bashinvocation (with appropriate scrutiny of what that script does). - Write a systemd user-unit equivalent of the launchd plist section, conditioned on
[[ "$OSTYPE" == "linux-gnu"* ]], so the same dotfiles repository works on Ubuntu development VMs. - Add GitHub Actions CI that runs
install.sh --dry-runandmake linton macOS and Ubuntu runners after every push, catching cross-platform breakage before a laptop bootstrap. - Complete the vim plugin manifest and add a post-install hook to
install.shthat runs:PlugInstallin headless vim, making the editor ready without manual intervention. - Evaluate
git-cryptfor encrypting a small set of near-sensitive configs (rclone config, mbsyncrc) so they can live in the repository without requiring manual scrubbing of credentials.
13 Wrapping Up
The gap between a correct architecture and an executed one is easy to accumulate and expensive to close. Post 24 described the right design for a portable dotfiles repository in February 2026; this post documents the audit that revealed why it had not been executed, identifies the three blockers (no version control, hardcoded absolute paths, and sensitive files without an inventory), and provides the concrete scripts and migration procedure.
The highest-leverage change is also the simplest: git init in a directory outside cloud sync, with a .gitignore written before the first commit. Everything else, the install.sh parameterisation, the launchd __USER__ substitution, the plugin-manifest strategy, builds on that foundation.
In conclusion, four points merit emphasis. First, cloud sync is not version control; a dotfiles repository outside any cloud-mounted path, with GitHub as the remote, is the correct design. Second, .gitignore must be written before git init; this is not a best practice but a prerequisite, since one sensitive commit requires a full history rewrite and credential rotation. Third, install.sh --dry-run should precede every real install; the cost of reviewing the plan is ten seconds, and the cost of an unexpected overwrite can be an afternoon. Fourth, per-file symlinks in ~/bin are more verbose than a top-level symlink but are the only pattern that works reliably across machines with different directory layouts.
14 See Also
Related posts on this site:
- Migrating Off Dropbox: Beyond Dotfiles (post 64): the preceding post in this series; covers migrating project content, shell history, and large binaries off cloud sync into a three-layer framework. This post implements the dotfiles layer.
- Creating a GitHub Dotfiles Repository (post 24, 2026-02-11): the architectural design this post implements.
- Setting Up pass, the Unix Password Manager (post 66): the next step after this post; covers GPG key generation, pass initialisation, and migrating credentials out of cloud sync.
- Multi-Laptop Security: Hardening the Bootstrap (post 67): a security audit of the infrastructure established in posts 64-66; covers FileVault, GPG subkey architecture, per-machine SSH keys, and quarterly review procedures.
Key resources:
- Atlassian Dotfiles Guide: alternative bare-repository approach without
install.sh - shellcheck: static analysis for bash scripts; used in
make lint - pipx documentation: managing Python CLI tools without virtualenv sprawl
- launchd.info: comprehensive reference for macOS launchd plist format and semantics
- git-filter-repo: the correct tool for removing sensitive data from git history (faster and safer than
git filter-branch)
15 Reproducibility
Tested configuration:
| Component | Version |
|---|---|
| Operating system | macOS 15.4 |
| zsh | 5.9 |
| git | 2.45.x |
| Homebrew | 4.3.x |
| pipx | 1.5.x |
| shellcheck | 0.10.x |
| Last verified | [pending] |
Configuration artifacts:
analysis/configs/install.sh: full installer sourceanalysis/configs/Makefile: build targetsanalysis/configs/gitignore:.gitignoretemplateanalysis/configs/zshenv:$DOTFILES/$PRJ_ROOTexports
To reproduce end-to-end:
git clone git@github.com:rgt47/dotfiles ~/dotfiles
cd ~/dotfiles
make test # dry-run + lint
make install # deploy symlinks and packagesRendered on 2026-05-17 at 09:27 PDT.
Source: ~/prj/qblog/posts/65-multi-laptop-bootstrap/multi-laptop-bootstrap/analysis/report/index.qmd
16 Let’s Connect
Have questions, suggestions, or spot an error? Let me know.
- GitHub: rgt47
- LinkedIn: Ronald Glenn Thomas
- Email: rgthomas47@gmail.com
I would enjoy hearing from you if:
- You spot a hardcoded assumption in
install.shthat breaks on your setup. - You have extended the launchd section to work with systemd on Linux.
- You use a different secrets mechanism (
pass,gopass, or a hardware token) and want to compare notes. - You just want to say hello and connect.