Files
Reinier van der LeerandClaude Fable 5 5e548164e1 feat(blocks): Add GitHub notification management blocks (#13634)
### Why / What / How

**Why:** We have GitHub trigger and repo/issue/PR blocks, but no way for
agents to work with the user's GitHub notification inbox — e.g.
inbox-zero automations, notification triage, or surfacing review
requests. GitHub's Notifications API is poll-only (no webhook events
exist for it), so inbox automations run as scheduled graphs using
regular blocks.

**What:** Adds six blocks covering the [GitHub Notifications REST
API](https://docs.github.com/en/rest/activity/notifications): listing
notifications and getting / marking read / marking done / unsubscribing
from notification threads, plus mark-all-as-read. Also adds a
`GithubGetUserInfoBlock` and extends `GithubListPRReviewersBlock` with
review status info, enabling agents to determine whether the account's
user is (still) involved in a PR (example use case: auto-archiving stale
review-request notifications).

**How:** New `notifications.py` in the GitHub blocks package, following
the existing block conventions there. Notification endpoints live under
`/notifications` rather than `/repos/...`, so the blocks use
`get_api(credentials, convert_urls=False)` with absolute URLs. API
responses are normalized into a shared `NotificationItem` shape whose
`thread_id` chains into the per-thread blocks and whose `subject_url` is
converted best-effort from the API URL to the corresponding github.com
page URL. Notification blocks use the minimal `notifications` OAuth
scope.

### Changes 🏗️

- Add `GithubListNotificationsBlock`: lists the inbox with include-read
/ participating-only / `since` / `before` filters and optional repo
scoping; yields the full list plus each notification individually
- Add `GithubGetNotificationThreadBlock`: fetches one thread and exposes
title, reason, unread, subject type/URL, and repository as separate
outputs
- Add `GithubMarkNotificationsAsReadBlock`: marks all notifications as
read, optionally repo-scoped, with optional `last_read_at` cutoff
- Add `GithubMarkNotificationThreadAsReadBlock` and
`GithubMarkNotificationThreadAsDoneBlock`: per-thread read / done
- Add `GithubUnsubscribeNotificationThreadBlock`: mutes a thread
- Add `GithubGetUserInfoBlock`: fetches info on a given user, or the
authenticated user if no username is given
- Extend `GithubListPRReviewersBlock`: new `include_past_reviewers`
toggle (default off) to also list users who already submitted a review,
plus `review_requested` / `has_reviewed` / `review_state` fields on each
reviewer item; the extra API call is gated behind the toggle so existing
graphs are unaffected
- Refactor: hoist `GITHUB_API_URL` constant into `_api.py` and reuse it

### Checklist 📋

#### For code changes:
- [x] I have clearly listed my changes in the PR description
- [x] I have made a test plan
- [x] I have tested my changes according to the test plan:
- [x] `poetry run pytest backend/blocks/test/test_block.py` — full block
suite passes, including schema validation + mocked execution of all
new/changed blocks
- [x] `poetry run pytest backend/blocks/github/test_github_blocks.py` —
passes
- [ ] Live-run the List / Mark as read blocks against a real GitHub
account (not done — mocked execution only)

<details>
  <summary>Example test plan</summary>
  
  - [ ] Create from scratch and execute an agent with at least 3 blocks
- [ ] Import an agent from file upload, and confirm it executes
correctly
  - [ ] Upload agent to marketplace
- [ ] Import an agent from marketplace and confirm it executes correctly
  - [ ] Edit an agent from monitor, and confirm it executes correctly
</details>

#### For configuration changes:

- [x] `.env.default` is updated or already compatible with my changes
- [x] `docker-compose.yml` is updated or already compatible with my
changes
- [x] I have included a list of my configuration changes in the PR
description (under **Changes**)

<details>
  <summary>Examples of configuration changes</summary>

  - Changing ports
  - Adding new services that need to communicate with each other
  - Secrets or environment variable changes
  - New or infrastructure changes such as databases
</details>

---------

Co-authored-by: Claude Fable 5 <[email protected]>
2026-09-02 17:09:09 +00:00

2.1 KiB

GitHub Users

A block for looking up a GitHub user's public profile, or the profile of the account the supplied credentials belong to.

Github Get User Info

What it is

This block fetches information about a GitHub user, or about the authenticated user (yourself) if no username is given.

How it works

Calls /users/{username} when a username is given, and the authenticated-user endpoint /user when it is left empty — which is how one block answers both "who is this person" and "who am I". The commonly used fields are pulled out as discrete outputs, and the untouched response is emitted as user as well, because GitHub returns roughly forty fields and which ones matter depends on the caller. The two endpoints do not return the same object: for the authenticated user the payload additionally carries private account details such as plan, email and private repository counts, so route user with that in mind.

Inputs

Input Description Type Required
username Username of the GitHub user to look up. Leave empty to get the authenticated user (yourself). str No

Outputs

Output Description Type
error Error message if fetching the user info failed str
username Login (username) of the user str
name Display name of the user str
profile_url URL of the user's GitHub profile str
avatar_url URL of the user's avatar image str
user The full user object from the API. For the authenticated user (i.e. when no username is given) this also includes private account details such as plan, email and private repository counts. Dict[str, Any]

Possible use case

A graph resolves the operating account once at the start of a run — no username, so it hits /user — and reuses the returned login to filter issues, pull requests and review requests to that person's own, instead of hardcoding a username into every downstream block.