Skip to content

Instantly share code, notes, and snippets.

@shawngmc
Last active May 27, 2026 12:04
Show Gist options
  • Select an option

  • Save shawngmc/c3231284b774ef68c3de66a0bacbd4ab to your computer and use it in GitHub Desktop.

Select an option

Save shawngmc/c3231284b774ef68c3de66a0bacbd4ab to your computer and use it in GitHub Desktop.
Mac Setup

Settings

  • General - About - Set Hostname
  • General - Langauge & Region - Date Format to ISO!
  • Network - WiFi - Network - Disable Private MAC

Tweaks

  • Open Home Folder (Cmd-Shift-H), then Options (Cmd-J), then Show Library
  • Disable system sleep while plugged in: pmset -c sleep 0

CLI Tooling

# Install Brew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# GNU/Linux common tool installs
brew install wget

# Set up CLI
brew install starship
echo 'eval "$(starship init zsh)"' >> ~/.zshrc && source ~/.zshrc

# Set up FZF
brew install fzf
echo 'source <(fzf --zsh)' >> ~/.zshrc && source <(fzf --zsh)

# Set up nvm and node/npm
brew install nvm
mkdir -pv ~/.nvm
echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.zshrc
echo '[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"  # This loads nvm' >> ~/.zshrc
echo '[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"  # This loads nvm bash_completion' >> ~/.zshrc
source ~/.zshrc
nvm install --lts

# Set up fastfetch
brew install fastfetch
echo 'fastfetch' >> ~/.zshrc

# Install Python
brew install uv
uv python install
uv python pin $(uv python list | grep 'cpython' | grep -v 'freethreaded' | grep -v 'a[0-9]' | head -1 | grep -o '3\.[0-9]*' | head -1)

# Install security tools
brew install testssl ssh-audit


# Bulk install other brew packages
brew install iftop fd ripgrep ugrep yq q tmux asciinema gping nvim bitwarden k9s dive dhex nushell zellij yazi doggo tealdeer crane llmfit

Containerization

# Colima is a open-source runtime
brew install colima
brew services restart colima

# Install docker and compose, then link
brew install docker
brew install docker-compose
mkdir -p ~/.docker/cli-plugins
ln -sfn $(brew --prefix)/opt/docker-compose/bin/docker-compose ~/.docker/cli-plugins/docker-compose

# Install extra tooling
brew install dive
brew install trivy
brew install jesseduffield/lazydocker/lazydocker
brew install crane
brew install lazyjournal
brew install jr-k/d4s/d4s
brew install docker-credential-helper


# Set up autocomplete
mkdir -pv ~/.zsh/completions
docker completion zsh > ~/.zsh/completions/_docker

cat >> ~/.zshrc << 'EOF'

# Docker completions
fpath=(~/.zsh/completions $fpath)
autoload -Uz compinit && compinit
EOF

Bitwarden CLI

brew install bitwarden-cli
bw config server https://bitwarden.hitoma.com
bw login
echo '' >> ~/.zshrc
echo '# Bitwarden Alias' >> ~/.zshrc
echo "alias bw-unlock='export BW_SESSION=\$(bw unlock --raw)'" >> ~/.zshrc
source ~/.zshrc
export BW_SESSION=$(bw unlock --raw)

Gmail via Aerc

#!/usr/bin/env bash

# Install dependencies
brew install aerc w3m

# Platform detection
if [[ "$(uname)" == "Darwin" ]]; then
    AERC_CONF_DIR="$HOME/Library/Preferences/aerc"
    SHELL_RC="$HOME/.zshrc"
    sedi() { sed -i '' "$@"; }
else
    AERC_CONF_DIR="$HOME/.config/aerc"
    SHELL_RC="$HOME/.bashrc"
    sedi() { sed -i "$@"; }
fi

# aerc setup
mkdir -pv "$AERC_CONF_DIR"
cp "$(brew --prefix)/share/aerc/binds.conf" "$AERC_CONF_DIR/binds.conf"
cp "$(brew --prefix)/share/aerc/aerc.conf" "$AERC_CONF_DIR/aerc.conf"

sedi "s|^text/html=! html\$|text/html=$(brew --prefix)/bin/w3m -T text/html -o display_link_number=1|" "$AERC_CONF_DIR/aerc.conf"
sedi 's|^#alternatives=text/plain,text/html$|alternatives=text/html,text/plain|' "$AERC_CONF_DIR/aerc.conf"

cat > "$AERC_CONF_DIR/accounts.conf" << 'EOF'
[Gmail]
source        = imaps://shawngmc@gmail.com@imap.gmail.com:993
outgoing      = smtps+plain://shawngmc@gmail.com@smtp.gmail.com:465
from          = Shawn McNaughton <shawngmc@gmail.com>
default = INBOX
folders-sort = INBOX
postpone = [Gmail]/Drafts
cache-headers = true
source-cred-cmd   = bw get password 79b829cb-8236-4c14-a7df-d3d1344759c8
outgoing-cred-cmd = bw get password 79b829cb-8236-4c14-a7df-d3d1344759c8
carddav-source = https://shawngmc@gmail.com@www.googleapis.com/carddav/v1/principals/shawngmc@gmail.com/lists/default
carddav-source-cred-cmd = bw get password 79b829cb-8236-4c14-a7df-d3d1344759c8
address-book-cmd = carddav-query %s
EOF


Desktop Apps

  • Install Claude
  • Install Google Chrome
  • Install Bitwarden
  • Install Localsend
  • Install VSCode
  • Install ProtonVPN
  • Install Raycast

Gaming

  • Install Battle.Net
  • Install WoW
  • Install CurseForge
  • Install Steam

Install Fonts

brew install fontconfig
brew install --cask font-roboto-mono-nerd-font
# Set in Tabby
# Set in VSCode

Device Management

  • Install Karabiner-Elements (KB customization)
  • Install USB Connection Information (App Store, detailed USB conn info)
  • Install ADB/Scrcpy brew install android-platform-tools scrcpy
  • Install AndroLaunch https://github.com/aman-senpai/AndroLaunch
  • Install FineTune brew install --cask finetune
  • Install BetterDisplay brew install --cask betterdisplay
  • Install BetterDisplay brew install --cask hammerspoon

UI Customization

  • Install alttab brew install --cask alt-tab

Other

  • Install Fuse-T
  • Install Veracrypt
  • Install Tor Browser

Key combinations

https://docs.google.com/spreadsheets/d/1TQeWm3X5-f8UXyZ82FypiX7Cze5nuABNBn2xKa3b970/edit?usp=sharing

-- Dock automation — Anker Prime TB5 (Thunderbolt 5, 14-in-1)
--
-- On dock connect:
-- - Disable system and display idle sleep (caffeinate)
-- - Set primary display to Odyssey G7
-- - Set audio output to Odyssey G7
-- - Mount SMB share: truenas.manavault.local.hitoma.com/ReliquaryTowerFull
-- - Guard audio output against late macOS overrides (e.g. Dell monitor audio)
--
-- On dock disconnect:
-- - Re-enable normal sleep policy
-- - SMB share is left mounted (intentional)
--
-- Note: display resolution and per-screen scaling (including MBP lid state)
-- are managed by BetterDisplay, not this script.
--
-- ─────────────────────────────────────────────
-- Strategy overview:
-- When the dock connects, macOS fires a storm of audio device change events as it
-- enumerates the dock's downstream USB hub (audio interfaces, monitors, etc.).
-- Fighting this in real time causes a feedback loop — every time we set the output,
-- macOS overrides it, we reassert, and so on.
--
-- Instead we use a settle-then-watch approach:
-- 1. On dock connect, enable caffeinate immediately and stay blind to audio events.
-- 2. Wait SETTLE_DELAY seconds for macOS to finish enumerating and settle on its
-- own default output choice (we do not interfere during this window).
-- 3. After the delay, set the desired audio output and display layout once (with
-- retry for audio in case the device hasn't fully enumerated yet).
-- 4. Arm the audio watcher — from this point, any change away from the desired
-- output is corrected immediately, guarding against late overrides.
-- 5. On dock disconnect, disarm the watcher and restore normal sleep policy.
--
-- ─────────────────────────────────────────────
-- Config
-- ─────────────────────────────────────────────
local DOCK_USB_NAME = "Anker Prime Docking Station"
local AUDIO_OUTPUT = "Odyssey G7"
local SCREEN_PRIMARY = "Odyssey G7"
local SCREEN_SECONDARY = "DELL S3220DGF"
local SETTLE_DELAY = 8 -- seconds to wait for device enumeration to settle
-- Note: display resolution and per-screen scaling (including whether the MBP lid
-- is open or closed) are managed by BetterDisplay, not this script.
local SMB_SHARE = "smb://truenas.manavault.local.hitoma.com/ReliquaryTowerFull"
local SMB_VOLUME = "ReliquaryTowerFull" -- volume name as it appears under /Volumes
-- ─────────────────────────────────────────────
-- State
-- ─────────────────────────────────────────────
local dockConnected = false
local audioWatching = false
-- ─────────────────────────────────────────────
-- Helpers
-- ─────────────────────────────────────────────
local function notify(title, msg)
hs.notify.new({ title = title, informativeText = msg }):send()
end
local function setAudioOutput(deviceName)
local dev = hs.audiodevice.findOutputByName(deviceName)
if dev then
dev:setDefaultOutputDevice()
print("[dock] Audio output → " .. deviceName)
return true
end
print("[dock] Audio device not found: " .. deviceName)
return false
end
local function setAudioOutputWithRetry(deviceName, attempts)
attempts = attempts or 0
if setAudioOutput(deviceName) then
return
elseif attempts < 10 then
print("[dock] Audio device not ready, retrying... (" .. (attempts + 1) .. "/10)")
hs.timer.doAfter(1, function()
setAudioOutputWithRetry(deviceName, attempts + 1)
end)
else
print("[dock] Audio device never appeared: " .. deviceName)
end
end
local function setDisplayLayout(primaryName, secondaryName)
local primary = hs.screen.find(primaryName)
local secondary = hs.screen.find(secondaryName)
if not primary then
print("[dock] Primary screen not found: " .. primaryName)
return false
end
primary:setPrimary()
print("[dock] Primary screen → " .. primaryName)
if secondary then
print("[dock] Secondary screen present: " .. secondaryName)
else
print("[dock] Secondary screen not found: " .. secondaryName)
end
return true
end
local function mountSmbShare(share, volumeName)
-- Skip if already mounted
if hs.fs.attributes("/Volumes/" .. volumeName) then
print("[dock] SMB share already mounted: " .. volumeName)
return
end
print("[dock] Mounting SMB share: " .. share)
-- Use open to hand off to macOS — it handles auth keychain and Finder integration
hs.execute('open "' .. share .. '"')
end
-- ─────────────────────────────────────────────
-- Audio watcher — only active after settle delay
-- ─────────────────────────────────────────────
hs.audiodevice.watcher.setCallback(function(event)
if not audioWatching then return end
if event ~= "dOut" then return end
local current = hs.audiodevice.defaultOutputDevice()
local currentName = current and current:name() or "unknown"
if currentName ~= AUDIO_OUTPUT then
print("[dock] Audio changed → " .. currentName .. ", reasserting " .. AUDIO_OUTPUT)
setAudioOutput(AUDIO_OUTPUT)
end
end)
hs.audiodevice.watcher.start()
-- ─────────────────────────────────────────────
-- Dock connect / disconnect handlers
-- ─────────────────────────────────────────────
local function onDockConnected()
print("[dock] Connected — waiting " .. SETTLE_DELAY .. "s for device enumeration...")
hs.caffeinate.set("systemIdle", true, true)
hs.caffeinate.set("displayIdle", true, true)
audioWatching = false -- stay blind during enumeration storm
hs.timer.doAfter(SETTLE_DELAY, function()
if not dockConnected then return end -- unplugged during wait
print("[dock] Settling complete, applying display, audio, and network config")
setDisplayLayout(SCREEN_PRIMARY, SCREEN_SECONDARY)
setAudioOutputWithRetry(AUDIO_OUTPUT)
mountSmbShare(SMB_SHARE, SMB_VOLUME)
notify("Dock connected", "Sleep disabled · " .. SCREEN_PRIMARY .. " primary · Audio → " .. AUDIO_OUTPUT)
audioWatching = true
end)
end
local function onDockDisconnected()
print("[dock] Disconnected")
audioWatching = false
hs.caffeinate.set("systemIdle", false, true)
hs.caffeinate.set("displayIdle", false, true)
notify("Dock disconnected", "Sleep policy restored")
end
-- ─────────────────────────────────────────────
-- USB watcher
-- ─────────────────────────────────────────────
hs.usb.watcher.new(function(event)
if event.productName ~= DOCK_USB_NAME then return end
if event.eventType == "added" then
dockConnected = true
onDockConnected()
elseif event.eventType == "removed" then
dockConnected = false
onDockDisconnected()
end
end):start()
-- ─────────────────────────────────────────────
-- Startup check
-- ─────────────────────────────────────────────
local function checkDockAtStartup()
for _, dev in ipairs(hs.usb.attachedDevices()) do
if dev.productName == DOCK_USB_NAME then
dockConnected = true
onDockConnected()
return
end
end
end
checkDockAtStartup()
print("[dock] USB watcher running — watching for: " .. DOCK_USB_NAME)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment