name: verify-citation
description: Verify that academic citations exist and match the metadata claimed for them, and optionally write verification results into a project summary table. Looks up DOIs against CrossRef, fetches canonical authors/title/year/journal and the abstract via OpenAlex, and reports any mismatch against a BibTeX entry or a free-form DOI. Use to gate every citation literature-curator adds, to audit an existing BibTeX file for fabricated or wrong entries, or to retrieve an abstract so the calling agent can judge whether the paper actually supports a given claim.
| Variable | Default | Purpose |
|---|---|---|
BIB_FILE |
references.bib |
Path to project BibTeX. Used when verifying by citekey. |
SUMMARY_FILE |
references.csv |
Project literature summary table. When --summary-csv is set (or this is configured in CLAUDE.md), verified_on / verify_status are written back per citekey. |
CITATION_VERIFY_EMAIL |
(unset) | Polite-pool email for CrossRef/OpenAlex. Strongly recommended — gives a higher rate limit and prioritizes your requests. |
CITATION_VERIFY_TIMEOUT |
15 |
Request timeout in seconds. |
Resolution order on each invocation:
- Command-line flags (highest priority).
- Environment variables.
- Project CLAUDE.md "Research stack" block — fields
BibTeX file,Summary file,CrossRef email. - Defaults above.
If BIB_FILE is not configured on first use, ask the user once and offer to persist it.
Step 1 — Pick the input mode
Four modes:
# Verify a single DOI
python3 verify_citation.py --doi 10.1038/s41586-023-XXXXX-X
# Verify one citekey from the BibTeX file
python3 verify_citation.py --bib references.bib --key smith2023connectome
# Audit the whole BibTeX file
python3 verify_citation.py --bib references.bib
# Audit and also update the project summary table in place
python3 verify_citation.py --bib references.bib --summary-csv references.csv
Optional flags:
--claim "<one-line claim>"attaches the claim to the report so downstream logs show what was being supported. The skill does NOT decide whether the abstract supports it — that is the calling agent's call.--jsonemits structured JSON instead of the human report.
Step 2 — Run the verifier
python3 "$CLAUDE_PLUGIN_ROOT"/skills/verify-citation/verify_citation.py \
--bib "$BIB_FILE" \
--summary-csv "$SUMMARY_FILE"
The script:
- Parses the requested entry(ies) from the BibTeX file.
- Hits CrossRef (
api.crossref.org/works/<DOI>) for canonical metadata. - Falls back to a CrossRef title+author search if no DOI is present in the BibTeX.
- Hits OpenAlex (
api.openalex.org/works/doi:<DOI>) for the abstract. - Compares author / title / year between BibTeX and CrossRef; flags mismatches.
- If
--summary-csvis set, writesverified_on(today, YYYY-MM-DD) andverify_statusto the matchingcitekeyrow. Other columns (our_use,paper_says,bucket,cited_sections) are never overwritten.
Step 3 — Read the report
Human report (per entry):
[PASS|MISMATCH|NOT_FOUND] <citekey or DOI>
DOI: <doi> → CrossRef: <found / not found>
Title: crossref="..." match=<true/false>
Author: crossref="..." (+N more) match=<true/false>
Year: crossref=YYYY match=<true/false>
Abstract (first 500 chars):
"..."
Claim: <if --claim was provided>
→ Read the abstract above and confirm whether it supports the claim.
Note: <any flags>
Statuses:
PASS— DOI resolves AND title/authors/year all match (case-insensitive, normalized).MISMATCH— found at CrossRef but at least one metadata field disagrees with the BibTeX entry.NOT_FOUND— DOI does not resolve and title+author search returns no plausible match.NOT_VERIFIED— network error, surfaced separately; not treated as a pass.
Step 4 — Caller assesses claim-fit
The script does NOT decide whether the abstract supports the claim — that requires reading. The calling agent reads the abstract from the report and answers the claim-fit question. The skill provides the evidence; the agent provides the judgment.
stdout: human-readable report (one block per entry) — or JSON if --json was passed.
Exit codes:
0— all entries PASS.1— at least one entry MISMATCH or NOT_FOUND.2— script error (network down on every retry, malformed BibTeX, missing file, etc.).
When --summary-csv is set:
- Columns updated:
verified_on,verify_status(per-citekey). - Columns added if the citekey row does not exist: a new row with
citekey,verified_on,verify_statusfilled and human-curated columns left blank forliterature-curatorto fill. - Columns the skill never touches:
our_use,paper_says,bucket,cited_sections,authors,year,title,venue,doi. These belong to the curator.
| Symptom | Cause | Action |
|---|---|---|
urllib.error.URLError / timeout |
Network unreachable, CrossRef down | Retry once; if still failing, report affected entries as NOT_VERIFIED (network) and do NOT mark them PASS |
Title matches but DOI does not resolve |
BibTeX has a typo in DOI | Report as MISMATCH; the curator agent fixes the DOI |
Author count differs |
BibTeX truncates with "et al." | Soft MISMATCH — flagged in notes but does not necessarily fail (curator decides) |
Abstract empty in OpenAlex |
Publisher does not deposit abstracts | Skill still PASSes on metadata; caller must verify claim-fit via manuscript download |
Summary file does not exist |
First run, no summary table yet | Skill creates the file with the canonical header row |