Launch Ghostty into Herdr at Mac Login
AI-assisted post: written by Pi from the setup we applied to my dotfiles.
I want my Mac to start where I work.
Right now, that’s Herdr running inside Ghostty.
Adding Ghostty to Login Items gets me halfway there. Setting Herdr as Ghostty’s global command goes too far — every new terminal would open Herdr.
A user LaunchAgent hits the seam. It opens one Ghostty instance into Herdr when I log in.
“When I log in” is the precise version of “when my Mac starts.” User LaunchAgents don’t run before login. That’s exactly what I want for a GUI app.
Keep the LaunchAgent in dotfiles
My dotfiles repo owns system bootstrap and shell wiring. So the LaunchAgent source lives here:
~/dotfiles/launchd/Library/LaunchAgents/dev.herdr.ghostty.plistThat path mirrors where GNU Stow will link it in my home directory.
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict> <key>Label</key> <string>dev.herdr.ghostty</string>
<key>ProgramArguments</key> <array> <string>/usr/bin/open</string> <string>-na</string> <string>Ghostty.app</string> <string>--args</string> <string>-e</string> <string>/bin/zsh</string> <string>-lc</string> <string>exec herdr</string> </array>
<key>LimitLoadToSessionType</key> <string>Aqua</string>
<key>RunAtLoad</key> <true/></dict></plist>The command hiding in that XML is:
open -na Ghostty.app --args -e /bin/zsh -lc "exec herdr"open -na starts a new Ghostty instance. --args sends everything after it to Ghostty. Ghostty’s -e runs a command instead of the default shell.
I run Herdr through a login shell so zsh loads my Homebrew environment. That avoids baking /opt/homebrew into the LaunchAgent.
Link it with Stow
From the dotfiles repo:
cd ~/dotfilesstow launchdThis creates:
~/Library/LaunchAgents/dev.herdr.ghostty.plist -> ~/dotfiles/launchd/Library/LaunchAgents/dev.herdr.ghostty.plistThe repo owns the file. macOS gets it where it expects it.
Make reloads repeatable
macOS will discover the agent on my next login. But I don’t want to log out every time I edit the plist.
I keep the reload incantation in dotfiles too:
#!/bin/bashset -euo pipefail
label="dev.herdr.ghostty"plist="${HOME}/Library/LaunchAgents/${label}.plist"domain="gui/$(/usr/bin/id -u)"
if [[ ! -f "${plist}" ]]; then echo "Missing ${plist}. Run 'stow launchd' from ~/dotfiles first." >&2 exit 1fi
/usr/bin/plutil -lint "${plist}"/bin/launchctl bootout "${domain}/${label}" 2>/dev/null || true/bin/launchctl bootstrap "${domain}" "${plist}"Make it executable and run it:
chmod +x ~/dotfiles/bash/bash/configure-launchdconfigure-launchdIt validates the plist, unloads the previous definition, and bootstraps the new one. Because the job uses RunAtLoad, Ghostty opens into Herdr immediately.
Inspect the loaded agent with:
launchctl print "gui/$(id -u)/dev.herdr.ghostty"The complete system
The durable setup has four parts:
- Ghostty and Herdr live in my
Brewfile. - The LaunchAgent definition lives in dotfiles.
- Stow links it into
~/Library/LaunchAgents. configure-launchdapplies changes without a logout.
Now the ritual isn’t trapped in a settings panel or my memory.
It’s source code.