惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
F
Fortinet All Blogs
Martin Fowler
Martin Fowler
M
MIT News - Artificial intelligence
G
Google Developers Blog
P
Proofpoint News Feed
Recent Announcements
Recent Announcements
MyScale Blog
MyScale Blog
D
DataBreaches.Net
Stack Overflow Blog
Stack Overflow Blog
月光博客
月光博客
爱范儿
爱范儿
罗磊的独立博客
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
博客园 - 叶小钗
Vercel News
Vercel News
酷 壳 – CoolShell
酷 壳 – CoolShell
B
Blog
C
Check Point Blog
美团技术团队
宝玉的分享
宝玉的分享
Microsoft Security Blog
Microsoft Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

Hacker News: Show HN

PurrrrrFocus: Pomodoro Timer App - App Store Workflow Engine — Multi-Step Orchestration for Bun RapidPhoto: Pro Photo Editor App - App Store GitHub - DheerG/swarms: Achieve extraordinary results with claude code across a variety of tasks SPICE simulation → oscilloscope → verification with Claude Code — Lucas Gerads Show HN: VCoding – A 5 MB native Windows IDE with no dynamic dependencies Show HN: LLMs don't hallucinate because they're bad at math, it's the format GitHub - Agent-FM/agentfm-core: AgentFM is a peer-to-peer network that turns everyday computers into a decentralized AI supercomputer. AgentFM lets you run massive AI workloads directly across a global mesh of idle CPUs and GPUs. Show HN: Tracking Top US Science Olympiad Alumni over Last 25 Years GitHub - Potarix/agent-hub: One place to talk to all your agents Show HN: Runtime security for AI agents(injection,tool abuse, data exfiltration) GitHub - dubeyKartikay/lazyspotify: Terminal Spotify client for macOS and Linux GitHub - the-banana-tool/king-louie: Easy to use GUI Personal AI Assistant. Win/Linux/Mac. Show HN I made my vacation rental bookable by AI agents–no Airbnb, 0% commission GitHub - basteez/jsf-autoreload: maven plugin to enable hot reload on jsf projects uvm32/hosts/host-gdbstub at main · ringtailsoftware/uvm32 GitHub - labsai/EDDI: Config-driven engine that turns JSON into production-grade AI agents. Multi-agent orchestration, 12+ LLM providers, MCP/A2A protocols, RAG, persistent memory, and enterprise compliance (EU AI Act, GDPR, HIPAA). Built on Quarkus. GitHub - glitchnsec/fortyone-oss: AI Executive Assistant Platform Quickstart | Alien GitHub - muxshed/shed: One stream in, or many. Every destination, simultaneously. No cloud middleman, no per-channel fees, no limits. GitHub - ocrbase-hq/ocrbase: 📄 PDF/IMG ->.MD/JSON Document OCR API for PaddleOCR and GLMOCR. Self-hostable. GitHub - impactjo/home-memory: MCP server that lets your AI assistant remember everything about your home. GitHub - Sets88/dbcls: DbCls is a powerful terminal database client that supports various databases GitHub - neptun2000/heor-agent-mcp GitHub - SeanFDZ/macmind: Single-layer transformer in HyperTalk for the classic Macintosh RollQuation: Math Puzzles - Apps on Google Play GitHub - dropbox/witchcraft Show HN: Agent-cache – Multi-tier LLM/tool/session caching for Valkey and Redis GitHub - opentalon/opentalon: OpenTalon is an open-source platform built from the ground up in Go as a robust alternative to OpenClaw LinkedIn™ 职位抓取工具 - Chrome 应用商店
GitHub - EronWright/gh-notifier: See GitHub Notifications...
eronwright · 2026-05-15 · via Hacker News: Show HN

A tiny macOS menu bar app that watches your GitHub notifications via the gh CLI.

image image

Download & install

Grab the latest zip from Releases, unzip, and drag GH Notifier.app to /Applications. Then:

open -a "GH Notifier"

macOS will prompt you to grant Notification permission. Accept.

Requirements (release build):

  • macOS 12 (Monterey) or later
  • gh authenticated against your GitHub account:
    brew install gh
    gh auth login

No Xcode required.

What it surfaces

It polls every 15 minutes (and on demand via "Refresh Now") and pulls your full unread notifications inbox, filtered to the reasons that actually matter day-to-day:

  • someone reviews or comments on a PR or issue you authored (reason: author)
  • you are @-mentioned (reason: mention)
  • someone requests a review from you (reason: review_requested)

The filtered set shows up two ways:

  1. Menu bar dropdown — a faithful mirror of your unread inbox at github.com/notifications, grouped by reason. Section names and leading icons match GitHub's notification filter sidebar:

    • 🎯 Assigned — an issue or PR is assigned to you (assign)
    • 👀 Review requested — someone wants you to review (review_requested)
    • Mentioned — you or your team were tagged (mention, team_mention)
    • 💬 Participating — activity on threads you authored or are subscribed to (author, comment, state_change)

    Each section caps at 10 rows; anything beyond shows up as → N more on GitHub which opens the matching filter on github.com/notifications. Within each section items are oldest-first. Rows are labeled owner/repo #1234 — Subject title (commits use @abc1234), prefixed with the section's emoji. Section headers carry a right-aligned hold ⌥ to mark done hint. The bell icon shows the total count.

  2. Notification Center banners — posted for items the app hasn't shown before, deduped by thread id (persisted in UserDefaults), and capped at 5 banners per poll so coming back from vacation doesn't blast you with 30 toasts. Anything past the cap silently appears in the dropdown.

Actions

Gesture What it does API call
Click a row or a banner Opens the PR/issue/commit on github.com, drops it from the dropdown, marks the thread read on GitHub. PATCH /notifications/threads/{id}
⌥-click a row in the dropdown Marks the thread done (archived to GitHub's "Done" filter). Does not open the browser. DELETE /notifications/threads/{id}
Refresh Now Manual poll. Same code path as the 15-minute timer. GET /notifications?all=false

The dropdown shows a hint row (Hold ⌥ to mark items as done) whenever you have unread items, and each row has a tooltip explaining the modifier on hover.

If GitHub or the app loses sync (e.g. the PATCH/DELETE fails on a flaky connection), the next poll will pull the unread set fresh and the thread reappears — same outcome as if you'd never clicked it.

Build from source

Additional requirements:

  • Xcode (for universal binary builds) or Xcode Command Line Tools (xcode-select --install) for host-arch builds

From this folder:

./build-app.sh --install
open -a "GH Notifier"

That:

  1. compiles the SwiftPM executable in release mode,
  2. wraps it in GH Notifier.app with the Info.plist in Resources/,
  3. codesigns the bundle,
  4. copies it to /Applications/.

If you'd rather build without installing:

./build-app.sh
open "./GH Notifier.app"

Start at login

Drag GH Notifier.app into System Settings → General → Login Items under "Open at Login".

Configuration

All knobs live in Sources/GHNotifier/AppConfig.swift:

Setting Default Notes
pollInterval 15 * 60 Seconds between polls.
bannerCapPerPoll 5 Max banners fired per poll. Items beyond the cap still show in the dropdown; they're just silent. Prevents the "you've been away" toast storm.
menuGroups [Assigned 🎯, Review requested 👀, Mentioned ✋, Participating 💬] Ordered dropdown sections, named and emoji-iconed to match GitHub's filter sidebar. Each carries its own reasons, cap (rows shown before overflow), and overflowQuery (passed to github.com/notifications?query=). Reasons not in any group are dropped entirely.
bundleIdentifier com.eronwright.gh-notifier Must match CFBundleIdentifier in Resources/Info.plist.

allowedReasons is derived from menuGroups automatically — no need to keep them in sync. Each group caps at 10 by default; bump in AppConfig.menuGroups if you want more rows before overflow kicks in.

After editing, rerun ./build-app.sh --install.

How it works

┌──────────────┐  every 15m   ┌─────────────────────┐
│  AppDelegate │ ───────────► │ NotificationFetcher │
│  (menu bar)  │ Refresh Now  │   gh api ...        │
└──────┬───────┘              └──────────┬──────────┘
       │                                 │ unread JSON
       │                                 ▼
       │                       filter reasons in
       │                        AppConfig.allowedReasons
       │                                 │
       ▼                                 ▼
┌──────────────┐              ┌─────────────────────┐
│   NSMenu     │              │ NotificationPoster  │
│ (dropdown)   │              │ UNUserNotification… │
└──────┬───────┘              └─────────────────────┘
       │ click             ⌥-click
       ▼                     ▼
PATCH notifications/threads/{id}   DELETE notifications/threads/{id}
        (mark read)                       (mark done / archive)
  • Each poll fetches the complete unread inbox (gh api notifications -f all=false). No since filter — the dropdown is meant to mirror github.com/notifications, not just show deltas.
  • A set of seen ids (capped at 2,000, persisted in UserDefaults under ghnotifier.seenIds.v1) prevents duplicate banners when an unread item gets touched again before you've cleared it.
  • Notification Center banners require the binary to live in an .app with a stable CFBundleIdentifier; that's what build-app.sh produces. There is no fallback channel — if macOS refuses to deliver, the dropdown header surfaces ⚠️ Notifications disabled… and clicking that row opens System Settings → Notifications.
  • "Mark read" uses PATCH /notifications/threads/{id}. "Mark done" (DELETE …) archives the thread to GitHub's "Done" filter.

Troubleshooting

Dropdown says "Notifications disabled". macOS won't deliver banners until you flip the switch in System Settings → Notifications → GH Notifier. Click the warning row in the dropdown to jump there. If GH Notifier doesn't appear in the list, run ./scripts/re-register-app.sh (or the VS Code task app: re-register with LaunchServices) — that nudges LaunchServices to re-discover the bundle so the next launch can register for notifications.

Menu bar says "Error: ... gh exited with code 4". Run gh auth status; you probably need to re-authenticate.

"Could not find the gh CLI". Install it (brew install gh) — the app probes /opt/homebrew/bin, /usr/local/bin, /usr/bin, and ~/.local/bin before falling back to command -v gh via zsh.

I want to test it but I don't have any open notifications. Drop AppConfig.pollInterval to 60 (one minute), comment on one of your own PRs from another account or browser session, then hit "Refresh Now". Set the interval back to 15 * 60 when you're done.

Fresh start. ./scripts/re-register-app.sh re-registers the bundle. The VS Code task app: reset state wipes seenIds/lastSync so the next launch behaves like a first run (it'll banner everything currently unread).

Source layout

GH Notifications/
├── Package.swift
├── build-app.sh
├── README.md
├── .vscode/
│   ├── launch.json
│   └── tasks.json
├── Resources/
│   ├── AppIcon.icns
│   └── Info.plist
├── scripts/
│   ├── make-icon.sh
│   ├── re-register-app.sh
│   └── release.sh
└── Sources/
    └── GHNotifier/
        ├── main.swift
        ├── AppConfig.swift
        ├── AppDelegate.swift
        ├── GitHubNotification.swift
        ├── NotificationFetcher.swift
        └── NotificationPoster.swift