/ˈɡɪt.bɛl/ (git-bell) noun
- a small desktop companion that rings when something happens in your repos.
Native desktop notifications for GitHub activity and coding agents, from your system tray.
GitBell is a lightweight desktop app that lives in your system tray and pops a native notification the moment someone pushes, opens a pull request, reviews, merges or releases in the repositories and organizations you care about.
No server, no webhooks, no browser tab left open. Your machine asks GitHub directly with your own token, once a minute, and the operating system shows the toast. That's it.
![]() |
![]() |
- Native toasts on Linux (freedesktop) and Windows (WinRT). Clicking a toast on Linux opens the commit, PR or issue on GitHub.
- Tray-first. Close the window and GitBell keeps watching from the tray. Left click reopens it, right click for the menu.
- Activity first. The window opens on what happened in your repos, with who you're connected as. Settings live one tab over, and every event category has its toggle and sound on the same row.
- Watch what you want. A single repo (
owner/repo), a whole organization (org:name) or everything you watch and follow (@me). - Pick your events. Pushes, pull requests, reviews, issues, comments, branches and tags, releases, stars and forks. Each one is a toggle.
- Sounds. Two bundled chimes, a different one per event category, volume control, or bring your own audio file.
- A mascot that rings its bell. The tray icon plays a short animation when something new arrives. Because why not.
gitbell notifyfrom any script. Agents, CI, cron: if it can run a command, it can ring your bell. See below.- Knows when an agent did it. Commits and PRs from Claude Code, Copilot, Codex, Cursor, OpenCode, Aider, Devin or Jules land in their own category, the toast names the agent, and the click opens the agent's session when the commit carried a link. Honest limits below.
- Polite polling. Honors GitHub's
X-Poll-Interval, uses ETags so unchanged polls cost zero rate limit, and backs off automatically when throttled. - No spam on first run. Adding a busy organization remembers where it is instead of dumping the last 90 days on you.
- Starts with your session, minimized to the tray, if you want it to.
- English and Spanish. Follows your system language, or pick one in settings.
- Glass. The window is translucent and asks the compositor to blur what's
behind it: KDE Plasma (both the KDE and the new
ext_background_effectprotocols), Windows 11 acrylic, macOS vibrancy. A slider in settings sets the opacity; 100% is opaque. GNOME shows the tint without blur. - Three-step first run. Token, what to watch (your busiest repos suggested), and a real notification from your own repo. Skippable, replayable from settings.
- Updates itself. Checks for a new release after start and every few hours, shows a banner, downloads a signed build and restarts. Signature is verified before anything is installed.
- Tiny. Built with Tauri v2: a few megabytes, not a bundled browser.
┌──────────┐ every 60 s, with ETag ┌────────────────────┐
│ GitBell │ ────────────────────────▶ │ api.github.com │
│ (tray) │ ◀──────────────────────── │ /repos/:r/events │
└────┬─────┘ 200 new events / 304 │ /orgs/:o/events │
│ │ /users/:u/received │
│ diff against last seen id └────────────────────┘
▼
┌──────────┐
│ OS toast │ + sound + tray animation
└──────────┘
GitBell reads the public GitHub Events API.
It keeps the id of the newest event it has seen per target and only notifies
for events newer than that. Your token never leaves your machine except to
call api.github.com.
- ETag polling. Every request carries
If-None-Match; a304costs no rate limit. GitHub'sX-Poll-Intervaland rate-limit headers are honored, and a hung request times out after 20 s instead of freezing the loop. - Keyring. The token lives in the OS keyring (Secret Service / KWallet, Credential Manager, Keychain), never in the settings file.
- Agent detection. Commit trailers, bot logins, branch prefixes and PR body markers identify Claude Code, Copilot, Codex and others. It only works when the tool signs its work; see Agents for the limits.
Grab the latest installer from the Releases page:
| Platform | Package |
|---|---|
| Linux | .deb, .rpm, .AppImage |
| Windows | .msi, .exe |
| macOS | coming soon (the CI matrix entry is one uncomment away) |
sudo apt install ./GitBell_*_amd64.deb # Debian, Ubuntu
sudo dnf install ./GitBell-*.x86_64.rpm # Fedora
chmod +x GitBell_*_amd64.AppImage && ./GitBell_*_amd64.AppImageFrom 0.3.0 on GitBell updates itself (signed, verified before install). 0.2.1 and earlier have no updater: install 0.3.0 by hand once.
GitBell needs a GitHub personal access token so it can see private repos and organization activity.
- GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic)
- Scopes:
repo(private repositories) andread:org(organization events) - Paste it into the first-run flow, or later in Settings → Account. GitBell can also open the token page for you with the scopes pre-checked.
The token goes straight into your OS keyring (KWallet / GNOME Keyring on
Linux, Credential Manager on Windows). Settings live in the app data
directory (~/.local/share/dev.ejos.gitbell/ on Linux,
%APPDATA%\dev.ejos.gitbell\ on Windows) and never contain the token.
| Syntax | Watches |
|---|---|
owner/repo |
one repository |
org:name |
every repository in an organization you belong to |
@me |
everything you watch or follow (your received-events feed). Never includes your own activity: to get notified about your own pushes, add the repo itself |
GitHub has no "an agent did this" flag. GitBell reads the fingerprints the
tools leave by default: Co-Authored-By trailers, session-link trailers
(Claude-Session:, Agent-Logs-Url:), bot logins (copilot-swe-agent[bot],
claude[bot]), branch prefixes (claude/, copilot/, cursor/) and PR
body markers. A hit moves the event to the Agents category with its own
toggle and sound, the toast reads "Claude Code (@you) pushed to …" with a robot prefix, and
the link prefers the agent's session. Your own agents count even with
"ignore my own activity" on, because cloud sessions push as you.
| Tool | Detected out of the box |
|---|---|
| Claude Code (CLI, desktop, web, GitHub Action) | yes |
| GitHub Copilot coding agent | yes, always |
| Codex (CLI, app, cloud) | yes |
| Cursor agent, OpenCode, Aider, Devin, Jules | yes |
| Gemini CLI, Cline, Roo Code, Kilo Code | no: they don't sign commits |
The catch: detection only works when the tool signs. If you turn attribution off (every tool lets you), or use a tool that doesn't sign, the commit is indistinguishable from yours, for GitBell and for anyone. For those cases use the hook below: the agent tells GitBell directly, no git forensics involved. Models (DeepSeek, GPT, Claude) are not tools; the mark comes from whatever wraps them.
GitBell doubles as a local notification endpoint. While it's running in the tray, any script can make it ring:
gitbell notify "Build finished" --body "all 212 tests green" --url https://ci.example.com/run/42The second process hands its arguments to the running instance and exits;
you get the toast, the bell animation, the sound and a row in recent
activity. If GitBell isn't running, the command starts it in the tray and
shows the toast anyway. Flags: --body, --url (https only).
This is what makes GitBell useful with coding agents. Claude Code, for
example, can call it from a hook
every time it finishes a turn, so you know when a task is done even if
nothing was pushed yet. In ~/.claude/settings.json:
{
"hooks": {
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "gitbell notify \"Claude Code finished\" --body \"$(jq -r .cwd)\""
}
]
}
]
}
}To be told about every commit Claude Code makes, whether or not it signs
them, hook the Bash tool and look for git commit:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "in=$(cat); echo \"$in\" | jq -e '.tool_input.command | test(\"git commit\")' >/dev/null && gitbell notify \"Claude Code committed\" --body \"$(echo \"$in\" | jq -r .cwd)\""
}
]
}
]
}
}Any tool that can run a shell command works the same way: CI scripts, long test runs, deploys, cron jobs.
src/ TypeScript, runs in the webview
├── core/ pure logic, no Tauri imports
│ ├── github.ts Events API client: ETag, X-Poll-Interval, rate limit
│ ├── poller.ts the loop, dedupe by last seen event id
│ ├── format.ts GitHub event → toast title/body/url
│ ├── agents.ts coding-agent fingerprints (trailers, bots, branches)
│ ├── i18n.ts typed dictionary, es/en
│ └── types.ts shared shapes and defaults
├── platform/ thin wrappers over Tauri commands and plugins
│ ├── secrets.ts token in the OS keyring
│ ├── settings.ts JSON store for settings and state
│ ├── notify.ts toasts and tray animation
│ └── sounds.ts audio playback
├── ui/ activity + settings window, onboarding, no framework
│ └── preview.ts boots the UI in a plain browser with fake data
└── main.ts wires the three layers together
src-tauri/src/ Rust, the trusted side
├── lib.rs builder, plugins, window lifecycle
├── cli.rs `gitbell notify` parsing, forwarded by single-instance
├── i18n.rs tray menu and toast button strings
├── tray.rs tray icon, menu, bell animation, unread badge
├── glass.rs asks the compositor to blur behind the window
├── notify.rs freedesktop toasts with click-to-open
├── secrets.rs keyring get/set/delete
└── sounds.rs validated import of user audio files
Rust stays thin on purpose. Anything that doesn't need OS access lives in
src/core, which has no Tauri imports and is trivially unit-testable.
The webview is treated as untrusted and Rust is the authority. Token in the
OS keyring, least-privilege capabilities, opener scoped to github.com,
asset protocol scoped to the app's own sounds folder, strict CSP, and
cargo audit plus Dependabot in CI. Details in SECURITY.md.
Prerequisites: Rust stable, Node 22, pnpm, and the Tauri system dependencies for your OS.
git clone https://github.com/eJosR-Coding/gitbell.git
cd gitbell
pnpm install
pnpm tauri dev # dev build with hot reload
pnpm tauri build # installers land in src-tauri/target/release/bundle/On Fedora the system libraries are:
sudo dnf install webkit2gtk4.1-devel libappindicator-gtk3-devel librsvg2-devel dbus-develUI preview without Tauri: run pnpm dev and open http://localhost:1420
in a browser. #ob=1, #ob=1c, #ob=2, #ob=3 render each onboarding
step with fake data; #view=settings the settings view; #notoken the
asleep state; no hash the activity view with sample notices.
Tests:
pnpm test # TypeScript core (Vitest)
cargo test --manifest-path src-tauri/Cargo.toml # Rust- Windows installers aren't code-signed yet. SmartScreen shows "Windows protected your PC"; choose More info → Run anyway. Signing is on the roadmap.
- Blur behind the window needs a compositor that offers it. KDE Plasma, Windows 11 and macOS do. GNOME shows the tint only.
- Events arrive with GitHub's own delay (30 s to a few minutes) and GitHub asks not to poll faster than once a minute. Instant delivery via webhooks is on the roadmap.
- Agent detection needs the tool to sign its commits. Tools that don't
(Gemini CLI, Cline and friends) or users who turned attribution off are
invisible; use
gitbell notifyfrom a hook for those.
Pushing a vX.Y.Z tag builds the installers and drafts a signed release.
The full procedure, secrets and update-manifest details are in
RELEASING.md.
- Spanish and English UI
-
gitbell notifyfor scripts and agents - First-run onboarding, activity-first window, glass
- Unread dot on the tray icon
- Agent detection
- Signed auto-updates
- Public repo, AUR and winget packages, then COPR and apt
- Instant mode: webhooks through a tiny relay instead of polling
- macOS builds and notarization
- Do-not-disturb schedule
- Per-branch filters (
mainyes,feature/*no)
Issues and pull requests are welcome. Read CONTRIBUTING.md for the project layout and a few ground rules.
If GitBell saves you from refreshing GitHub one more time, a star on the repo goes a long way. And if it saved you more than that:
GitBell is released under the MIT License.
Developed by Joseph Rodriguez · @eJosR-Coding



