Skip to main content

enrich-paper

Enrich an existing paperswithcode paper with its official GitHub repository, project page, Hugging Face artifacts, existing-taxonomy task/method tags, and a recognizable thumbnail through `create-thumbnail`. Use whenever the user asks to enrich a paper, attach its code or project page, improve its tags, fill missing links, replace Gemini URL extraction, or complete an arXiv/external paper page. Finds authentic URLs from cheap authoritative evidence, preserves existing tags and HF normalization, rejects false-positive repos, and fixes thumbnails that are missing, generic, “Untitled resource,” stale, broken, wrongly versioned, squat, letterboxed, or otherwise unsuitable.

Source facts

Repository
huggingface/paperswithcode
Last source activity
October 14, 2026 at 15:43
Detected SKILL.md language
English
Stars
188
Forks
20

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
enrich-paper
description
Enrich an existing paperswithcode paper with its official GitHub repository, project page, Hugging Face artifacts, existing-taxonomy task/method tags, and a recognizable thumbnail through `create-thumbnail`. Use whenever the user asks to enrich a paper, attach its code or project page, improve its tags, fill missing links, replace Gemini URL extraction, or complete an arXiv/external paper page. Finds authentic URLs from cheap authoritative evidence, preserves existing tags and HF normalization, rejects false-positive repos, and fixes thumbnails that are missing, generic, “Untitled resource,” stale, broken, wrongly versioned, squat, letterboxed, or otherwise unsuitable.
# Enrich a Paper This skill fills in the two things a freshly imported paper most often lacks: 1. **Code links** — the paper's *own* official GitHub repository and project page URL. 2. **Hugging Face artifacts** — official model, dataset, and Space URLs, synchronized into normalized artifact links. 3. **Taxonomy tags** — `tasks` and `methods` that already exist in the database, matched to what the paper is actually about. 4. **Thumbnail** — an authoritative, recognizable paper-card image, not merely a reachable URL or generic browser capture. It is the agent-driven replacement for the Gemini URL-extraction cron (`backend/genai_steps/extract_github_and_project_page_url.py` + `backend/database/repos_and_pages_setup/batch_extract.py`). Instead of calling the Gemini API, **you** (the coding agent) fetch a small amount of evidence and reason over it yourself. The whole point is to find *authentic* URLs at low token cost, so prefer cheap structured sources first and only escalate to heavier ones (PDF text, project-page HTML) when something is still missing. Writes go to the **live database** via existing services / the admin API, exactly like `add-external-paper`. Keep writes idempotent and scoped to the requested paper. ## Core principles - **Authenticity over recall.** A GitHub or project-page URL is only valid if it is the paper's *own* artifact. Papers routinely cite *other* repos (baselines, datasets, frameworks, related work). A `github.com/...` on page 1 is **not** automatically the paper's repo. When in doubt, leave it out and report it — a false positive is worse than a miss. - **Cheapest evidence first.** Each step below is more expensive than the last. Stop as soon as you confidently have both URLs. Never dump a whole PDF into your context — the first 2 pages (or the HF markdown) carry the code links. - **Only existing taxonomy.** Tag with `tasks`/`methods` rows that already exist. Do not invent new ones (that's `add-task` / `add-method`). If the right concept is missing, pick the closest existing tag and report the gap. - **Complement the crons, don't fight them.** Method tags are *also* added by the Semantic Scholar citation cron (papers that cite a method's source paper) and by the HF import keyword matcher. Your job is content-based tagging for *this* paper; a few high-confidence tags beat keyword stuffing. - **Leave the paper card looking right.** Thumbnail completion is part of enrichment. A reachable image can still be incomplete when it is blank, generic, says “Untitled resource,” shows stale content, or uses the wrong arXiv-version title. Use the sibling `create-thumbnail` skill for the audit, source selection, composition, cache-safe publication, and live visual verification. ## Pre-flight Run everything from the repo root with the project environment so the venv and secrets load: ```bash uv run --env-file backend/keys.env ... ``` Confirm the API is up and grab the admin token + HF token: ```bash curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8000/api/v1/papers/recent?limit=1 ADMIN_TOKEN=$(grep '^PWC_ADMIN_API_TOKEN=' backend/keys.env | cut -d= -f2-) HF_TOKEN=$(grep '^PWC_HF_TOKEN=' backend/keys.env | cut -d= -f2-) ``` If the API is unavailable, use direct database verification where supported or report the blocker. Do not start or restart deployed services during curation. ## Step 0 — Resolve the paper row You need the DB `paper_id` (and `arxiv_id` if any). Accept an arXiv id, a `paperswithcode.co/paper/<id>` URL, or an external paper. Read what's already linked so you can **merge** rather than clobber. ```bash uv run --env-file backend/keys.env python - <<'PY' from sqlalchemy import text from backend.database.connection import get_engine ident = "2509.14033" # arxiv_id, numeric paper id, or title fragment with get_engine().connect() as conn: row = conn.execute(text(""" SELECT id, arxiv_id, title, source, source_url, urls_extracted FROM papers WHERE arxiv_id = :ident OR CAST(id AS TEXT) = :ident OR title ILIKE :like ORDER BY is_latest_version DESC NULLS LAST, id DESC LIMIT 1 """), {"ident": ident, "like": f"%{ident}%"}).mappings().first() print(dict(row) if row else "NOT FOUND") PY ``` Then read existing tasks/methods/repos/project pages so you can merge: ```bash curl -s "http://localhost:8000/api/v1/papers/<paper_id>?include_resources=true" \ | uv run python -c "import json,sys; p=json.load(sys.stdin); print('tasks',[(t['id'],t['slug']) for t in p.get('tasks') or []]); print('methods',[(m['id'],m['slug']) for m in p.get('methods') or []]); print('repos',[(r.get('url'),r.get('is_official')) for r in p.get('repositories') or []]); print('project_pages',[pp.get('url') for pp in p.get('project_pages') or []])" ``` If the paper has no arXiv id (external paper), the arXiv-specific steps below don't apply — use the paper's `source_url`, linked GitHub README, or HF model card as the evidence surface instead, and skip straight to URL validation + tagging. If the paper row itself does not exist yet, this is the wrong skill — use `add-external-paper` first, then come back to enrich. ## Part A — GitHub repository & project page URL Walk the layers in order. Carry forward whatever you've found; only escalate for what's still missing. After each candidate URL, **validate authenticity and liveness** (see "Validating URLs"). ### Layer 1 — Hugging Face papers API (cheapest, most authoritative) If the paper is on HF, authors/maintainers often already linked the repo and project page. Use the HF token to avoid rate limits. ```bash curl -s -H "Authorization: Bearer $HF_TOKEN" \ "https://huggingface.co/api/papers/<arxiv_id>" \ | uv run python -c "import json,sys; d=json.load(sys.stdin); print('githubRepo:', d.get('githubRepo','')); print('projectPage:', d.get('projectPage',''))" ``` `githubRepo` and `projectPage` here are author-curated and can be trusted with light validation. If both are present and live, you're done with Part A. The same surface has author/community comments that frequently contain the links (HF often surfaces the official repo here even when the abstract doesn't): ```bash curl -s -H "Authorization: Bearer $HF_TOKEN" \ "https://huggingface.co/api/papers/<arxiv_id>?field=comments" \ | uv run python -c "import json,sys; d=json.load(sys.stdin); [print(c.get('author',{}).get('name'),'=>',c.get('data',{}).get('latest',{}).get('raw','')[:400]) for c in d.get('comments',[])]" ``` Prefer links posted by an author of the paper or its official org; treat random third-party comments with more suspicion. ### Layer 2 — Regex over abstract + HF markdown (cheap text) The HF markdown rendering of a paper is small and link-rich. Read it and the abstract, and scan for the paper's own GitHub/project links: ```bash # Markdown version of the paper page (note the .md suffix) curl -sL -H "Authorization: Bearer $HF_TOKEN" "https://huggingface.co/papers/<arxiv_id>.md" -o /tmp/<arxiv_id>.md # or: uv run --env-file backend/keys.env hf papers read <arxiv_id> > /tmp/<arxiv_id>.md ``` Patterns the existing pipeline uses (reuse them rather than reinventing): - GitHub: `\bhttps?://github\.com[^\s]*\b` - Project page (github.io is a strong signal but not required): `\bhttps?://[a-zA-Z0-9.-]+\.github\.io[^\s]*` You can also call the repo's own helpers for the abstract-regex + HF-API combo: ```bash uv run --env-file backend/keys.env python - <<'PY' import asyncio from backend.utils.paper_utils import ( get_abstract, find_github_url, get_github_and_project_page_urls_from_daily_papers, ) async def main(): arxiv_id = "<arxiv_id>" gh_api, pp_api = await get_github_and_project_page_urls_from_daily_papers(arxiv_id) abstract = await get_abstract(arxiv_id) gh_abs = await find_github_url(arxiv_id=arxiv_id, abstract=abstract) print("hf_api github:", gh_api, "| hf_api project:", pp_api, "| abstract github:", gh_abs) asyncio.run(main()) PY ``` A GitHub URL stated in the abstract ("code available at …", "we release … at …") is almost always authentic. A bare `github.com` link buried in markdown body text needs the authenticity check before you trust it. ### Layer 3 — First 2 pages of the PDF (only if still missing) Many papers put the repo/project link in a first-page footnote or under the abstract, not in the HF metadata. Download the PDF and read **only the first two pages** to keep cost down: ```bash curl -sL "https://arxiv.org/pdf/<arxiv_id>.pdf" -o /tmp/<arxiv_id>.pdf pdftotext -l 2 -layout /tmp/<arxiv_id>.pdf - 2>/dev/null | head -c 12000 ``` If `pdftotext` is unavailable, use the repo helpers (`extract_text_from_pdf` reads the first 2 pages; `extract_hyperlinks_from_pdf` pulls embedded hyperlinks, which often contain the clickable repo link even when the visible text is truncated): ```bash uv run --env-file backend/keys.env python - <<'PY' from backend.utils.pdf_utils import extract_text_from_pdf, extract_hyperlinks_from_pdf print(extract_text_from_pdf("/tmp/<arxiv_id>.pdf", num_pages=2)[:8000]) print("LINKS:", [l["url"] for l in extract_hyperlinks_from_pdf("/tmp/<arxiv_id>.pdf") if "github.com" in l["url"] or "github.io" in l["url"]]) PY ``` Reason over this text yourself (this is the part that used to be the Gemini call). Decide which link, if any, is the paper's own repo/project page. Do **not** feed the whole PDF to anything — first two pages only. ### Layer 4 — Project-page HTML → GitHub (the Step-2 fallback) Some papers only print a project-page URL and hide the real GitHub link inside the project page's HTML — this is the single highest-value step, because the layers above genuinely can't see it. If you have a project page but **no** GitHub yet, fetch the project page and look for the repo: ```bash curl -sL "<project_page_url>" | grep -oE 'https?://github\.com/[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+' | sort -u | head ``` (Or use `WebFetch` on the project page and read off the "Code"/"GitHub" link.) **Critical: project pages are built from website templates, so the HTML almost always contains a template's GitHub repo that is NOT the paper's code.** Grepping blindly here is the most common false-positive source. Reject these on sight: - `github.com/eliahuhorwitz/Academic-project-page-template` - `github.com/nerfies/nerfies.github.io` (and other `*/<name>.github.io` *page-source* repos) - any `*-project-page`, `*-template`, `*.github.io` repo that is the page's own source rather than the method's code - starter kits, analytics, or library repos referenced by the page's `<head>`/footer Accept a repo only when it is plausibly the paper's *own* code. Strong signals: the owner matches the project-page subdomain owner (e.g. page `https://yimingc9.github.io/physiformer` → repo `github.com/yimingc9/PhysiFormer` ✓) or a paper author; the repo name matches the method/paper name; the page links it under a "Code"/"GitHub" button rather than a tiny "website template" credit in the footer. When the page exposes a "Code coming soon" placeholder and only the template repo is present, the correct answer is **no GitHub** — link the project page and move on. Examples seen in the wild: a page whose only GitHub link is `eliahuhorwitz/Academic-project-page-template` ⇒ no repo; a page linking both `owner/Method` and `owner/Method.github.io` ⇒ take `owner/Method`, not the `.github.io` page-source repo. ### Validating URLs (authenticity + liveness) Before saving, every candidate must pass both: 1. **Liveness** — the URL resolves (HTTP 200). Reuse the repo helper or curl: ```bash uv run --env-file backend/keys.env python -c "import asyncio; from backend.utils.verify_url import verify_url; print(asyncio.run(verify_url('<url>')))" ``` For GitHub, also confirm the repo exists and isn't a 404/empty redirect: `gh repo view <owner>/<repo> --json url,isArchived,description` (or `curl -sI`). 2. **Authenticity** — it is the paper's own artifact. Strong positive signals: stated in the abstract or a first-page footnote; linked as `githubRepo`/`projectPage` on the HF API; posted by an author/official-org comment; owner/org matches the authors' affiliation or the project page domain; project page and repo cross-link each other. Red flags that mean **reject**: the link sits in References / Related Work / a baseline-comparison table; it points to a well-known third-party project (a dataset, a framework, a different paper's repo); it is a **website-template / page-source repo** found in project-page HTML (`eliahuhorwitz/Academic-project-page-template`, `nerfies/nerfies.github.io`, any `*.github.io` page-source or `*-template` repo — see Layer 4); the owner is clearly unrelated to the authors and the project page. A `github.com` literal is required for a GitHub URL; a project page must *not* be a GitHub repo URL, and HF model/dataset/collection pages are **not** project pages (an HF Space can be only if explicitly presented as the project page). When unsure, prefer no write and list the candidate under "needs review". ### Saving Part A results GitHub repos and project pages are saved as **official** (`is_official=true`) and tagged with `source='ai_extraction'` to match the cron's provenance. Use the services directly (they normalize the GitHub URL and skip if an official one already exists): ```bash uv run --env-file backend/keys.env python - <<'PY' from backend.database.connection import get_database_session from backend.services.repository_service import RepositoryService from backend.services.project_page_service import ProjectPageService from backend.utils.github_utils import parse_github_url paper_id = <paper_id> github_url = "<validated github url or ''>" project_page_url = "<validated project page url or ''>" session_gen = get_database_session() db = next(session_gen) try: if github_url: owner, name = parse_github_url(github_url) RepositoryService(db).create_repository_for_paper( paper_id=str(paper_id), url=github_url, owner=owner, name=name, num_stars=0, is_official=True, source="ai_extraction", skip_if_official_exists=True, ) if project_page_url: ProjectPageService(db).create_project_page_for_paper( paper_id=str(paper_id), url=project_page_url, is_official=True, source="ai_extraction", skip_if_official_exists=True, ) db.commit() print("saved", {"github": github_url, "project_page": project_page_url}) finally: try: next(session_gen) except StopIteration: pass PY ```
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub