Systematic Reviews skill for Claude Code
Protocol first, PRISMA counts that actually add up. Claude writes a registrable protocol before any screening, builds PRESS-checked search strategies, runs dual independent screening with kappa checks, and extracts data with page-level locators. A bundled script computes PRISMA 2020 flow counts from your screening log and flags missing reasons or impossible decisions, so the diagram, bias tables and GRADE ratings stay consistent.
- name
systematic-reviews - size178 lines · ≈2,200 tokens
- files3
- licenseMIT
- updated
What Claude sees before loading it
This description is the only part of the skill that sits in context all the time. Claude reads it to decide when to load the full playbook below.
description: Plans and runs PRISMA 2020 systematic reviews and scoping reviews — registered protocol, eligibility criteria, reproducible multi-database searches, dual independent screening, piloted data extraction forms, risk-of-bias assessment with RoB 2, ROBINS-I, or QUADAS-2, GRADE certainty, and a computed PRISMA flow diagram. Use when the user mentions a systematic review, meta-analysis, scoping review, PRISMA, PROSPERO, Cochrane-style evidence synthesis, risk of bias, or needs an exhaustive and auditable answer to a focused research question. Try asking
- Draft a PROSPERO-ready protocol for a systematic review of exercise therapy for chronic low back pain
- Compute the PRISMA flow diagram numbers from my Rayyan screening export
- Which risk-of-bias tool should I use for these cohort studies and how do I record it?
Use it when
- You are planning or running a systematic or scoping review
- You need PRISMA 2020 flow numbers and checklist items
- You must assess risk of bias or GRADE certainty
- A reviewer asked for an auditable search and screening record
Skip it when
- A narrative related-work section is enough — use literature-review
- You are appraising a single paper rather than a body of evidence — use paper-analysis
How to check the result
prisma_flow.py exits 0 on the screening log, every pooled number traces to an extraction cell with a page locator, and each included study ID resolves.
The common mistake it prevents
Counting multiple reports of one trial as separate studies, which double-counts participants and inflates certainty.
Done well means: the protocol was fixed before screening, any deviation is reported, every record can be traced from search hit to final decision with a reason, two people (or one person plus a documented check) made each eligibility and bias judgment, the PRISMA counts add up, and conclusions match the GRADE certainty.
Hard rules
- Never report a study you have not retrieved and read. Every included study has a verified DOI/PMID/registry ID. Never fabricate counts, effect sizes, or bias judgments; leave cells empty and flag them.
- If the full search cannot actually be executed (no database access), produce the protocol, search strategy, and forms, and say clearly that searching is pending.
- Write the protocol before screening; changes after that are “deviations” and are reported with reasons.
- An AI-assisted screen is a single screener at most. State its role in the methods, and have a human verify all exclusions or a validated random sample.
Review type
| Question | Type | Reporting guideline |
|---|---|---|
| Does X improve Y? Effect size wanted | Systematic review +/- meta-analysis | PRISMA 2020 |
| What evidence exists on a broad topic? | Scoping review | PRISMA-ScR, JBI guidance |
| Synthesis of existing reviews | Umbrella review | PRIOR |
| Diagnostic accuracy | DTA review | PRISMA-DTA |
| Time-limited decision support | Rapid review | Cochrane rapid review guidance; report shortcuts |
Workflow
- [ ] 1. Protocol: question, criteria, outcomes, analysis plan; register
- [ ] 2. Search strategy: peer-review it (PRESS), run, export, log (PRISMA-S)
- [ ] 3. Deduplicate; keep counts
- [ ] 4. Title/abstract screening, dual and independent; pilot first
- [ ] 5. Full-text screening with recorded exclusion reasons
- [ ] 6. Data extraction with a piloted form
- [ ] 7. Risk of bias per study per outcome
- [ ] 8. Synthesis: meta-analysis or structured narrative (SWiM)
- [ ] 9. Certainty of evidence (GRADE)
- [ ] 10. PRISMA flow + checklist; write up
1. Protocol
Fill this template and register it (PROSPERO for health outcomes; OSF Registries for anything else; scoping reviews usually on OSF):
Title / review type
Question (PICO): Population | Intervention/Exposure | Comparator | Outcomes (primary, secondary) | Study designs | Setting
Eligibility: include ... / exclude ... (designs, languages, dates, publication status)
Information sources: databases with platforms, registers, grey literature, citation chasing, expert contact
Search strategy: full string for one database (others in appendix)
Selection process: two independent reviewers, pilot on 50-100 records, conflict resolution
Data items: list of variables extracted, outcome definitions and time points
Risk of bias tool(s): per design
Effect measures: RR/OR/MD/SMD; how converted
Synthesis: criteria for pooling, model (random effects), heterogeneity, subgroup and sensitivity analyses
Reporting bias assessment; certainty assessment (GRADE)
Timeline, funding, conflicts
2. Search
- Minimum for health: MEDLINE, Embase, CENTRAL, plus a trials register (ClinicalTrials.gov, WHO ICTRP). Other fields: the 2-4 core discipline databases plus Scopus or Web of Science.
- Combine controlled vocabulary and free text per concept; validate against known included studies; have a second person check it with the PRESS checklist.
- Log database, platform, date, exact string, limits, and hits for each run. Export full records (RIS) with abstracts.
- Grey literature: theses, preprints, conference abstracts, regulatory documents. Decide in the protocol, not after seeing results.
- For database syntax, see the literature-review skill’s search-syntax reference.
3-5. Screening
- Tools: Rayyan, Covidence, ASReview (active learning), or a spreadsheet with locked columns. Blind reviewers to each other’s decisions.
- Pilot on 50-100 records; compute agreement; refine criteria wording, not the criteria themselves (that would be a deviation).
- Report inter-rater agreement (Cohen’s kappa) for title/abstract screening. Kappa below 0.6 after the pilot means the criteria are ambiguous: clarify and re-pilot.
- Full-text exclusions need one reason each, from a fixed ordered list (first failing criterion): wrong population > wrong intervention > wrong comparator > wrong outcome > wrong design > duplicate report > not retrievable.
- Track multiple reports of the same study (linked by registry ID or author/sample); PRISMA counts studies and reports separately.
Keep a screening log CSV and compute the flow counts from it, never by hand:
python3 scripts/prisma_flow.py screening.csv # counts + consistency errors, exit 1 if any
python3 scripts/prisma_flow.py screening.csv --json # for plotting tools
Columns: record_id, source, duplicate, auto_excluded, title_abstract, retrieved, full_text, exclusion_reason, study_id. Sources prefixed other: (citation searching,
websites) follow the “other methods” column of the PRISMA 2020 diagram. Paste the counts
into the PRISMA 2020 flow diagram template or the PRISMA2020 R package / Shiny app.
6. Data extraction
Build the form from the protocol’s data items, pilot it on 3-5 studies with two extractors, then freeze it.
Study ID | Report(s) | Registry ID | Country/setting | Design | Funding/COI
Population: N randomized/analysed per arm, inclusion criteria, baseline characteristics
Intervention / comparator: dose, duration, delivery, co-interventions
Outcomes: definition, measure, time point, effect estimate, 95% CI or SD, N per arm
Analysis: ITT/per-protocol, adjustment variables, missing-data handling
Notes: discrepancies between registry and publication; author contact log
Source locator for every number: page / table / figure
- Extract the outcome result closest to the protocol’s time point and definition; record the rule used when several are available.
- Prefer the registry or clinical study report when it conflicts with the article; record the discrepancy.
- Double extraction for outcome data; single extraction with verification for descriptive items is acceptable if stated.
7. Risk of bias
Pick the tool by design (RoB 2 for randomized trials, ROBINS-I for non-randomized interventions, QUADAS-2 for diagnostic accuracy). Assess per outcome, two reviewers, with a supporting quote for each domain judgment. For the full tool table, domains, the recording format, and GRADE rating rules, read references/risk-of-bias.md.
8. Synthesis
| Condition | Approach |
|---|---|
| >= 2 studies, same outcome construct, compatible measures | Meta-analysis, random effects; report pooled estimate, 95% CI, tau^2, I^2, prediction interval |
| Same construct, different scales | Standardized mean difference (Hedges’ g) |
| Clinically or methodologically incompatible | Structured narrative synthesis following SWiM; vote counting by direction of effect only, not by significance |
| Scoping review | Charting: frequencies and evidence map; no pooled effects, no bias assessment by default |
Pre-specified sensitivity analyses: exclude high risk-of-bias studies; fixed vs. random effects; imputed vs. observed SDs. Assess small-study effects with funnel plots only when there are 10 or more studies.
9-10. Certainty and reporting
- GRADE each critical outcome; present a Summary of Findings table.
- Complete the 27-item PRISMA 2020 checklist with page numbers; include the flow diagram, full search strategies for every database (PRISMA-S), the list of excluded full texts with reasons, and the protocol registration number.
- Use certainty-matched language: “probably reduces” (moderate), “may reduce” (low).
Verification
prisma_flow.pyexits 0; identification minus removals equals screened; assessed minus excluded equals included reports.- A random 10% of exclusions re-screened by a second reviewer agree, or disagreements are resolved and the criteria clarified.
- Every number in the results traces to an extraction cell with a page/table locator.
- Every included study’s identifier resolves; check retraction status before submission.
Gotchas
- Changing eligibility criteria after seeing results without reporting it is the most common integrity problem in published reviews.
- Counting reports as studies inflates the evidence base and double-counts participants.
- Searching only PubMed or only Google Scholar is not systematic.
- Language and date limits must be justified in the protocol; “English only” is a known source of bias.
- Searches older than 12 months at submission usually need an update run.
Bundled files
Loaded only when a step in the skill needs them. Review them here before installing.
references/risk-of-bias.md
# Risk of bias and certainty: tool selection and domains
Read this at the bias-assessment and certainty steps. Use the official tool guidance
documents for signalling questions; this file summarizes structure so you pick the right
tool and record judgments consistently. Do not reproduce tool forms verbatim in outputs;
cite the tool.
## Tool selection
| Included design | Tool | Judgment levels |
|---|---|---|
| Randomized trials (parallel, cluster, crossover) | Cochrane RoB 2 (variants for cluster and crossover) | Low / Some concerns / High |
| Non-randomized studies of interventions | ROBINS-I (version 2 released 2025; check which version the protocol names) | Low / Moderate / Serious / Critical (V2 adds algorithm-suggested judgments) |
| Non-randomized studies of exposures | ROBINS-E | Low / Some concerns / High / Very high |
| Diagnostic accuracy | QUADAS-2 (QUADAS-C for comparative) | Low / High / Unclear, plus applicability |
| Prognostic factor studies | QUIPS | Low / Moderate / High |
| Prediction model studies | PROBAST | Low / High / Unclear |
| Qualitative studies | CASP qualitative checklist or JBI checklist | Methodological limitations (feeds GRADE-CERQual) |
| Systematic reviews (umbrella review) | AMSTAR 2 or ROBIS | Confidence: High / Moderate / Low / Critically low |
| Animal studies | SYRCLE RoB | Low / High / Unclear |
| Cross-sectional / prevalence | JBI prevalence checklist | Checklist items, summarized |
## RoB 2 domains (randomized trials)
1. Bias arising from the randomization process
2. Bias due to deviations from intended interventions (specify: effect of assignment
[ITT] or effect of adhering)
3. Bias due to missing outcome data
4. Bias in measurement of the outcome
5. Bias in selection of the reported result
Overall: Low only if all domains are low; High if any domain is high or several have
some concerns that together substantially lower confidence. Assess per outcome, not per
study.
## ROBINS-I domains (non-randomized interventions)
Pre-intervention: confounding; selection of participants. At intervention:
classification of interventions. Post-intervention: deviations from intended
interventions; missing data; measurement of outcomes; selection of the reported result.
Requires a pre-specified list of important confounders and a "target trial" description
in the protocol. Version 2 also addresses immortal time bias explicitly.
## QUADAS-2 domains (diagnostic accuracy)
Patient selection; index test; reference standard; flow and timing. Each has risk of
bias; the first three also have applicability concerns.
## Recording format
One row per study per outcome. Every judgment needs a supporting quote or location.
```markdown
| Study | Outcome | D1 | D2 | D3 | D4 | D5 | Overall | Support (quotes / page refs) |
|-------|---------|----|----|----|----|----|---------|------------------------------|
| Lee 2021 | Pain at 12 wk | Low | Some | Low | High | Low | High | D4: unblinded self-report (p.5); D2: 18% crossover (Table 2) |
```
Two reviewers assess independently; record disagreements and how they were resolved.
Visualize with robvis (R package or web app) as traffic-light and summary plots.
## GRADE certainty of evidence
Start: randomized trials at High; observational studies at Low (with ROBINS-I, start at
High and let the tool's judgments rate down).
Rate down (one or two levels each):
- Risk of bias
- Inconsistency (unexplained heterogeneity; I^2 high, non-overlapping CIs)
- Indirectness (population, intervention, comparator or outcome differ from the question)
- Imprecision (CI crosses decision thresholds; optimal information size not met)
- Publication bias (small-study effects, funnel asymmetry with >= 10 studies, industry-only data)
Rate up (observational evidence without serious limitations):
- Large magnitude of effect
- Dose-response gradient
- All plausible residual confounding would reduce the observed effect
Final levels: High, Moderate, Low, Very low. Present in a Summary of Findings table:
```markdown
| Outcome | No. studies (participants) | Relative effect (95% CI) | Absolute effect | Certainty | Reasons |
|---------|----------------------------|---------------------------|-----------------|-----------|---------|
| Mortality 30 d | 6 RCTs (2,140) | RR 0.82 (0.69-0.97) | 21 fewer per 1,000 | Moderate | Imprecision (-1) |
```
Plain-language statements by certainty: High "reduces", Moderate "probably reduces",
Low "may reduce", Very low "the evidence is very uncertain about the effect".
## Meta-analysis checks
- Random-effects by default when studies differ clinically; report tau^2 and a
prediction interval, not just I^2.
- Do not pool when designs, outcomes, or measures are incompatible; use structured
narrative synthesis (SWiM reporting guideline) instead.
- Funnel plots and Egger's test only with 10 or more studies.
- Pre-specify subgroup and sensitivity analyses (e.g., excluding high risk-of-bias studies).
scripts/prisma_flow.py
#!/usr/bin/env python3
"""Compute PRISMA 2020 flow-diagram counts from a screening log CSV and check it
for inconsistencies (missing decisions, decisions after exclusion, full-text
exclusions without a reason).
Usage: python3 prisma_flow.py screening.csv [--json]
Expected columns (header row required, case-insensitive):
record_id unique id per record
source database or register name (e.g. "PubMed", "register:CT.gov"),
or "other:<method>" (citation searching, websites, experts)
duplicate yes/no - removed as duplicate before screening
auto_excluded yes/no - optional; marked ineligible by automation tools
title_abstract include/exclude (blank for other-method records)
retrieved yes/no - full text obtained (for records passing screening)
full_text include/exclude
exclusion_reason required when full_text = exclude
study_id optional; groups multiple reports of one study
Exit status: 0 consistent, 1 inconsistencies found, 2 usage error.
"""
from __future__ import annotations
import csv
import json
import sys
from collections import Counter
YES = {"yes", "y", "true", "1"}
NO = {"no", "n", "false", "0", ""}
def norm(v: str | None) -> str:
return (v or "").strip().lower()
def flow(rows: list[dict]) -> tuple[dict, list[str]]:
errs: list[str] = []
ids = Counter(norm(r.get("record_id")) for r in rows)
for rid, c in ids.items():
if c > 1:
errs.append(f"record_id '{rid}' appears {c} times")
def pathway(r: dict) -> str:
return "other" if norm(r.get("source")).startswith("other") else "db"
out = {p: Counter() for p in ("db", "other")}
by_source: Counter = Counter()
reasons = {"db": Counter(), "other": Counter()}
included_studies: dict[str, set] = {"db": set(), "other": set()}
for r in rows:
rid = r.get("record_id", "?")
p = pathway(r)
c = out[p]
c["identified"] += 1
by_source[r.get("source", "").strip() or "(blank)"] += 1
dup, auto = norm(r.get("duplicate")), norm(r.get("auto_excluded"))
ta, ret, ft = norm(r.get("title_abstract")), norm(r.get("retrieved")), norm(r.get("full_text"))
for col, val, allowed in (("duplicate", dup, YES | NO), ("auto_excluded", auto, YES | NO),
("retrieved", ret, YES | NO),
("title_abstract", ta, {"include", "exclude", ""}),
("full_text", ft, {"include", "exclude", ""})):
if val not in allowed:
errs.append(f"{rid}: invalid {col} value '{val}'")
if dup in YES:
c["removed_duplicates"] += 1
if ta or ft:
errs.append(f"{rid}: duplicate but has screening decisions")
continue
if auto in YES:
c["removed_automation"] += 1
if ta or ft:
errs.append(f"{rid}: automation-excluded but has screening decisions")
continue
if p == "db":
c["screened"] += 1
if not ta:
errs.append(f"{rid}: missing title_abstract decision")
continue
if ta == "exclude":
c["excluded_screening"] += 1
if ret in YES or ft:
errs.append(f"{rid}: excluded at screening but has full-text data")
continue
c["sought"] += 1
if ret not in YES:
c["not_retrieved"] += 1
if ft:
errs.append(f"{rid}: full_text decision without retrieved=yes")
continue
c["assessed"] += 1
if not ft:
errs.append(f"{rid}: retrieved but missing full_text decision")
continue
if ft == "exclude":
reason = (r.get("exclusion_reason") or "").strip()
if not reason:
errs.append(f"{rid}: full-text exclusion without exclusion_reason")
reason = "(no reason recorded)"
reasons[p][reason] += 1
continue
c["included_reports"] += 1
included_studies[p].add((r.get("study_id") or "").strip() or f"rec:{rid}")
for p in out:
out[p]["included_studies_pathway"] = len(included_studies[p])
total_studies = len(included_studies["db"] | included_studies["other"])
total_reports = out["db"]["included_reports"] + out["other"]["included_reports"]
result = {
"identified_by_source": dict(by_source),
"databases_registers": dict(out["db"]),
"other_methods": dict(out["other"]),
"full_text_exclusion_reasons": {k: dict(v) for k, v in reasons.items()},
"total_included_studies": total_studies,
"total_included_reports": total_reports,
}
return result, errs
def render(res: dict) -> str:
d, o = res["databases_registers"], res["other_methods"]
g = lambda c, k: c.get(k, 0)
lines = ["PRISMA 2020 flow counts", "", "IDENTIFICATION"]
for s, n in sorted(res["identified_by_source"].items()):
lines.append(f" {s}: n = {n}")
lines += [
f" Records identified (databases/registers): n = {g(d, 'identified')}",
f" Records removed before screening: duplicates n = {g(d, 'removed_duplicates')}, "
f"automation n = {g(d, 'removed_automation')}",
f" Records identified (other methods): n = {g(o, 'identified')}"
f" (duplicates removed n = {g(o, 'removed_duplicates')})",
"", "SCREENING (databases/registers | other methods)",
f" Records screened: n = {g(d, 'screened')}",
f" Records excluded: n = {g(d, 'excluded_screening')}",
f" Reports sought for retrieval: n = {g(d, 'sought')} | n = {g(o, 'sought')}",
f" Reports not retrieved: n = {g(d, 'not_retrieved')} | n = {g(o, 'not_retrieved')}",
f" Reports assessed for eligibility: n = {g(d, 'assessed')} | n = {g(o, 'assessed')}",
]
for p, label in (("db", "databases/registers"), ("other", "other methods")):
rs = res["full_text_exclusion_reasons"][p]
if rs:
lines.append(f" Reports excluded ({label}): n = {sum(rs.values())}")
for reason, n in sorted(rs.items(), key=lambda x: -x[1]):
lines.append(f" {reason}: n = {n}")
lines += ["", "INCLUDED",
f" Studies included in review: n = {res['total_included_studies']}",
f" Reports of included studies: n = {res['total_included_reports']}"]
return "\n".join(lines)
def main(argv: list[str]) -> int:
args = [a for a in argv if not a.startswith("--")]
if len(args) != 1:
print(__doc__.strip(), file=sys.stderr)
return 2
try:
with open(args[0], newline="", encoding="utf-8-sig") as fh:
reader = csv.DictReader(fh)
reader.fieldnames = [f.strip().lower() for f in (reader.fieldnames or [])]
rows = list(reader)
except OSError as exc:
print(f"error: {exc}", file=sys.stderr)
return 2
missing = {"record_id", "source", "duplicate", "title_abstract", "retrieved", "full_text"} - set(reader.fieldnames)
if missing:
print(f"error: missing columns: {', '.join(sorted(missing))}", file=sys.stderr)
return 2
res, errs = flow(rows)
if "--json" in argv:
print(json.dumps({**res, "errors": errs}, indent=2))
else:
print(render(res))
if errs:
print(f"\n{len(errs)} inconsistency(ies):")
for e in errs:
print(f" - {e}")
else:
print("\nLog is internally consistent.")
return 1 if errs else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:]))
About this skill
Written and maintained by the Claude Skills editors to the same editorial standard as every skill in the directory: a selective trigger, a real workflow, known pitfalls and a verification step. First published , last updated . MIT licensed.