| name | fact-check |
| description | Use when the user asks to fact-check a manuscript, verify citations, audit sources, or check whether cited papers actually support the claims attributed to them. Trigger phrases "fact-check", "verify citations", "audit citations", "check the sources", "do these papers actually say that", "verify the numbers in this draft". Do NOT use during or immediately after `/critic-loop` — the evidence critic inside that loop covers the same ground and burns MCP / Zotero quota twice. |
fact-check
Pre-flight (ALWAYS run first)
Before any step below, verify the plugin has been configured:
python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/setup/check_configured.py"
If the result is NOT CONFIGURED, stop immediately and tell the user:
The academic-research project has not been set up on this machine yet. Run the setup skill or setup wizard first — fact-check depends on Zotero and MCP citation lookups, which require API keys and MCP servers that the setup wizard configures.
Do not call MCP tools or proceed with the audit. Running the setup skill/wizard is the required first step.
If the result is configured, proceed.
Bootstrap (first run in this project)
Before running the audit, check that the regression-test backstop this skill relies on is installed in the project:
python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/setup/check_project_scaffold.py" \
scripts/test_common.py scripts/test_citations.py
If the output lists missing files, install them:
python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/setup/install_templates.py" \
test_common.py:scripts/test_common.py \
test_citations.py:scripts/test_citations.py
Tell the user what was installed and flag that the top of
scripts/test_citations.py has project-specific paths they should
review. Then proceed with the audit.
Relationship to critic-loop
This skill is the standalone cousin of the critic-loop evidence
critic. The evidence critic fires inside the revision loop; fact-check
runs one-shot when the user explicitly asks for a citation/claim audit.
Mutual-exclusion rule. If a critic-loop session is currently
running, or just completed with no unresolved evidence-critic MAJORs,
fact-check is redundant — skip unless the user explicitly asks for a
second pass. The two cover the same ground for citations and
quantitative claims; running both on the same draft in the same
session burns MCP lookups twice without new information. If the user
invokes fact-check while a critic-loop is clearly in progress (e.g.
critic-reviews/iter-*/ directories exist and were written in
the last few minutes), ask whether they want to wait for the loop to
finish, or proceed with fact-check as an additional audit.
When to prefer which.
critic-loop— during revision rounds; citations are one of four concerns (with method, argument, expert) and the loop applies fixes iteratively.fact-check— pre-submission audit, supervisor hand-off, journal-submission checklist, or a deliberate citation-only spot-check without the other three critic perspectives. File mode produces a durable report atfact-check-reports/report.mdthe author can share; console mode prints an inline table for paragraph excerpts.
Invocation
The user will typically say something like:
- "fact-check the methods section of the manuscript"
- "verify the citations in chapter 2"
- "do these sources actually support the claims"
- "audit the citations against Zotero"
If the user did not name a target document, ask before proceeding.
Procedure
1. Identify the target and choose output mode
Resolve the document path. If the project has a rendered build (Quarto, R Markdown), fact-check the rendered output, not the authoring source — the rendered form shows resolved inline expressions and citations as the reader will see them.
Output mode. Two modes, picked from the input shape:
| Input shape | Mode | Output |
|---|---|---|
| Quoted prose block in the prompt (no resolvable file path) | console | Compact inline table in chat. No report file. |
File path (manuscript.qmd, chapter.md, …) |
file | Durable report at fact-check-reports/report.md plus a ~100-word console summary. |
If both are present ("fact-check this paragraph from manuscript.qmd"),
the quoted block wins — the user is auditing that excerpt, not the
whole document. Announce the chosen mode at the start of the run
("Mode: console" or "Mode: file") so the user knows what to expect.
2. Extract claim mentions and group by citation
Walk the target document and extract three lists:
- Cited claim mentions — every
@citekey/[@citekey]reference OR every Author (YYYY) / (Author, YYYY) prose mention, with ~20 words of surrounding context per mention. Then group by the underlying citation — the same paper cited in five places is one citation with five mentions, not five separate items. For@citekeyform, the grouping is exact; for Author-Year prose in console mode, treat the surface form as the grouping key (subagent's resolution step will catch ambiguities). - Bare author–year mentions in rendered manuscripts (file mode
only) — Author (YYYY) prose without a governing
@citekeyinside a rendered.qmd/.mdis MAJOR automatically: the manuscript should be using BBT keys, not raw author-year, andscripts/test_citations.pytreats this as a regression class. In console mode the input is normal prose, not rendered output — Author-Year is the normal form, not an error. - Quantitative claims — numbers, percentages, p-values, effect sizes, sample sizes, date ranges mentioned in prose.
3. Verify cited claims (per-citation parallel dispatch)
REQUIRED SUB-SKILLS:
verifying-citations— defines the staged resolve-then-abstract-then- fulltext rule, the VERIFIED / MINOR / MAJOR / UNVERIFIABLE classification, the always-escalate triggers (quoted passages, specific statistics, method details, subgroup findings), the multiple-mentions handling, and the cross-mention consistency check. Every dispatched subagent loads it.superpowers:dispatching-parallel-agents— the pattern for fanning work out to subagents in a single assistant message.
Decide audit scope (once, before dispatching):
- ≤ 30 unique citations → audit every one.
- > 30 unique citations → audit a sample. Sample size
n = max(20, ⌈0.25 × total_unique⌉). Quoted passages and specific statistics cited from a paper are never sampled — every citation containing one of these claim types is audited (all of its mentions). Sample the remainder, prioritising in order: citations whose mentions include directional claims about the manuscript's core contribution → other directional claims → topical/biographical references. Recordnoftotal_uniquein the first line of the output.
Dispatch. In a single assistant message, launch one Agent
per unique citation with subagent_type="general-purpose". Each
subagent receives:
- The citation identifier —
@citekeyfor rendered docs, the Author-Year surface form for console mode — and every mention of it with ~20 words of context each. - Instructions to follow
verifying-citations: Stage 0 (resolve once), Stage A (fetch abstract once), Stage C only if any mention requires it (fetch fulltext once); classify each mention independently; run the cross-mention consistency check at the end. - The return contract from
verifying-citations(per-mention blocks plus an optional cross-mention block).
The unit of work is the unique citation, not the mention — a paper
cited five times is one subagent with five mentions in its prompt,
not five subagents. This (a) fetches the source once and (b) lets the
subagent catch internal inconsistency in how the manuscript uses that
source. The main agent aggregates returned blocks directly — no
per-citation file writes (scale doesn't justify the disk-write
overhead that critic-loop uses for its four critics). Both
console and file modes use the parallel dispatch; the
difference is only in how the aggregate is presented.
4. Verify quantitative claims
For each number in prose:
- Identify the expected source — usually a file under
analysis/results/per theempirical-integrityskill. - Open the results file and check that the literal value appears.
Classify each:
- VERIFIED — number matches authoritative file.
- MAJOR — number absent from or inconsistent with the results file; or the number was hand-typed rather than produced by an inline expression.
Hand-typed numbers are MAJOR regardless of whether they happen to match — they violate the empirical-integrity rule and will drift when the pipeline re-runs.
Report format
Two formats, picked by the output mode chosen in Step 1.
File mode — fact-check-reports/report.md
Create the directory first if needed:
python3 "${CLAUDE_PLUGIN_ROOT:-.}/scripts/setup/ensure_dir.py" fact-check-reports
Report layout:
# Fact-check report
**Document:** <path>
**Mode:** file
**Sampled:** <n> of <total_unique> citations (or "all")
**Date:** <YYYY-MM-DD>
## Summary
| Classification | Cited-claim mentions | Quantitative claims |
|---|---:|---:|
| VERIFIED | N | N |
| MINOR | N | N |
| MAJOR | N | N |
| UNVERIFIABLE | N | — |
(Mentions are counted here, not unique citations — a paper cited
three times with one MAJOR and two VERIFIED contributes 1 MAJOR and
2 VERIFIED to the table.)
## MAJOR issues (fix before submission)
1. `@citekey` in section X: <the claim>.
Source: <what the paper actually says>.
Recommended fix: <replace / remove / find different source>.
...
## UNVERIFIABLE (cannot audit — resolve before submission)
1. `@citekey`: <the claim>. Reason: <e.g. no PDF attached to Zotero>.
Recommended fix: run `enrich_pdfs.py` then re-audit, or replace the
citation.
## Cross-mention inconsistency (one source used in contradictory ways)
(Omit this section if no subagent flagged a cross-mention finding.)
1. `@citekey` cited in sections X (claim Y) and Z (claim ¬Y).
Source: <what the paper actually says>.
Recommended fix: <reconcile the two mentions — drop one, qualify
one, or pick a different source for one>.
## MINOR issues (tighten when convenient)
...
## VERIFIED (sampled)
- `@citekey1`, `@citekey2`, … — checked and match sources.
Console mode — inline output only
For pasted-paragraph excerpts the entire output is an in-chat table; no file is written. One row per unique citation in single-mention cases, one row per mention when a citation appears more than once in the excerpt (rare in a single paragraph):
Fact-check: <first ~10 words of the excerpt> …
Mode: console
Sampled: all (n=5 unique citations)
@citekey1 VERIFIED — claim matches abstract.
@citekey2 MAJOR — direction reversal vs paper's β = −0.23.
@citekey3 UNVERIFIABLE — no PDF attached; run enrich_pdfs.py.
@citekey4 VERIFIED — fulltext supports the claim.
Summary: 2 VERIFIED, 1 MAJOR, 1 UNVERIFIABLE.
Action: address MAJOR and UNVERIFIABLE before relying on this paragraph.
If any subagent returned a cross-mention finding, append a single extra line:
CROSS-MENTION @citekey — used for X in §A and ¬X in §C; reconcile.
The console table is the report. Do not also write a file; the user asked for an inline check.
Reporting to the user
- File mode — write a concise summary (~100 words) pointing at
fact-check-reports/report.md, with MAJOR and UNVERIFIABLE counts and a one-line description of each. Do not paste the full report into chat. - Console mode — the inline table is the report. Do not also write a file, do not append a separate summary block (the table already ends with one).
Regression backstop
Fact-check is a one-shot audit. The recurring companion is
scripts/test_citations.py (installed by Bootstrap above; source at
${CLAUDE_PLUGIN_ROOT:-.}/templates/test_citations.py) — it catches the
regressions that would show up on the next audit: unresolved
@citekeys, bare Author (YYYY) mentions without a governing @key,
and BBT-key drift in coded_papers.csv. Run it in the critic-loop
test gate so fact-checkable issues never rebuild silently between
audits.
Grow the suite with the audit. Every MAJOR item in a fact-check
report is a regression class. Before closing out the audit, promote
each MAJOR into a test in scripts/test_citations.py (or
scripts/test_empirical_integrity.py for hand-typed numbers) if a
static check could catch it. The test failure then becomes the
sentinel for the next cycle — the audit's value compounds rather
than resetting each time.
Red flags
(Citation-verification red flags — direction reversals, training-memory
fetches, abstract-only verification of specific stats — live in
verifying-citations. The flags here are scoped to fact-check's own
procedure.)
- You are about to mark a hand-typed prose number VERIFIED because it happens to match the results file today — mark MAJOR regardless (empirical-integrity violation; numbers must come from inline expressions).
- You are skipping citation checks because "the authors are reputable".
- You are about to write a report file in console mode, or skip the report file in file mode. Mode is decided in Step 1; do not switch mid-run.
- You are about to dispatch citation checks sequentially instead of in
one parallel
Agent-call batch — re-readsuperpowers:dispatching-parallel-agents. - You are about to read
~/.config/academic-research/config.tomlviacat,head,tail,grep,less,more,awk,sed, a Python script, or any other command. NEVER read that file. It holds API keys. No part of a fact-check audit needs those keys in your context.