skills/fetch-pubmed-recent/SKILL.md
Fetches PubMed articles posted in a given date window matching a keyword set, returning normalized records (PMID, title, authors, abstract, journal, date, DOI, URL). Uses NCBI E-utilities (`esearch` + `esummary` + `efetch`) via WebFetch for portability, but prefers a PubMed MCP server's `search_articles` + `get_article_metadata` tools when one is connected (faster, paginated, parsed). Builds date-bounded queries with optional MeSH expansion. Domain-neutral - usable for any PubMed scan, not just one project. Use when user mentions PubMed, NCBI, last-N-days PubMed, weekly PubMed scan, MeSH search, or when a literature-scan agent needs structured PubMed records.
npx skillsauth add lyndonkl/claude fetch-pubmed-recentInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Fetch PubMed records for a date window + keyword set. Normalize the output to the same shape as fetch-preprint-recent so a calling agent can dedupe across sources.
- [ ] Step 1: Detect transport — prefer PubMed MCP if available, else E-utilities via WebFetch
- [ ] Step 2: Build the keyword query with explicit date bounds
- [ ] Step 3: Execute search → list of PMIDs (page if > 100)
- [ ] Step 4: Fetch metadata + abstracts for each PMID batch
- [ ] Step 5: Normalize records to canonical shape
- [ ] Step 6: Return matched records + summary
Step 1 — Detect transport
At session start the runtime exposes any connected MCP servers. Check whether tools matching mcp__*PubMed*__search_articles and mcp__*PubMed*__get_article_metadata are available.
https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term={query}&retmode=json&retmax=200https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&id={pmids_csv}&retmode=jsonhttps://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id={pmids_csv}&rettype=abstract&retmode=xmlBoth transports return the same downstream shape. The skill caller should not need to care which was used (record transport_used in the return summary so debugging is possible).
Step 2 — Build the date-bounded query
PubMed accepts boolean keyword expressions plus a date filter. The canonical date filter for "papers indexed in PubMed during this window" is:
("YYYY/MM/DD"[PDAT] : "YYYY/MM/DD"[PDAT])
PDAT is the publication date — the most stable choice for a weekly digest. (EDAT is the entry-into-PubMed date, useful if you want "newly indexed even if old"; MHDA is the MeSH-indexed date. Default PDAT.)
For each watchlist keyword, expand into a sub-query:
"protein language model"[Title/Abstract]("Alzheimer Disease"[MeSH] OR "alzheimer's disease"[Title/Abstract]) — only when the keyword has a clean MeSH match the caller has confirmed; do not auto-MeSH-expand or you'll widen the net unpredictably.Combine sub-queries with OR, then AND the date filter:
(("term1"[Title/Abstract]) OR ("term2"[Title/Abstract]) OR ...) AND ("2026/05/04"[PDAT] : "2026/05/10"[PDAT])
Watch out for special characters — escape () inside terms by quoting the term.
Step 3 — Execute search
Call the search tool. Expected output is a list of PMIDs and a count.
If count > 200, page: rerun the search with retstart=200, retstart=400, etc. Cap at 1,000 PMIDs (5 pages). If a 7-day window matches more than 1,000 records, the keyword set is too broad — surface this and ask the calling agent to tighten.
Step 4 — Fetch metadata + abstracts
Batch the PMIDs (200 per esummary call). Pull:
et al. truncation is the digest's job, not this skill's)fulljournalname)pubdate, sortpubdate)articleids[].idtype == 'doi')efetch call with rettype=abstract since esummary doesn't return abstracts)Abstract fetch is the slow part. Batch 100 PMIDs at a time. If abstract fetch fails for a record, keep it but with abstract: null and a warnings flag.
Step 5 — Normalize
Same canonical shape as fetch-preprint-recent:
{
"id": "PMID:39123456", // PMID-prefixed for source clarity
"title": "...",
"authors": ["Smith J", "Doe A", ...],
"abstract": "...",
"date": "2026-05-07", // YYYY-MM-DD parsed from pubdate
"server": "pubmed",
"journal": "Nature Biotechnology",
"doi": "10.1038/s41587-026-12345-6", // if present
"url": "https://pubmed.ncbi.nlm.nih.gov/39123456/",
"matched_keywords": ["protein language model"]
}
URL pattern: https://pubmed.ncbi.nlm.nih.gov/{pmid}/ — the canonical PubMed link. Optional secondary URL via DOI: https://doi.org/{doi} for the publisher's page.
Step 6 — Return
{
"server": "pubmed",
"transport_used": "mcp" | "eutils",
"window": "2026-05-04/2026-05-10",
"query": "(...full query string...)",
"fetched_total": 47,
"matched_total": 47, // PubMed filter is server-side, so fetched == matched
"fetch_errors": [],
"records": [ ... ]
}
Cache the raw search + metadata responses to .cache/{YYYY-WW}-pubmed.json.
Pattern A — Standard weekly scan: PDAT-bounded query with all watchlist keywords OR'd together. The default.
Pattern B — Newly-indexed reach-back: when the user wants "papers PubMed indexed this week, even if published earlier" (useful for older preprints just appearing in PubMed), swap PDAT for EDAT. Document the choice in the digest.
Pattern C — High-precision MeSH-only search: when keyword matching is producing too much noise, ask the user for the exact MeSH headings they care about and search term[MeSH] only. Higher precision, lower recall.
Pattern D — Author-specific watch: outside this skill's default scope but easy — add (Smith J[Author] OR Doe A[Author]) as an additional OR clause to the keyword group.
PDAT is the bug that turns a 7-paper digest into a 70,000-paper data dump.[Title/Abstract] to disable expansion unless MeSH expansion is explicitly requested.efetch with rettype=abstract occasionally times out for batches > 100. On failure, halve the batch and retry; only after two full halvings do you give up on a record.PMID: prefix from id. It distinguishes PubMed records from preprint DOIs at a glance — important during cross-source dedupe in the caller.NCBI_API_KEY), include it as &api_key=....Publisher (in-process, not yet fully indexed). Fine to include but note status if available.| Field | E-utilities (fallback) | MCP (preferred) |
| -------------- | ------------------------------------------------------------------------ | ------------------------------------- |
| Search | esearch.fcgi?db=pubmed&term={q}&retmode=json | search_articles(query=...) |
| Metadata | esummary.fcgi?db=pubmed&id={pmids}&retmode=json | get_article_metadata(pmids=...) |
| Abstract | efetch.fcgi?db=pubmed&id={pmids}&rettype=abstract&retmode=xml | included in metadata when MCP returns it |
| Date filter | ("YYYY/MM/DD"[PDAT] : "YYYY/MM/DD"[PDAT]) | same — pass inside query string |
| Page size | 200 (search), 100-200 (summary), 100 (abstract) | MCP server's choice |
| Auth | optional api_key query param (3 → 10 rps) | per MCP server config |
| Canonical URL | https://pubmed.ncbi.nlm.nih.gov/{pmid}/ | |
testing
Cluster a conference's event records into a small set of coarse themes with finer sub-clusters, an explicit outlier bucket, and soft (multi-membership) affinities — using the hybrid embed-then-label pipeline (embed abstracts, reduce, density-cluster, then LLM-label the clusters) when embedding libraries are available, and an LLM-reasoned hierarchical fallback when they are not. Embeddings do the grouping; the LLM only names the groups. Conference-agnostic. Use when turning structured event records into a navigable theme map for preference elicitation and scheduling, when you need 6-8 reasonable themes rather than 20 muddy ones, or when overlapping talks must belong to more than one theme. Trigger keywords - theme clustering, cluster talks, embed then label, soft membership, outlier talks, conference themes, topic map.
development
Build a personal conference schedule as a constraint-optimization problem — hard constraints (no time overlap, room-to-room travel time, capacity/registration, the attendee's own must-attends and blackouts) plus a user-owned weighted objective trading interest against breadth, pacing (maximize contiguous free time), and serendipity. Surfaces unbreakable conflicts (two high-value overlapping talks the model cannot rank) as decisions for the human rather than silently picking, and reports what each choice traded away. Conference-agnostic. Use to turn a preference profile plus a theme map into a day-by-day plan, to resolve overlapping sessions, or to balance a packed vs paced schedule. Trigger keywords - schedule optimization, conference schedule, constraint optimization, overlapping talks, contiguous free time, conflict surfacing, packed vs paced.
development
Parse a heterogeneous conference program (markdown, HTML, PDF-derived text, or JSON) into normalized event records with per-field confidence scores and independent classification axes (topic, depth, format, prerequisites, recorded, capacity). Detects the program's format before extracting, treats every inferred field as uncertain (present vs inferred vs missing), and flags thin or missing abstracts so downstream enrichment can target them. Conference-agnostic. Use when ingesting a conference or event schedule into a structured store, normalizing a talk/session list, or extracting per-session metadata with calibrated confidence. Trigger keywords - program ingestion, parse schedule, session extraction, event records, conference program, talk metadata, per-field confidence.
development
Build a personalized preference profile from a small number of well-chosen, cluster-grounded questions instead of a long survey. Represents the person's interests as an uncertainty region over the theme map, picks the single highest-information-gain choice-based question (contrasting real talks from different clusters), balances exploiting known interests against exploring uncertain ones, deliberately injects outlier probes to fight selection bias, and stops as soon as the schedule would be stable. Also elicits the user-owned objective weights and hard constraints. Interactive — runs where it can actually ask the person. Conference-agnostic. Use to turn a theme map into a preference profile, to decide what to ask a conference attendee, or to elicit scheduling priorities. Trigger keywords - preference elicitation, ask few questions, information gain, choice-based questions, selection bias probe, objective weights, attendee preferences.