Coding agents open pull requests faster than any human can keep up with β across all of your repositories at once, and in a study of 33,596 agent-authored pull requests, 61% carried no recorded human review at all (the numbers). Review tools were built for a handful of pull requests a week; Shepherd is built for the flood. It herds every pull request from every repository into one place: a fast, local-first, keyboard-driven inbox where you triage, review and merge without opening a browser tab. It is open source, and docs/PRIVACY.md lists everything it sends and where.
| Review | |
|---|---|
| π Real diffs, in the app Side-by-side and inline Monaco diffs β the VS Code engine β with syntax highlighting, viewed-state tracking, and files ordered by what deserves attention first. |
π¬ Full GitHub review parity Inline comments, multi-comment pending reviews, approve / request changes / comment, thread replies and resolves, checks, and merge / squash / rebase. |
| β¨οΈ Focus session β§ββ walks you through every pull request waiting on you, one at a time, over a queue frozen at start. Twenty agent PRs, twenty keystrokes. |
π Saved replies & templates Reusable snippets in every comment field, plus a per-repo review checklist that prefills a new, empty review β and never touches one you started. |
| π§ Open in your editor Link a repository to its local checkout and jump from a file, a finding or a CI failure straight to the line β in VS Code, IntelliJ IDEA, Cursor, the system default or a command of your own. |
π€ Nothing out of sight A merge on its way, a queued approval or a change GitHub refused shows on the row and in the review β Mergingβ¦, Merge queued, Not sent β with Retry right there. Merged appears only once GitHub confirms it. |
| Triage | |
| β
Bulk triage Tick the green ones, then approve or merge them behind one confirmation that lists what it will skip β red CI, conflicts, drafts, yours β and why. |
π§Ύ Claims beside the evidence What the description says it did β tests added, nothing breaking, fixes #142 β next to what the diff and CI show. Look closer lets the on-device model point at the lines behind a claim; Shepherd finds every excerpt in the diff itself. |
| π·οΈ Where it came from Claude Code, Copilot, Codex, Devin, Cursor or a colleague β detected on every row and usable as a lens next to repository and review state. The rail keeps its places whichever view you pick, with your watched repositories always on top. |
π₯ Watch a repository Every open pull request in a repository you watch reaches the inbox, even the ones nobody asked you to review. |
| βοΈ Morning digest An opt-in daily summary built from the local database alone: new requests, green PRs one keystroke from done, your red CI, reviews still parked. |
π Menu-bar quick inbox The number of pull requests waiting on your review, and the top ones one click away β off the same local data, so it costs no extra API call. |
| π The fleet Every agent Shepherd has seen, and what became of its pull requests: merged, closed, reverted, rounds of changes and how often its first push was green β across every repository, then one repository at a time underneath, plus at most three sentences the counts below them support. Counts, never a score: no rank, no ordinal, no sortable rate, no traffic-light colour, and no page for a person. |
|
| π Semantic βK search Type what a pull request was about β βflaky login testβ finds βRetry the auth suiteβ β over titles, labels, branches, descriptions and the diffs you have opened. On-device embeddings, stored in your own SQLite, never sent to an AI endpoint; owner/repo#128 still wins outright. |
|
| Automate | |
| π οΈ Delegate to a local agent Hand a PR or a single finding back to Claude Code in an isolated worktree with a budget cap and a turn cap you can lift. Optionally started for you when CI turns red. |
π¦ Auto-merge rules Opt in, and an agent PR that is green, approved and mergeable gets its merge queued for you β narrowable by repo and label, never approving anything, every decision in a local audit log. |
| π» Your own clones Pick a folder and Shepherd reads the repository from its origin, links the checkout and watches every pull request in it β one step. Then Start an agentβ¦ hands a task you type to Claude Code on a fresh agent/β¦ branch off the default branch, with the same caps β as many tasks side by side in one repository as you like, each in its own worktree. Shepherd itself pushes nothing. |
|
| π Webhooks, deep links, CLI Signed outbound events into n8n, shepherd:// links, and a shepherd binary that drives the app from a terminal, Raycast or Shortcuts. |
|
| π£οΈ Shortcuts & Siri App Intents with typed parameters: open a pull request, show a filtered inbox, sync, start a review session, or just ask how many need you. Notifications name their pull request, so Siri can open or summarise the one it is about. No write actions β nothing can approve or merge from a phrase. |
π¦ Spotlight Your inbox in βSpace: title, owner/repo#123 Β· author Β· CI state, labels and agent as keywords. Titles and metadata only β never a description or a diff β and one toggle removes them all. |
| Intelligence | |
| β¨ Drafts, not submissions Draft a review summary or an inline comment from the diff in front of you. It lands as editable text; nothing is ever submitted for you. |
π§ On-device first Heuristics always, Apple Foundation Models where available, your own key optional β Claude through Apple's own model interface, any OpenAI-compatible endpoint, Konduit (EU) or Ollama. |
| π Translate in place A description or comment in a language you don't read gets an on-device translation below the original β never instead of it, never through a cloud endpoint. |
βοΈ Writing Tools everywhere Apple's proofread, rewrite and tone tools in every field you write review text in β summary, inline comment, thread reply, saved reply. |
| πΌοΈ Screenshots, read on this Mac Switch it on, and a click lets the on-device model describe up to two screenshots from a pull request's description β what changed visually, next to the text summary. Off by default; the images come from GitHub's own upload host and never reach a cloud model. |
|
| Sync & privacy | |
| π Sync you host Every setting and every secret in one AES-256-GCM object in an S3 bucket you own. A new Mac plus the passphrase is a set-up Mac. No account, no server. |
ποΈ Local-first by construction SQLite is the source of truth, writes go through a persisted outbox, secrets live in the Keychain, and anonymous usage counts are off until you say yes. |
| π©πͺ Auf Deutsch Set your Mac to German and the whole app is German β the diff viewer and GitHub's error messages included; no language setting, it follows the system. GitHub's own review vocabulary stays English inside the German sentences (pull request, review, approve, request changes, merge, draft, CI), so what you read matches what the next window says. |
|
The long form β every feature, with the decisions behind it β is in docs/FEATURES.md.
The inbox. One row per pull request across every repository, with its CI state, review state and diff size on the row itself β grouped by repository, review state or author (person, bot, or named coding agent), whichever lens you reach for. The right pane is the pull request without leaving the list: its CI, the files worth opening first, and a summary written by the on-device model.
The review screen. A real Monaco diff β the VS Code engine β side by side or inline, with the unchanged stretches folded away and changes highlighted down to the word. Comment, approve, request changes and merge without opening a browser tab.
Watched repositories. The inbox is built from @me searches, which is right until a repository
matters to you without anyone naming you on it. Add it in Settings and its open pull requests
arrive too β under Watched until you are involved in one.
- Local SQLite is the source of truth. GitHub is a sync target, not a backend (ADR 0006).
- Writes go through an outbox. Approve offline; it lands when the network does, with retries and a staleness check.
- Secrets live in the Keychain β never in
UserDefaults, never in the database. - Anonymous telemetry, off in one click. Thirteen allow-listed events, every property an enum or a bucket, and never a repository, a branch or a line of code β docs/PRIVACY.md says exactly what is sent and ADR 0036 says why. The complete list of hosts Shepherd may contact is in CONTRIBUTING.md; adding one requires a new ADR.
- Sync is end-to-end encrypted and self-hosted. Your bucket, your passphrase, ciphertext on the wire (ADR 0014).
- AI runs only when you ask. Off by default, on-device where possible, and the unattended morning digest may never call an endpoint at all. βK search is the other side of the same rule: it runs on every keystroke, so it is on-device only and has no code path to a provider (ADR 0019).
- Crash reports stay on disk. Opt-in MetricKit JSON in Application Support, no uploader in the code path (ADR 0017).
| Keys | Action | Keys | Action | |
|---|---|---|---|---|
j k |
Move down / up the list | r a |
Approve | |
β |
Open the selected pull request | r x |
Request changes | |
x |
Tick a row for bulk triage | r c |
Comment | |
g a g r g s |
Group by agent / repo / review state | m |
Merge⦠| |
βK |
Command palette & pull-request search | r f Β· β§ββ |
Start a focus review session | |
βR |
Sync now | d n esc |
In a session: done & next Β· next Β· end | |
ββ |
Submit the pending review |
Two-keystroke sequences forget an unfinished prefix after 1.5 s, so a stray r never swallows the
next key.
shepherd open schnaq/review#128 # β¦/review/128 and a github.com PR URL work too
shepherd inbox needs-my-review # mine Β· involved Β· approved-by-me Β· watched
shepherd inbox --filter agent:claude-code # humans Β· bots Β· agent:<id> Β· repo:<owner>/<name>
shepherd fleet # every agent; add an id for one agent's page
shepherd sync # sweep every repository now
shepherd settings automation # jump to a Settings tabEvery command is a URL the app parses, so anything that can open one β Raycast, Shortcuts, a
bookmark, open(1), an n8n Execute Command node β can drive Shepherd
(ADR 0013):
| URL | Effect |
|---|---|
shepherd://pr/<owner>/<repo>/<number> |
Open that pull request's review screen |
shepherd://inbox Β· shepherd://inbox?filter=<token> |
Inbox, optionally filtered |
shepherd://fleet Β· shepherd://fleet/<agent-id> |
The fleet, optionally on one agent's page |
shepherd://sync |
Run one sweep now |
shepherd://settings Β· shepherd://settings/<tab> |
Open Settings, optionally on a tab |
Outbound webhooks (Settings β Automation) POST a versioned JSON event to the one URL you type β
review.submitted, pr.merged, delegation.finished, inbox.new_review_request β after the
action really reached GitHub, plus pr.auto_merge_queued the moment a rule decides something
unattended. With a signing secret each request carries
X-Shepherd-Signature: sha256=<hex HMAC of the raw body>, deliberately the same shape as GitHub's
X-Hub-Signature-256, so an n8n Crypto node you already have works unchanged. Schema, guarantees
and a three-minute n8n recipe: docs/WEBHOOKS.md.
AI endpoints are yours to pick: Anthropic, or any OpenAI-compatible base URL with one-click presets for Konduit (EU) and a local Ollama, model discovery and a connection test.
brew install --cask schnaq/tap/shepherdOr download the DMG from the latest release.
Every build is notarized by Apple and keeps itself current through Sparkle 2; the cask sets
auto_updates, so Homebrew leaves the installed copy to it. To build from source instead:
brew install xcodegen
git clone https://github.com/schnaq/shepherd.git && cd shepherd
cd web/diff-viewer && npm ci && npm run build && cd ../.. # bundle the Monaco diff viewer
xcodegen generate
open Shepherd.xcodeprojNeeds macOS 27 (Golden Gate) or later on Apple Silicon, Xcode 27+ and Node 22+. Sign in with GitHub via
device flow, or paste a fine-grained personal access token. A source build is unsigned and has its
updater switched off, which Settings β Account states in one line. The ShepherdKit package is
platform-independent β cd Packages/ShepherdKit && swift test needs no Xcode. The shepherd CLI is
its own scheme:
xcodebuild -project Shepherd.xcodeproj -scheme ShepherdCLI -configuration Release \
-derivedDataPath .build/cli build
cp .build/cli/Build/Products/Release/shepherd /usr/local/bin/Under active development, and in daily use by the people who build it. Releases ship signed and notarized, update themselves through Sparkle and install through Homebrew β see the latest release. It is young software, so expect rough edges and tell us about them. What is done, next and deliberately out of scope: docs/ROADMAP.md.
The app target owns all UI and every Apple-only framework; everything else lives in ShepherdKit,
an SPM package that imports no AppKit, SwiftUI or WebKit and is tested headlessly on Linux in CI.
The shepherd CLI links only the domain module, so it has no client, no database and no Keychain
access β it can reach the app solely through shepherd://.
flowchart LR
CLI["shepherd CLI"] -->|"shepherd://"| App
App["Shepherd.app<br/>SwiftUI Β· Monaco in WKWebView"] --> Sync["ShepherdSync"]
App --> DB["ShepherdPersistence<br/>SQLite Β· outbox"]
Sync --> GH["GitHubKit<br/>GraphQL + REST"]
Sync --> DB
GH --> Core["ShepherdCore<br/>models Β· heuristics Β· agent detection"]
DB --> Core
GH --> GitHub[("github.com")]
App -.->|"a bucket you own"| S3[("S3-compatible storage")]
App -.->|"only when you ask"| AI[("AI endpoint you chose")]
Details in docs/ARCHITECTURE.md; every significant decision has an ADR in docs/adr, grounded in the research reports in docs/research.
CONTRIBUTING.md has the setup, the module rules and the hard privacy lines (allow-listed anonymous telemetry, Keychain-only secrets, local-first), and docs/PRIVACY.md is the plain-language version for people who are not reading the source. Third-party licences that ship inside the app are in NOTICES.md.
MIT β π


