Engagement Tracking
Oversight computes engagement signals for every PR and issue, classifying them by activity status and surfacing items that need attention. Combined with configurable staleness thresholds and AI-generated nudge messages, it keeps your backlog from going silent.
Engagement Signals
For each PR or issue, oversight computes a set of engagement signals from GitHub activity
data. These signals are stored in the EngagementSignals structure:
| Signal | Type | Description |
|---|---|---|
days_since_last_author_activity |
number | null | Days since the PR/issue author last commented or pushed a commit. |
days_since_last_maintainer_activity |
number | null | Days since a non-author human commented or submitted a review. |
pending_review_state |
enum | Current review state: none, changes_requested, approved, or review_requested. |
human_comment_count |
number | Total human comments (bots excluded). |
last_human_commenter |
string | null | Username of the most recent human commenter. |
author_responded_after_review |
boolean | Whether the author has responded since the latest review. |
is_draft |
boolean | Whether the PR is in draft state. |
Engagement Classification
Based on the computed signals, each item is classified into one of four engagement statuses:
active
Both the author and maintainers have been active recently. The PR or issue is progressing normally and does not need intervention.
waiting-on-author
A maintainer has responded (comment or review) but the author has not followed up. This typically means changes were requested and the author needs to address them.
waiting-on-maintainer
The author has been active (pushed commits, left comments) but no maintainer has responded. The PR or issue is blocked on maintainer attention.
stale
Neither the author nor maintainers have been active beyond the configured staleness threshold. The item may need a nudge or should be considered for closing.
Bot Activity Filtering
Engagement signals only count human activity. Oversight automatically filters out known bots to prevent their activity from inflating engagement metrics:
- Usernames ending in
[bot](GitHub App convention) - Known bot accounts: Dependabot, Renovate, Codecov, SonarCloud, Netlify, Vercel, GitHub Actions, Copilot AI
This means a PR with 50 Codecov comments and zero human responses is correctly classified
as stale, not active.
Staleness Thresholds
Staleness thresholds are configurable per user via the settings API:
{
"staleness": {
"pr_days": 14,
"issue_days": 30
}
}
A PR is considered stale after pr_days of inactivity; an issue after
issue_days. These thresholds feed into the engagement classification
and the nudge/ping system.
Nudge and Ping System
Oversight provides a two-stage ping system for stale items:
Warning Ping
A friendly reminder generated by Claude based on configurable templates. The message includes context about the item (title, author, labels, how long it has been idle) and a professional nudge to re-engage.
Final Ping
A last-chance notice before closing. Can optionally close the PR or issue when posted. When a final ping is sent, the item's author is also assigned to the issue so it appears on their GitHub dashboard.
Ping Generation
Pings are generated via AI using context from the analysis:
POST /api/ping/generate
Content-Type: application/json
{
"repoId": 1,
"itemNumber": 42,
"kind": "pr",
"pingType": "warning"
}
The generated message is stored as a task result and shown in the UI, where you can edit it before posting. Generated pings are cached — re-opening the ping modal for the same item returns the previously generated message unless you explicitly request regeneration.
Posting Pings
After reviewing (and optionally editing) the message, post it to GitHub:
POST /api/ping/post
Content-Type: application/json
{
"repoId": 1,
"itemNumber": 42,
"message": "Hey @author, this PR has been idle for 3 weeks...",
"closeItem": false,
"kind": "pr"
}
Setting closeItem: true posts the comment and closes the PR/issue. All ping
actions are recorded in the audit log.
Manual Overrides
Sometimes automated engagement classification gets it wrong. Oversight supports manual overrides per item:
PUT /api/repos/1/items/42/engagement-override
Content-Type: application/json
{
"override": "not-stale"
}
Valid override values:
"stale"— force an item to appear as stale regardless of activity"not-stale"— suppress staleness for an item (e.g., a long-running feature branch)null— remove the override and return to automatic classification
Overrides are shown in the UI as a badge on the item, and they persist across analysis refreshes until explicitly removed.
Ping Templates
Ping messages are generated from configurable templates stored in user settings. There are separate templates for PRs and issues, and for warning vs. final pings:
{
"pingWarning": {
"pr": "Hi! This PR has been inactive. Are you still working on it?",
"issue": "Hi! This issue has been quiet. Is it still relevant?"
},
"pingFinal": {
"pr": "Closing this PR due to inactivity. Feel free to reopen.",
"issue": "Closing this issue due to inactivity. Please reopen if needed."
},
"requireWarnBeforeClose": true
}
When requireWarnBeforeClose is enabled, a warning ping must be sent before
a final/close ping is allowed. The AI uses these templates as a starting point and
customizes the message based on the specific item's context.