literature-review
You must use this when synthesizing existing knowledge, identifying research gaps, or tracing the evolution of scientific ideas.
How do I install this agent skill?
npx skills add https://github.com/poemswe/co-researcher --skill literature-reviewIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The skill provides a specialized framework for conducting systematic literature reviews. It utilizes well-known academic APIs to fetch research papers and includes custom Python scripts for data processing and citation verification. Security best practices are followed, including instructions for the agent to handle credentials safely and the use of a reliable package manager (uv). Remote code execution is limited to the installation of this recognized tool.
- Socketpass
No alerts
- Snykwarn
Risk: MEDIUM · 1 issue
- Runlayerwarn
1/1 file flagged
- ZeroLeakspass
Score: 93/100 · 2 sections analyzed
What does this agent skill do?
<search_backend>
This skill owns the command-line search backends in scripts/. They are not separate skills. They handle rate limits and retries automatically via the shared http_client and jats helper modules that sit alongside them in scripts/.
Invocation & workspace (read first): Invoke each script by its absolute path under this skill's base directory (shown to you above as "Base directory for this skill") — e.g. uv run <skill-dir>/scripts/openalex_cli.py …. Never cd into the skill directory. Stay in the directory where the user invoked the skill and anchor the review workspace there with an absolute path: compute WS="$(pwd)/review/{slug}" once at step 1 and pass $WS as --workspace everywhere. Relative review/{slug} resolves against the wrong directory and pollutes the installed plugin. In the command examples below, scripts/… is shorthand for <skill-dir>/scripts/….
Prerequisites:
uvmust be installed. Verify withuv --version. If missing, run the plugin's setup script once:bash <plugin-root>/scripts/setup.sh. The setup script installsuv, prompts (optionally) for an OpenAlex API key, and warms the dependency cache. Fallback if setup is unreachable:curl -LsSf https://astral.sh/uv/install.sh | sh && export PATH="$HOME/.local/bin:$PATH".OPENALEX_API_KEY(optional, recommended). Without it, OpenAlex runs in the unauthenticated polite pool — $0.01/day budget, ~10filterqueries or 1--searchper day before throttling. With a free key, $1/day budget at ~10 req/s. The key lives in~/.env. Never read, print,cat,echo, or otherwise inspect~/.env— credentials must stay out of the agent's context. If the user needs to add a key without leaking it, give them:printf "Enter OpenAlex API key (hidden): " && read -s k && echo && printf "OPENALEX_API_KEY=%s\n" "$k" >> ~/.env && unset k && echo "Saved.".
1. OpenAlex — scripts/openalex_cli.py (cross-disciplinary, ~250M works)
Use as the default broad search. Full reference: references/openalex/works.md, authors.md, topics.md, etc.
uv run scripts/openalex_cli.py filter works \
--search "your query" \
--filter "publication_year:>2019,type:article" \
--sort "cited_by_count:desc" \
--select "id,doi,title,publication_year,authorships,cited_by_count,abstract_inverted_index" \
--per-page 10 > openalex.json
Raw --search alone pulls topical noise (off-topic gen-AI papers ranking high). For a focused corpus, foreground concept/topic filters: resolve the topic via references/openalex/topics.md, then narrow with --filter "topics.id:T<id>" (or concepts.id:C<id>) and use --search only to rank within that slice. Never pair a raw --search with --sort "cited_by_count:desc" — that ranks by fame rather than relevance and fills the pool with landmark papers that merely contain your keywords. Searching "large language model abstract screening" that way returns the WGCNA R package, the PRISMA Statement, and Rayyan; dropping the sort surfaces the actual LLM-screening papers instead. Sort by citations only inside an already-narrow topic filter. The script prints the total hitCount/result count — log it as the query's hit count.
2. arXiv — scripts/search_arxiv.py (preprints: CS, physics, math, quant-bio, stat)
Use for very recent work, ML/CS topics, and physics. Query syntax: references/arxiv/query_syntax.md.
uv run scripts/search_arxiv.py \
--query "ti:\"your phrase\" AND cat:cs.LG" \
--sort_by relevance \
--max_results 10 > arxiv.json
Default to relevance for a review — it surfaces foundational work. Use --sort_by submittedDate --sort_order descending only when you specifically want the newest preprints; date-sort biases the pool to the most recent month and misses seminal papers. Emits one JSON object with a results_count field — log that as the hit count.
3. Europe PMC — scripts/europepmc_api.py (life-science open-access full text + citation graph)
Use for biomedical topics, full-text retrieval, and forward/backward citation chaining.
uv run scripts/europepmc_api.py search "your query AND HAS_FT:y" \
--sort "CITED desc" --max_results 10 --output europmc.json
uv run scripts/europepmc_api.py get_citations MED <PMID> --output citing.json
uv run scripts/europepmc_api.py get_references MED <PMID> --output refs.json
uv run scripts/europepmc_api.py get_fulltext <PMCID> --output fulltext.txt
4. Full-text acquisition — scripts/read_paper.py (any identifier → markdown)
One call per paper; resolves the best legal open-access route automatically.
uv run scripts/read_paper.py --doi 10.1038/s41586-021-03819-2 --workspace "$WS"
uv run scripts/read_paper.py --arxiv 1706.03762 --workspace "$WS"
uv run scripts/read_paper.py --pmcid PMC8371605 --workspace "$WS"
($WS is the absolute workspace from step 1 — $(pwd)/review/{slug}; never pass a relative path.) Prints one JSON line: {"status": "fulltext|abstract-only", "path": ..., "source": ..., "id": ...}. Files land in $WS/papers/{id}/ (paper.pdf, fulltext.md or abstract.md). A PDF the user drops at $WS/papers/{id}/paper.pdf is picked up before any network call. Paywalled papers return abstract-only — never scrape for them.
5. Corpus assembly — scripts/build_corpus.py (raw backend JSON → normalized, deduplicated corpus.json)
uv run scripts/build_corpus.py --openalex "$WS/openalex.json" \
--arxiv "$WS/arxiv.json" --epmc "$WS/epmc.json" --output "$WS/corpus.json"
Each flag is repeatable. Papers found by several backends are merged into one record with a joined found_via (openalex+epmc). Running it again against an existing corpus.json adds only new papers — screening decisions, fulltext, and role on records already there are left untouched, so later search rounds and snowballing never discard prior work.
6. Citation verification — scripts/verify_citations.py (bibliography → verified/mismatched/not_found/retracted)
uv run scripts/verify_citations.py --input "$WS/refs.json"
Input: JSON array ([{"doi", "title"}] or bare strings), BibTeX (.bib), or a text/markdown file with one citation per line (DOIs extracted automatically). Resolves each through OpenAlex, then Europe PMC for DOIs, then cross-checks every clean DOI against Crossref's Retraction Watch data (OpenAlex's own retraction flag misses some withdrawn papers). Set CO_RESEARCHER_USER_AGENT="your-tool (mailto:you@example.edu)" to use Crossref's faster polite pool. Retraction is checked down a ladder — OpenAlex, then Crossref for DOIs, then the paper's PubMed record when there is no DOI (or when Crossref cannot answer). Every result carries retraction_checked and retraction_source; a check that could not run is reported as unchecked, never as clean. Prints a JSON report; exit 0 only when every citation verifies. Run it on any bibliography before presenting it — a mismatched result means the DOI exists but the claimed title doesn't match it (the classic fabrication pattern), and retracted means the paper exists but has been withdrawn; fix or drop either before output.
7. PRISMA counts — scripts/prisma_counts.py (corpus.json → PRISMA 2020 flow numbers)
uv run scripts/prisma_counts.py --corpus "$WS/corpus.json"
Reports records by source, after-dedup, screened, excluded-by-reason, included, not-retrieved, and in-synthesis. Exits 1 if any excluded record lacks a reason. Used by systematic-review; useful in any review to sanity-check that the corpus bookkeeping matches reality.
Picking a backend:
- Cross-discipline overview, citation counts, author/institution metadata → OpenAlex
- Bleeding-edge preprints in CS/ML/physics → arXiv
- Life sciences, medicine, full text, citation chaining → Europe PMC
For broad reviews, run all three in parallel and dedupe by DOI in step 3. </search_backend>
<protocol> All state lives in a review workspace `review/{slug}/`: `protocol.md` (question, criteria, query log), `corpus.json` (candidate pool + screening decisions), `papers/{id}/` (full texts + notes), `synthesis.md`. Create it at step 1; on a restarted session, read `corpus.json` first and resume where screening left off.- Scope — Write the research question and strict inclusion/exclusion criteria to
protocol.md. Pause for user approval of the criteria. Scoping searches may revise the question; append revisions, never overwrite. - Search — Execute the backends. Log every query verbatim in
protocol.mdwith date and hit count. Save raw JSON in the workspace; do not load it into context wholesale. - Dedupe & pool — Run
build_corpus.pyon the raw backend files; never hand-merge them. It emits one record per paper —key(normalized DOI, else normalized title, else a source identifier),ids,title,year,cited_by(highest any backend reported),found_via,screening: {status, stage, reason},fulltext,role— deduplicated across backends, and re-running it after a later search round preserves every screening decision already made.
uv run scripts/build_corpus.py --openalex "$WS/openalex.json" \
--arxiv "$WS/arxiv.json" --epmc "$WS/epmc.json" --output "$WS/corpus.json"
-
Title/abstract screening — Set
screening.status(included/excluded) andreasonper record. Exclusion reasons are mandatory. If the pool exceeds ~50, pilot-screen a random ~20 first and surface borderline calls to the user before bulk screening. -
Acquire & read — For each included paper, run
read_paper.py. Write the script'sstatusvalue ("fulltext" or "abstract-only") into that paper'sfulltextfield incorpus.jsonimmediately —prisma_counts.pyreads this field to computenot_retrievedandin_synthesis, and a record left atnullis counted as not retrieved. Classify each asevidence(bears directly on the question) orbackground. Evidence papers requirenotes.mdwritten from the full text — methods and results actually read via Read/Grep onfulltext.md, one paper at a time, never multiple full texts in context. Background papers may be cited at abstract level.notes.mdformat: citation, read depth, design, N, key effects, claims relevant to the question (with section anchors), limitations, theme tags. Do not trust extracted tables — multi-column tables come through as scrambled line fragments; re-read the source PDF for any tabular data.Navigating
fulltext.mddepends on the route, given by thesourcefield of the script's JSON line.source: "epmc"(JATS) yields real markdown headings — find sections withgrep -n "^#". Every PDF route (arxiv_pdf,oa_pdf,user_pdf,cached) yields no#headings at all; section titles appear as bold lines, so usegrep -n "^\*\*"instead. Agrep "^#"returning nothing on a PDF-route paper means you used the wrong pattern, not that the document is unstructured. If neither pattern finds a section you need, cite by content rather than a section anchor. -
Snowball — For core evidence papers, run
get_references/get_citations(Europe PMC) or follow OpenAlexreferenced_works. Fold the new candidates into the samecorpus.jsonwithbuild_corpus.py --epmc citing.json --found-via snowball:citations --output "$WS/corpus.json"(it adds only what's new, tags their provenance, and preserves decisions already made), then screen them at step 4. One round by default; stop when a round adds nothing. If included papers reveal vocabulary the original queries missed, run one adapted search round and log it. -
Synthesize — Write
synthesis.mdfromnotes.mdfiles only. Tag any citation whosefulltextisabstract-onlywith[abstract-only]inline. End with a retrieval summary listing papers not retrieved and thepapers/{id}/paper.pdfpath where the user can drop a legally obtained PDF for a re-run. -
Verify bibliography — Write the final citation list to
</protocol>$WS/refs.jsonand runverify_citations.py --input "$WS/refs.json". Exit 0 is required before presenting; correct or remove anymismatched/not_foundentry. (Papers screened throughcorpus.jsonwill pass — this gate catches citations that entered the synthesis from memory rather than from the corpus.)
<output_format>
Literature Review: [Topic]
Research question: [Stated] Inclusion criteria: [Population / methods / date / language] Searches executed:
- OpenAlex:
<exact query>→ N hits - arXiv:
<exact query>→ N hits - Europe PMC:
<exact query>→ N hits
Thematic synthesis:
- [Theme 1]: [Summary with verified citations]
- [Theme 2]: [Summary with verified citations]
Research gaps:
- [Gap with evidence of absence]
- [Gap with evidence of absence]
Annotated bibliography:
- [Full citation with DOI/arXiv ID/PMID] — [Key contribution + quality note]
Retrieval summary: [N full-text / N abstract-only; drop-in paths for missing PDFs] </output_format>
<checkpoint> Pause for the user only at: (1) end of Scope — criteria approval; (2) pilot screening — borderline calls; (3) before Synthesize, if the included set is unexpectedly large (>40) or small (<3). Otherwise run the funnel autonomously. </checkpoint>How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/poemswe/co-researcher/literature-review">View literature-review on skillZs</a>