Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Github Notifications Laravel Package

graham-campbell/github-notifications

A PHP client for GitHub's notifications API, letting you list, filter, mark as read, and manage repository notifications from your applications. Part of Graham Campbell's GitHub package ecosystem.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a Laravel wrapper around the GitHub Notifications API whose purpose is to programmatically shed notification noise — bulk-marking threads as read/done, pruning stale threads, and ignoring the repositories that generate the most chatter. Day-to-day it is a scheduled maintenance tool, not a request-time dependency.

Minimum path from zero to value:

  1. Install and discover.

    composer require graham-campbell/github-notifications
    

    Laravel's package discovery registers GrahamCampbell\GitHubNotifications\GitHubNotificationsServiceProvider. On older skeletons add it to config/app.php manually.

  2. Publish the config.

    php artisan vendor:publish --provider="GrahamCampbell\GitHubNotifications\GitHubNotificationsServiceProvider"
    

    This drops config/github-notifications.php. Read it end-to-end before touching anything else — this file is the real API of the package, and the rules you care about live there.

  3. Provide credentials. Create a classic PAT with at least notifications scope (repo too if you intend to resolve subject URLs or act on private repo threads), then set it in .env:

    GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
    GITHUB_USERNAME=your-handle
    

    The package typically consumes the shared graham-campbell/github connection config, so if you already have GITHUB_TOKEN wired for other Graham Campbell GitHub packages, you are usually done.

  4. Confirm what commands exist. Don't guess command signatures — enumerate them:

    php artisan list github
    

    That prints the registered commands and their options. Run the primary command with --help before the first real execution.

  5. First use case: a one-shot inbox purge. The highest-value first run is marking everything older than N days as read, and optionally unsubscribing. Do it once interactively so you can see the output, then move it to the scheduler. Run it in a dry-run/verbose mode if the command exposes one, and cross-check the GitHub notifications page in a browser immediately after — the API's notion of "read" and the UI's unread badge should agree.

Implementation Patterns

Scheduled pruning (the canonical pattern). The package earns its keep as a nightly job. In routes/console.php:

Schedule::command('github-notifications:...')->dailyAt('06:00');

or in the legacy app/Console/Kernel.php $schedule array. Guard it with ->withoutOverlapping() — a slow paginated run against a large inbox will otherwise stack if the API is throttling.

Layered rules instead of one blunt rule. Treat the config as a policy document with progressively stricter tiers:

'rules' => [
    // 1. Never touch review requests or direct @mentions.
    ['keep' => ['reason' => ['review_requested', 'mention']]],

    // 2. Aggressively clear high-volume bot repos.
    ['repo' => 'org/renovate-bot', 'older_than' => '1 day', 'action' => 'done'],

    // 3. Softer treatment for human repos.
    ['repo' => 'org/*', 'older_than' => '30 days', 'action' => 'read'],
],

Order matters: first match wins in most implementations, so put the protective "keep" rules at the top. Verify the precedence by running with verbose output on a small time window.

Dry-run → audit → enforce. Always prototype with the narrowest possible window (--since/older_than of a few hours or one repo) and compare the command's summary line against the GitHub UI. Once the counts match what you expect, widen the window. Keep the pre-change counts in a log so you can prove the tool isn't silently dropping threads you needed.

Separate "read" from "unsubscribe." These are different decisions with different blast radius. Marking read is reversible in the UI; unsubscribing is not recoverable without re-finding the thread. Run the read pass on a short schedule (daily) and any unsubscribe pass on a long one (monthly), or gate unsubscribe behind an explicit flag in the command invocation.

Multi-account handling. If you maintain personal and work identities, don't share one process. Register two GitHub connections (different token, different config) and run two scheduled commands, or parameterize the command with a connection name if supported. Mixing tokens in one run is the fastest way to mark the wrong account's threads as read.

Log the delta, not the chatter. Wrap the scheduled invocation and emit a metric:

Schedule::command('github-notifications:...')->daily()->then(function () {
    // read the command's summary output / log line and push to your metrics sink
});

Trending "threads pruned per night" is the signal that your rules have drifted too aggressive or too lax.

Pair with an outbound notifier. If the package clears threads you'd otherwise see, you lose information. Feed the surviving notifications (review requests, mentions) into Slack/Mail via a small supplementary command so pruning never removes the last channel by which you'd learn about a blocker.

Gotchas and Tips

  • Scopes are the number one silent failure. A token missing notifications yields empty result sets, not errors. If a run reports "0 threads processed" against an obviously busy inbox, check the token scope before you debug anything else.
  • Rate limits are per-token and shared with your other GitHub tooling. A large first purge can burn through the hourly budget and starve a deploy pipeline or IDE extension using the same PAT. Use a dedicated token for this package, and implement backoff rather than retrying in a tight loop.
  • Paginated results can be huge. The first run against a long-neglected inbox is the worst-case; on a 5,000-thread backlog expect a multi-minute run and plan the scheduler timeout accordingly. Subsequent runs are cheap because the delta is small.
  • config:cache will bite you. After editing rules, run php artisan config:cache (or clear it) — a cached config is the usual explanation for "my rule changes did nothing."
  • Timezone/offset skew. Rules expressed as "older than 24 hours" are evaluated against server time, which may differ from your local day boundary. An inbox that looks stale locally at 9am can be untouched by a run at 6am UTC. Pin APP_TIMEZONE and reason in UTC when writing windows.
  • API surface drift. GitHub's notifications endpoints have been iterated on repeatedly (the last_read_at semantics, the all/participating split, deprecations around since). Pin the package version in composer.json and read the changelog before a major bump — a green test suite won't catch a changed default in an upstream API.
  • "Done" ≠ "unsubscribed." Marking a thread read does not stop future notifications on it. A repo that keeps pinging you needs a repo-level ignore/mute rule, not a thread-level mark-read rule. Conflating the two produces a config that runs nightly and never actually reduces volume.
  • Muted repos still appear in the API. Server-side mutes are not reliably reflected in the notifications feed, so you generally must express ignores explicitly rather than relying on GitHub's own mute state.
  • Extension point: custom rules/handlers. Most of these packages accept a configurable list of rule objects or a callback hook. When the built-in predicates run out (e.g., "ignore anything whose subject is a dependency-bot PR that is already merged"), implement the package's rule interface and register your class in config rather than forking — forks of small Graham Campbell packages are disproportionately painful to keep current.
  • Debugging checklist when nothing happens: (1) command registered in php artisan list, (2) token scope, (3) config cached, (4) scheduler actually running (schedule:run in cron, not just schedule:list), (5) rules ordered such that a broad "keep" isn't swallowing everything.
  • Treat it as infrastructure, not a library. Because there is essentially no community footprint, you are your own support channel. Keep the package version pinned, keep your rules in version control alongside a short comment on why each exists, and re-audit after any GitHub API announcement.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings