Daemon that monitors GitHub PRs and exposes state over D-Bus
Project description
ForgeWatch
Monitor your GitHub pull requests. Get notified instantly.
An async Python daemon that watches GitHub for PRs assigned to you, sends desktop notifications, and shows live status in your system tray.
Screenshots
|
Desktop notifications Individual notifications with author avatars and clickable links when new PRs arrive. |
System tray indicator Live PR count in your panel with colour-coded status icons. |
|
PR list popup Click the tray icon to see all your PRs at a glance. Click any PR to open it in your browser. |
Setup wizard Interactive CLI walks you through configuration and systemd service setup. |
Features
- Live PR monitoring -- polls the GitHub Search API for PRs assigned to you or requesting your review
- Desktop notifications -- individual notifications for small batches with author avatars and clickable links; summary for larger batches
- System tray indicator -- optional panel icon with live PR count, colour-coded status, and a popup window listing all PRs
- D-Bus interface -- query current PR state, trigger manual refresh, subscribe to change signals
- GitHub Enterprise support -- configurable API base URL for GHE instances
- Systemd integration -- runs as a user service with security hardening and
systemctl reloadsupport - Resilient -- exponential backoff with configurable retries, rate limit handling, graceful shutdown (SIGTERM, SIGHUP for config reload)
- Runtime configurable -- log level, notification behaviour, D-Bus toggle, and more via config reload without restarting
Installation
From PyPI
# Using pip
pip install forgewatch
# Using pipx (recommended for CLI tools)
pipx install forgewatch
# Using uv
uv tool install forgewatch
From source
git clone https://github.com/dvoraj75/forgewatch.git
cd forgewatch
uv sync # install runtime + dev dependencies
System packages (for the indicator)
The system tray indicator requires GTK3 and AppIndicator3:
# Ubuntu / Debian
sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-3.0 \
gir1.2-appindicator3-0.1 libcairo2-dev libgirepository1.0-dev
# Fedora
sudo dnf install python3-gobject gtk3 libappindicator-gtk3
The core daemon works without these -- the indicator is fully optional.
Quick start
1. Configure
The fastest way to get started is the setup wizard:
forgewatch setup
Or configure manually:
mkdir -p ~/.config/forgewatch
cp config.example.toml ~/.config/forgewatch/config.toml
$EDITOR ~/.config/forgewatch/config.toml
Minimal config:
github_token = "ghp_your_personal_access_token"
github_username = "your-github-username"
poll_interval = 300 # seconds (minimum 30)
repos = [] # empty = all repos, or ["owner/repo1", "owner/repo2"]
The token can also be provided via the GITHUB_TOKEN environment variable.
See docs/configuration.md for the full reference.
2. Run
forgewatch # start the daemon
forgewatch -v # verbose (DEBUG) logging
forgewatch -c /path/to/config.toml # custom config path
3. Manage as a systemd service
forgewatch setup --service-only # install + enable + start services
forgewatch service status # check service status
forgewatch service restart # restart after config changes
Or manually:
cp systemd/forgewatch.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now forgewatch
journalctl --user -u forgewatch -f # follow logs
4. System tray indicator (optional)
forgewatch-indicator # start (daemon must be running)
forgewatch-indicator -v # verbose logging
As a systemd service:
cp systemd/forgewatch-indicator.service ~/.config/systemd/user/
systemctl --user enable --now forgewatch-indicator
See docs/systemd.md for the full service management guide.
CLI commands reference
forgewatch setup # interactive setup wizard
forgewatch setup --config-only # only create config file
forgewatch setup --service-only # only install + start services
forgewatch service status # show service status
forgewatch service start|stop|restart
forgewatch service install # install systemd unit files
forgewatch service enable|disable # toggle autostart
forgewatch uninstall # remove services + optionally config
Architecture
┌──────────────┐
│ GitHub API │
└──────┬───────┘
│
┌────────▼────────┐
│ Poller │
│ (aiohttp + │
│ asyncio) │
└────────┬────────┘
│
┌────────▼────────┐
│ State Store │
│ (in-memory) │
└───┬─────────┬───┘
│ │
┌────────▼──┐ ┌───▼──────────┐
│ Notifier │ │ D-Bus │
│ (notify- │ │ Interface │
│ send) │ └───┬──────────┘
└───────────┘ │
D-Bus session bus
│
┌───────▼────────┐
│ Indicator │
│ (GTK3 tray + │
│ popup window)│
└────────────────┘
The poller queries the GitHub Search API on a configurable interval. The state store computes diffs (new / updated / closed PRs). The notifier sends desktop notifications for new PRs. The D-Bus interface lets the indicator (and other tools) query current state. The indicator is a separate process that shows a live tray icon and clickable PR list.
For the full design, see docs/architecture.md.
Development
uv sync # install all deps
uv run pytest # run tests (parallel, with coverage)
uv run ruff check . # lint (all rules enabled)
uv run ruff format . # format (black-compatible)
uv run mypy forgewatch # type check (strict mode)
See docs/development.md for coding conventions, testing patterns, CI pipeline details, and project structure.
Documentation
| Document | Description |
|---|---|
| Architecture | System design, component interactions, design decisions |
| Configuration | Full configuration reference with examples |
| Development | Developer guide: tooling, conventions, CI pipelines, testing |
| Systemd | Service setup, management, and troubleshooting |
Module API references
| Module | Description |
|---|---|
| CLI | Management subcommands (setup, service, uninstall) |
| Config | Configuration loading and validation |
| Poller | GitHub API client, pagination, rate limiting |
| Store | In-memory state store with diff computation |
| D-Bus Service | D-Bus interface methods, signals, serialization |
| Notifier | Desktop notifications, avatars, click-to-open |
| URL Opener | XDG portal + xdg-open URL opener |
| Daemon | Main daemon loop and signal handling |
| Indicator | System tray icon, popup window, D-Bus client |
Dependencies
Runtime:
| Package | Purpose |
|---|---|
aiohttp |
Async HTTP client for GitHub API |
dbus-next |
Async D-Bus client/server |
gbulb |
GLib/asyncio event loop integration (for the system tray indicator) |
System tray indicator (optional, requires system packages):
| Package | Purpose |
|---|---|
| GTK3 + AppIndicator3 | System packages (see Installation) |
Dev-only: pytest, pytest-asyncio, pytest-xdist, pytest-cov, aioresponses, ruff, mypy, pre-commit, pip-audit.
Contributing
Contributions are welcome! See CONTRIBUTING.md for development setup, coding conventions, testing guidelines, and the PR process.
License
MIT -- see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file forgewatch-1.4.1.tar.gz.
File metadata
- Download URL: forgewatch-1.4.1.tar.gz
- Upload date:
- Size: 42.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74d95a043809f7bc0f7d4c564f9ad99968a5c0b798dbaf9f33f59cdace0bdf8a
|
|
| MD5 |
13b1ef3077fd108c3189dc1d3d10dc03
|
|
| BLAKE2b-256 |
9ae240e7ec4d4b35d6402eb61ef7d2d4ce4acadce6275eb404095c7f76d5ab18
|
Provenance
The following attestation bundles were made for forgewatch-1.4.1.tar.gz:
Publisher:
publish.yml on dvoraj75/forgewatch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forgewatch-1.4.1.tar.gz -
Subject digest:
74d95a043809f7bc0f7d4c564f9ad99968a5c0b798dbaf9f33f59cdace0bdf8a - Sigstore transparency entry: 1092015756
- Sigstore integration time:
-
Permalink:
dvoraj75/forgewatch@13b3e45357fa4bfa7148908f6058c22dc7578806 -
Branch / Tag:
refs/tags/v1.4.1 - Owner: https://github.com/dvoraj75
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13b3e45357fa4bfa7148908f6058c22dc7578806 -
Trigger Event:
release
-
Statement type:
File details
Details for the file forgewatch-1.4.1-py3-none-any.whl.
File metadata
- Download URL: forgewatch-1.4.1-py3-none-any.whl
- Upload date:
- Size: 59.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bcb27ce86bb76c83a404bc67b0b3417381d427a760f8a565a5d6773edfe244de
|
|
| MD5 |
df530976eab7edea6f2217969cf2fde4
|
|
| BLAKE2b-256 |
71e8608c7b294fc493dea32396a301c07490a3474b4c2896f6b7d0f0444c132b
|
Provenance
The following attestation bundles were made for forgewatch-1.4.1-py3-none-any.whl:
Publisher:
publish.yml on dvoraj75/forgewatch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forgewatch-1.4.1-py3-none-any.whl -
Subject digest:
bcb27ce86bb76c83a404bc67b0b3417381d427a760f8a565a5d6773edfe244de - Sigstore transparency entry: 1092015767
- Sigstore integration time:
-
Permalink:
dvoraj75/forgewatch@13b3e45357fa4bfa7148908f6058c22dc7578806 -
Branch / Tag:
refs/tags/v1.4.1 - Owner: https://github.com/dvoraj75
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13b3e45357fa4bfa7148908f6058c22dc7578806 -
Trigger Event:
release
-
Statement type: