Shepherd connects to herdr, a terminal multiplexer for coding agents, and watches your agents across local and remote hosts from the menu bar. When an agent starts waiting for your input, the icon turns red.
brew install cryks/tap/shepherdOr download the zip from Releases and move Shepherd.app into /Applications.
Notifications are off by default. Enable them in General settings to get a macOS notification when an agent becomes blocked or done. Clicking one takes you to that agent.
Click the menu bar icon to list your agents, grouped by source and workspace, with their current task titles. Click a local agent to focus its pane in herdr and bring your terminal to the front. Remote agents are monitor-only.
The terminal to bring forward defaults to Ghostty. To use another one:
defaults write io.github.cryks.shepherd TerminalBundleID <bundle id>The Display settings tab decides what each row shows. A row is a list of lines, and every line has a left and a right side written as a template. Every line also has a wrap count; only the left side wraps across that many lines.
| Syntax | Meaning |
|---|---|
{name} |
A variable. A name the language does not define renders as nothing. |
{a|b} |
The first alternative that has a value. |
[…] |
Drops out when every variable inside it is empty, separators and all. |
Anything herdr reports is addressable under herdr., spelled the way herdr spells it:
{herdr.agent.terminal_title_stripped} {herdr.agent.cwd}
{herdr.agent.agent} {herdr.agent.agent_status}
{herdr.workspace.label} {herdr.workspace.branch}
{herdr.workspace.worktree.repo_name} {herdr.tab.label}
Values your own hooks report with herdr pane report-metadata land in the same namespace: {herdr.agent.tokens.model}, {herdr.workspace.tokens.jj_status}, and the presentation fields {herdr.agent.title}, {herdr.agent.display_agent}, {herdr.agent.state_labels.working}.
The remaining variables are Shepherd's own:
| Variable | Value |
|---|---|
{title} |
Terminal title without the spinner and without Codex's [ ! ] Action Required | prefix |
{cwd_short} |
Working directory with your home as ~ |
{cwd_name} |
Last component of the working directory |
{excerpt} |
The agent's latest message, when excerpts are on |
{source} |
This Mac or the remote's name, blank while no remote is visible |
{agent_icon} |
The brand mark |
{status_emoji} |
🔴 blocked, 🟢 done, 🟡 working, ⚪ idle |
The rows ship as:
| Line | Left | Right |
|---|---|---|
| 1 | {title|herdr.agent.agent} |
{herdr.agent.agent_status} |
| 2 | {agent_icon|herdr.agent.agent}[ {herdr.workspace.branch}] |
|
| 3 | {excerpt} |
An override for one agent replaces that agent's whole line list. Notification titles and subtitles take one template each, and the body takes a list of them — a line that renders empty is left out. {agent_icon} renders as nothing there.
To keep the list on screen, choose "Pop Out as Window" from the menu.
Add SSH destinations in the Remote settings tab and agents on those hosts appear in the same list and icon. A destination is a Host from ~/.ssh/config or user@host, plus an optional herdr session name. Each destination has its own polling interval.
Connections use the standard macOS ssh, so ProxyJump, authentication methods, and host keys from your ~/.ssh/config apply as usual. Shepherd stores no passwords or private keys and never prompts for input. All a remote host needs is a running herdr; Shepherd does not install or restart anything there. You do not need to run herdr --remote locally.
- Launch at login
- Rewrite what each row and each notification shows, per agent if you like
- Show agent brand marks in color (monochrome by default)
- Blink the menu bar icon when attention is needed
- Send macOS notifications when agents need attention (off by default)
- Rename or hide this Mac's section title
- Language: System, English, or 日本語
- Check for updates automatically or manually
- Add and edit remote sources and their polling intervals
- Hide or pause individual remotes
- macOS 15 or later
- herdr running on this Mac and every remote you monitor
There is no Xcode project. SwiftPM and a Makefile assemble the app bundle:
make app # release build + assemble dist/Shepherd.app (ad-hoc signed)
make run # make app, then open itTo install, move dist/Shepherd.app into /Applications.
swift build
swift test
make icon # regenerate the .icns and the README PNG from Support/GenerateAppIcon.swiftShepherd polls herdr for state. The synchronization design lives in the header comments of Sources/Shepherd/Store.swift, and fleet aggregation in Sources/Shepherd/FleetStore.swift.
