Reading papers
Skill ericluo04/claude-academic-workflow/skills/reading-papers
Academic research workflow for Claude Code: 14 skills (paper reading, lit review, bib auditing, preregistration, referee reports, replication packages, LaTeX, TikZ) plus a Quarto reveal.js slide system with render-time quality gates. Entirely AI-generated with Claude Code as a proof of concept.
npx -y skills add ericluo04/claude-academic-workflow --skill reading-papersAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Look up, resolve, and read academic papers when the user sends a link, DOI, title, author name, or vague description, across marketing (Marketing Science, JMR, JM, JCR), economics (QJE, AER, ECMA, JPE, ReStud, AEJs, AER:Insights), psychology (Psych Science), and CS (ICLR/ICML/NeurIPS, JMLR, ACL). Preserves LaTeX equations; integrates the user's Zotero library and an optional ~/ocr-examples HPC OCR pipeline. TRIGGER whenever the user asks to read, summarize, check, find, or cite a paper, asks "what does X argue", pastes a paper URL, or asks what an author has written. For a whole literature on a topic, use litreview instead.
SKILL.md
13.9 KB, as published. Nobody here has run it
Reading papers
Get from a fuzzy reference to clean full text with equations intact, cheaply, without wasting context on dead ends. The intelligence is yours; the script is a tool. Don't blindly trust its first answer on hard cases (common author names, paywalled venues). Verify, as flagged below.
The command
~/.claude/skills/reading-papers/scripts/paper.py <cmd> "<query>" [flags]
| cmd | does |
|---|---|
resolve | fuzzy ref → canonical record (DOI, arXiv id, venue, year, OA status, best free URL, free AEA appendices) |
get | resolve, then fetch the cleanest full text available |
search | topic/keyword search across Semantic Scholar + OpenAlex + arXiv, deduped and merged |
author | works by a person, newest first, with disambiguation |
cites | citation graph: cited-by and references; --contexts adds the citing sentences |
Flags: --venue "…" · --since/--until YEAR · -n N · --json · --save · --raw ·
--list-sections · --section "<substr>" · --affiliation "…" · --orcid "…" · --contexts
Keys (optional, all free) live in ~/.claude/secrets/scholar.env; the script auto-loads them.
How resolution works, and why order matters
resolve is cheap and prints whether a free copy exists and where. Always resolve before
web-searching or guessing URLs. The routing is cost- and Cloudflare-aware:
- An arXiv id or arxiv link → arXiv metadata (free) + OpenAlex if a DOI exists.
- A DOI → OpenAlex (1 credit) + Unpaywall + NBER direct-PDF + AEA free appendices + a Semantic Scholar OA-PDF fallback (catches NBER copies the others miss).
- An NBER or SSRN URL → mapped to a DOI from the URL itself, skipping the Cloudflare wall.
- A bare title → Crossref first (free); on a confident title match it pulls the record by
DOI (1 credit). Only an unconfident title falls through to OpenAlex
search(10 credits). So hand it a DOI or arXiv id when you have one; a title costs up to 10× more.
Version-of-record vs preprint: a title search can surface the NBER or SSRN copy. The matcher ranks the journal version above preprint containers, but econ papers genuinely exist as several records with different DOIs and different citation counts, so say which one you mean.
search is the topic-level entry point (resolve is for a known item). One query per source,
merged on DOI → arXiv id → normalized title, re-ranked by reciprocal-rank fusion, one OpenAlex
search call per invocation. --json carries abstracts and a sources block saying which
sources answered; each record names the source of its citation count. A source that 429s or errors
is reported and skipped, never fatal. For a whole literature, use the litreview skill, which
wraps this with scoring, Zotero cross-check, and parallel readers.
Read long papers one section at a time
For any paper with an arXiv copy, map first, then pull only what's needed:
paper.py get "10.1257/aer.20181169" --list-sections # cheap map
paper.py get "10.1257/aer.20181169" --section "decomposition" # that section, raw LaTeX
The single biggest context saver: a 70K-char paper becomes a 10K-char section with every
equation, \label, and \ref intact. --section carries the preamble's \newcommand /
\newtheorem definitions along, so macros stay resolvable.
Math fidelity ladder
get tries these in order and prints the source: rung it used:
- arXiv raw LaTeX (
--raw, or auto when HTML is absent): the authors' own source. Best for reproducing/checking an equation. Quote the LaTeX verbatim; don't retype it. - arXiv HTML (LaTeXML):
<math alttext="…">holds the TeX, macros already expanded, clean prose around it. Best default for discussing a paper. - ar5iv: same engine, for papers before arXiv's native HTML (pre-Dec 2023).
- Born-digital PDF (NBER, JMLR, PMLR, repositories): saved to
~/.claude/cache/papers/; read with~/.claude/assets/bin/pdfread.py text <pdf>(pngfor figure pages). Text layer survives; math is fine. - OCR: only when
getreports(SCANNED). See the OCR rung below.
Rule of thumb: discuss → HTML; reproduce/check an equation → --raw.
The OCR rung: ~/ocr-examples (scanned PDFs only)
get runs a text-layer check and tags a PDF (SCANNED) when the first pages have almost no
extractable text. Only then is OCR worth it. If you have such a setup, route it through the
~/ocr-examples repo
(an OCR pipeline on an HPC cluster); do not hand-roll OCR.
- Read first:
~/ocr-examples/README.md,docs/ocr-engines.md, and the relevantscripts/*.py --help. Load any HPC plugin skills you use before launching a cluster job. - Two modes.
diskis for public/non-sensitive PDFs (bytes may live on HPC disk).tunnelis for sensitive documents: the Mac reads the PDF and streams pages to a compute-node service over SSH, so bytes never land on HPC storage and the output is written locally. Use tunnel when in doubt about sensitivity. - Engines (best math first):
olmocr2(olmOCR-2, Apache-2.0, the default),deepseek_ocr,glm_ocr,docling(structure-strong, math-weaker),pypdf(text-native only, no OCR). - Smallest safe start: one document, one worker, one engine, RTX 8000 not A100.
just smoke olmocr2 tunnelproves the path;just documents-process/just engine-olmocr2run real work. Layout is<documents-root>/<guid>/document.pdf; feed a GUID list via--from-fileor direct paths via--pdf-list. Runjust sync-hpcafter editing that repo. - Apple-Silicon note:
olmocr2/deepseek_ocr/glm_ocralso have a local MLX backend, so a single non-sensitive page can be OCR'd on the Mac without the cluster. A large batch belongs on a GPU node via Slurm, never the login node.
Zotero: the user's citation library
A Zotero MCP server is connected; its tools are underscore-named under mcp__zotero__, e.g.
zotero_search_items. This is the user's own reference manager.
- Reads work only while the Zotero desktop app is open with the local API enabled
(Settings → Advanced → "Allow other applications on this computer to communicate with Zotero").
If a
zotero_*call fails, that's almost always the cause, so ask the user to open Zotero. - Use it to: search what they already have, read PDF full text and their own annotations/notes, pull BibTeX for citing, and find items by tag. Prefer their copy of a paper over re-fetching; it's faster and it's the version they annotated.
- Writes (adding a found paper to the library) need a web API key in
scholar.envand are hybrid-mode. Don't add items unless asked. - Natural pairing:
paper.pyfinds and reads anything on the open web; Zotero is the private library. When the user says "the paper I saved / my notes on X," reach for Zotero first.
When there is no free copy
Verified July 2026, hard-blocked to plain HTTP: INFORMS (Marketing/Management Science), SSRN,
AEA direct PDF, Elsevier/Wiley/OUP/Chicago, OpenReview anonymous api2. Escalate in order:
resolvealready checked for a green-OA copy (repository, arXiv, RePEc, NBER) and iterates all OA locations, including the ones it doesn't rank first. Trust it; it finds most paywalled AER / Marketing Science papers as a free copy elsewhere.- Working-paper version: NBER (
nber.org/papers/wXXXXX), CEPR, author's site. For econ this is usually near-identical to the published version. - Free AEA appendix/data: for AER/AEJ the article PDF is walled but the online appendix
(where the proofs live) and replication package are free;
resolvesurfaces them. - Playwright MCP, a real browser, the only thing that clears Cloudflare. An institutional
proxy has the shape
https://<your-library>.idm.oclc.org/login?URL=<target>, but login is typically SSO + MFA, so the user must be in the loop. Ask first; one paper at a time. Systematic proxy downloading can get the whole university cut off, so never loop it. - Scholar Gateway (
semanticSearch): Wiley-leaning licensed corpus, returns passages, not full text; can't fetch by DOI. Good for corroborating a claim, not reading a paper. - Say plainly that only the abstract is reachable. Never paraphrase an abstract as if you read the paper.
Cost model (OpenAlex, metered since 2026)
| call | credits |
|---|---|
DOI / ID lookup, plain filter= | 1 |
anything with search, incl. filter=title.search: | 10 |
Anonymous = 1,000 credits/day. A free key (openalex.org/settings/api) → 10×; put it in
scholar.env as OPENALEX_API_KEY. The script disk-caches every response 30 days, so re-reads
are free. Prefer DOIs/arXiv ids over titles.
Author queries: where you must stay in the loop
author resolves a name via OpenAlex (most-works profile) and prints runner-up matches. Common
names are genuinely hard; do not trust the top pick blindly:
- OpenAlex fragments one person across profiles: the same author appears as a 300-work record and a 2-work stub, and even an ORCID can resolve to a stub. Always sanity-check that the returned works match the person's field (a marketing scholar shouldn't be returning optics papers). If they don't, you have the wrong fragment.
--affiliation "Columbia"filters to the current institution, the reliable fix for a common name. If nothing matches, the script lists candidates with their ORCIDs instead of guessing.--orcidis the most deterministic single input, but see the fragment caveat above.- In CS, DBLP is the gold standard for name disambiguation (explicit homonym suffixes) and its author XML also yields the person's Google Scholar / ORCID / ACM ids.
- Diacritics matter: the canonical
display_namemay beAcemoğlu, notAcemoglu.
cites --contexts shows the actual sentences citing a paper (Semantic Scholar; needs S2_API_KEY).
Use it to see what a paper is actually being used for.
Gray areas / known false positives
- Abstract-vs-fulltext:
getclassifies an HTML page structurally (has a References section? heading count? body word count?), not by raw length, so a short genuine paper with references (an AER P&P note, a Comment) reads as full text and is not flagged. When a page looks abstract-only,getfirst tries any PDF the page advertises (thecitation_pdf_urlmeta tag, or a linked author manuscript) before falling back, which recovers the full text on many repository landing pages. If it still returns only the abstract, it says so (label endsabstract-only). - Scanned-PDF flag: heuristic (little text in the first 3 pages). A born-digital paper with a figure-only opening could false-flag; conversely a mostly-image PDF with a text cover could slip through. Glance at the PDF before committing to an OCR job.
- "Open access" that isn't fetchable: for hybrid-OA Oxford/SAGE, OpenAlex reports a PDF URL on
academic.oup.com/journals.sagepub.com(legally open, technically Cloudflare-dead). The green-OA (repository/PMC/OSF/arXiv) locations are the ones that resolve;resolveprefers them. - Missing abstracts: Crossref lacks abstracts for JPE (Chicago) and JPSP (APA), though OpenAlex has them. Semantic Scholar elides AEA abstracts by publisher request.
Venue cheat sheet
- CS: almost all on arXiv →
--rawgives exact math. Bulk-friendly mirrors are PMLR (per-volumebibliography.bib), ACL Anthology (whole corpus is a git repo), JMLR, NeurIPS proceedings. Reviews/scores need an authenticated OpenReview client. - Econ: arXiv
econ.EM, then NBER (direct PDF). AER/AEJ article PDF is members-only but appendices are free. IDEAS pages give the working-paper ↔ published crosswalk. - Marketing: INFORMS is walled but green OA, so the readable copy is normally an
institutional repository, which
resolvefinds. 2023+ INFORMS DOIs changed shape; listings contain non-article DOIs (…ack…,…eb…) worth ignoring. - Psychology: Psych Science is SAGE (PMC holds front matter only). Try PsyArXiv/OSF.
Honesty rules
- State which version you read (published, arXiv preprint, or NBER working paper). The numbers can differ.
- Citation counts are source-specific and disagree (same Econometrica paper: 235 OpenAlex / 177 S2 / 210 Crossref / 157 OpenCitations). Name the source; never mix counts in one table.
- Never invent a DOI, page number, or quotation. If
resolvereturns nothing, say so.
Working with many papers
Per the user's standing preference, for several papers at once spawn parallel subagents, one
paper each, returning structured summaries. Every API call in paper.py now retries with
exponential backoff on 429/503 (arXiv, Semantic Scholar, OpenAlex, Crossref), and the OpenAlex key
gives a 10,000-credit daily budget, so a fan-out of a dozen readers is safe. Two things still
apply: results are disk-cached (so re-reads across agents are free), and for a very large batch
(many dozens) keep arXiv-heavy concurrency modest, since arXiv politeness is ~1 request / 3s.
Setup state
- This setup assumes Zotero MCP (
zotero-mcp-launch.shreadsscholar.env), Playwright MCP, and Scholar Gateway are installed and connected; adjust to your machine.paper.pyneeds no keys. ~/.claude/secrets/scholar.env: putOPENALEX_API_KEYandS2_API_KEYhere, plus the optional Zotero web-API creds; REFERENCE.md §7 says how to get all of them.- Background on the whole landscape (what's blocked, what's open, why a script beat a fleet of MCP
servers):
REFERENCE.mdin this directory.