A place for me to keep a set of tools, configurations and installation instructions for tools that I use for development on OSX
brew install --cask ghostty
Config file is empty by default, the install.sh script will place the config at ~/.config/ghostty/config.
If the wrong config is loading, check Menu Bar -> Ghosty -> Settings.
brew install neovim
We use Karabiner elements for low-level keyboard remapping, i.e. it captures inputs before they reach the OS.
Mainly we want to use Karabiner to set a hyperkey, then we use Hammerspoon to set keyboard shortcuts using the hyperkey.
We use Hammerspoon and not native solutions (Shorcuts app / Apple script) because they have a noticable action delay.
brew install --cask karabiner-elements
brew install --cask hammerspoon
- In Karabiner under
Complex Modifications:
Add your own rule- paste the contents of karabiner-elements-rules.json
- Under simple modifications for any non mac keyboard we want to swap cmd and option keys, this lets you use your thumb for command like on a mac keyboard.
On a mac with a European layout the § key is replacing the backtick key, and there is a smaller shift button with a backtick next to it.
To map § to backtick and backtick to left shift (extending the left shift key), add the following mappings in Karbiner-Elements:

Then set Virtual Keyboard to ANSI

- clone this repo
- run
sh .hammerspoon/install.sh- this will create a symlink to the.hammerspoonfolder in~/.hammerspoon cp .hammerspoon/Config.lua.template .hammerspoon/Config.lua
brew install pyenv
pyenv install -l - list available versions
pyenv install 3.8
pyenv init (one time, and follow instructions for interactive shell).
Optional: Add the following to ~/.zshrc:
alias python=python3
alias py=python3
alias pip=pip3
pyenv shell <version> -- select just for current shell session
pyenv local <version> -- automatically select whenever you are in the current directory (or its subdirectories)
pyenv global <version> -- select globally for your user account
to unset: pyenv local --unset
brew install --cask betterdisplay
Universal autofill allows you to fill in passwords anywhere in the Mac using a keyboard shortcut (default - cmd + \).
Disable autofill and passwords in MacOs settings completely, 1Password doesn't use those.
I'm using this over other options because at the time of writing it's the only option that's free and has hardware acceleration.
Note: As of 21June2025 you cannot install VMWare Fusion through brew, use web installer instead.
Note: As of 21June2025 clipboard sharing and dragging files between host and guest don't work on Linux guest running KDE with Wayland, so if we want KDE we are forced to use X11, which is inferior. This is a very old bug, so I should probably just use Gnome instead of KDE.
By default modifier keys are sent to the host, this can cause delayed actions on the guest, for example pressing cmd to open Gnome activities will be delayed.
To prevent this:
- Open VMWare settings -> Keyboard and Mouse tab
- In
MacOS shortcutssub-tab, remove checkbox fromEnable Mac OS Host Keyboard Shortcuts - In
Fusion Shortcutssub-tab and ensureMinimize Windowshortcut is enabled
I want to be able to use modifier keys inside the VM without affecting MacOS.
By default there are 3 keyboard shortcuts to switch out of VMWare without closing it:
ctrl+cmd+ ungrab mouse cursorcmd+m- minimize windowcmd+h- hide windows
Note: VMWare does not allow you to modify those.
Since Karbiner elements is low level remapping, any remapping I make in it will affect both the host and the guest.
This means I can write a mapping that maps some shortcut to ctrl + cmd in order to exit the vm.
This also means I could reuse the mapping for switching to VMWare as the mapping to switch out, but that mapping can't rely on the hyper key without conflicts or complicated logic, and I want all app switching to be through the hyper key.
Taking all of this into account I decided that the few extra key presses i.e. (cmd + h -> the actual app shortcut I want) is good enough.
nvim ~/.zshrc
for custom device name (hostname)
# update how command line prompt looks, show full file path
PS1='%n@<your device name> %d %# '
for actual hostname
# update how command line prompt looks, show full file path
PS1='%n@%m %d %# '
# ------ custom commands ------
echo_and_run() { echo "\$ $*" ; "$@" ; }
# replace common npm commands with shortened commands without "run"
# i.e. "npm run start" becomes "npm start"
npm() {
if [[ "$1" == "build" || "$1" == "start" || "$1" == "lint" || "$1" == "dev" ]]; then
local cmd="$1"
shift
echo "Running: npm run $cmd $@"
command npm run "$cmd" "$@"
else
echo "Running: npm $@"
command npm "$@"
fi
}
# brew up - full update for brew, brew packages and brew casks (apps)
brew() {
if [ "$1" = "up" ]; then
echo_and_run brew update && echo_and_run brew outdated --greedy && echo_and_run brew upgrade --greedy && echo_and_run brew cleanup
else
command brew "$@"
fi
}
nvim ~/.zprofile
add the following line:
export HOMEBREW_CASK_OPTS="--appdir=/Volumes/MSI-M461-1TB/Applications --fontdir=/Library/Fonts"
If you want a custom icon for the external storage Applications folder, add the icon before creating the symlink.
To set a custom icon:
- Copy an application icon from the web (or another folder through CMD + I)
CMD + Ithe folder you wish to set an icon for- click the icon and paste
To crate the symlink:
ln -s /Volumes/MSI-M461-1TB/Applications /Applications/ExternalSSD
brew install git
To be able to authenticate via the browser we need to install git-credential-manager
brew install --cask git-credential-manager
When cloning make sure to clone via HTTPS URL
After installing VSCode, we want to add VSCode CLI to path:
In VSCode open Command Pallete and type Shell Command: Install 'code' command in PATH
sudo cp /etc/pam.d/sudo_local.template /etc/pam.d/sudo_localsudo nvim /etc/pam.d/sudo_local- Uncomment
auth sufficient pam_tid.soas per the instructions in the file
In dock settings, enable: Automatically hide and show the Dock.
Then run:
defaults write com.apple.dock autohide-delay -float 0; defaults write com.apple.dock autohide-time-modifier -int 0; killall Dock
to undo:
defaults delete com.apple.dock "autohide-delay"; defaults delete com.apple.dock "autohide-time-modifier"; killall Dock
Now for each shortcut you want to add, do the following:
- Open automator
- Choose the type of your document: Quick Action
- Workflow receives: no input
- in: any application
- Under actions select: Run AppleScript
- write your script
- File -> save, and give the shortcut a name
- Assign a keyboard shortcut in System Settings -> Keyboard -> Keyboard Shortcuts -> Services -> General
Volume up (^F3):
set vol to ((output volume of (get volume settings)) + 5)
if (vol > 100) then set vol to 100
set volume output volume (vol)
Volume down (^F2)
set vol to ((output volume of (get volume settings)) - 5)
if (vol < 0) then set vol to 0
set volume output volume (vol)
Mute/Unmute volume (^F1)
-- Get current mute state via the System Preferences AppleScript API
set currentMute to (do shell script "osascript -e 'output muted of (get volume settings)'")
if currentMute is "true" then
-- Unmute the system
do shell script "osascript -e 'set volume without output muted'"
else
-- Mute the system
do shell script "osascript -e 'set volume with output muted'"
end if
Play/Pause Apple Music (^F6)
Unfortunately there's no simple way to simulate the mac keyboard play/pause key, instead we send play/pause to Apple Music
tell application "Music"
if player state is playing then
pause
else
play
end if
end tell
Next track Apple Music (^F7)
if application "Music" is running then
tell application "Music" to next track
end if
Previous track Apple Music (^F5)
if application "Music" is running then
tell application "Music" to previous track
end if
-
Use f18 instead of ctrl + cmd + option + shift for hyperkey in Karabiner / Hammerspoon- This requires wonky workarounds because hs.hotkeybind requires modifier keys in the array and leaving the modifier array empty makes it so the key is always pressed, current hyperkey works well enough for now.
- Switch to Obsidian for my note taking
- MacOS Tahoe broke Apple Music control via Apple Scripts which I relied on for Music Keybinds, check if there's a fix after some time