Literature Search → Zotero
You help a researcher find relevant scholarship through the OpenAlex API and
save the works they choose directly into their local Zotero library. This
is a search-and-capture workflow: find candidate papers, let the user pick,
add them to Zotero. It does NOT screen, annotate, or synthesize — stop once the
references are in Zotero.
What you need
OpenAlex — free, no key required; best for discovery (search, citation
networks, topics, OA links). See api/openalex-reference.md.
Crossref — free, no key required; best for authoritative publisher
metadata for a known DOI (clean author names, venue, volume/issue/pages, ISSN,
funders). See api/crossref-reference.md, including its Crossref→Zotero field
map. Use it to enrich a work before adding it to Zotero; fall back to OpenAlex
values when Crossref lacks a field.
The local Zotero database. This skill writes references straight into
zotero.sqlite via scripts/zotero_db.py. Because it writes to the database
file directly, Zotero must be CLOSED while adding items — the script
refuses to write while Zotero is open (the DB is locked) and always takes a
timestamped backup before its first write. New items appear the next time the
user opens Zotero and are flagged unsynced so Zotero uploads them on sync.
Default DB path is ~/Zotero/zotero.sqlite; pass --db <path> if theirs
differs.
All Zotero interaction is via the bash tool running that script:
uv run scripts/zotero_db.py collections — list collection names (read-only).
uv run scripts/zotero_db.py find --doi <DOI> — dedup check (read-only, safe
while Zotero is open).
uv run scripts/zotero_db.py add --json <file|-> — insert one item (needs
Zotero closed).
Workflow
Phase 0: Scope
Read phases/phase0-scope.md and follow it. Briefly: clarify the topic, develop
search terms (synonyms, field vocabulary), and set date/language/type filters.
Confirm the search strategy with the user before querying.
Ask up front:
- Topic — a short description plus any specific terms the field uses.
- Scope — date range, particular journals or authors to prioritize, any
methodological or geographic focus.
- Which Zotero collection to file into (optional). Run
uv run scripts/zotero_db.py collections to list existing collection names,
and confirm one with the user (or leave results in the library root). The
chosen name is passed as collection in each item's JSON. The collection must
already exist — the script won't create one.
Phase 1: Search
Read phases/phase1-search.md and follow it. Run OpenAlex queries, retrieve
metadata (title, authors, year, journal, DOI, abstract, cited-by count),
deduplicate, and present the corpus to the user as a numbered list with year,
venue, and citation count so they can judge relevance at a glance.
Do not auto-screen or auto-exclude. The user decides what to keep — your job
is to surface candidates clearly.
Phase 2: Add to Zotero
Once the user says which works to keep (e.g. "add 1, 3, and 7" or "add all"):
- Confirm Zotero is closed. Tell the user to quit Zotero completely before
you add anything — the script writes to the database file directly and will
refuse (exit code 2) while Zotero is open.
- Optionally dedup each candidate first with
uv run scripts/zotero_db.py find --doi <DOI> and skip ones already present.
For each kept work that has a DOI, fetch its Crossref record first
(api/crossref-reference.md) and prefer that clean publisher metadata,
falling back to OpenAlex for anything Crossref is missing.
- Build one JSON object per work from the (Crossref-enriched) metadata and add it with
uv run scripts/zotero_db.py add --json - (pipe the JSON on stdin), one call
per work so a single bad record can't sink the batch. Fields:
itemType — usually "journalArticle"; use "book", "bookSection",
"conferencePaper", "preprint", or "report" when the OpenAlex type
indicates it.
title; creators — array of {"firstName","lastName"} (split OpenAlex
author display names), or {"name"} for an organization, in author
order; date; DOI (bare); url; publicationTitle (venue); volume;
issue; pages; abstractNote; tags (optional); collection (the name
from Phase 0, if any).
The script prints a JSON result with the new item key (and any skipped_fields).
After the batch, confirm to the user how many were saved, list any failures, and
tell them they can reopen Zotero to see the new references. Then stop — capture
is done and the user drives what happens next.
Reminders
- The user is the expert on relevance. Present, don't pre-filter.
- Never fabricate a DOI or metadata. Add only what OpenAlex actually returns;
leave a field blank if it's missing rather than guessing.
- One work per
zotero_add call, so a single bad record doesn't sink the batch.
- This skill ends at capture. If the user later wants annotation or synthesis,
that's a separate task.
1---2name: lit-search-33description: Find scholarship on a topic via OpenAlex and Crossref and add the chosen works straight into the user's local Zotero library (by writing zotero.sqlite directly). Use when the user wants to search the literature and capture references (NOT to screen, annotate, or synthesize them). Adding items requires Zotero to be closed.4---56# Literature Search → Zotero78You help a researcher find relevant scholarship through the OpenAlex API and9save the works they choose directly into their **local Zotero library**. This10is a *search-and-capture* workflow: find candidate papers, let the user pick,11add them to Zotero. It does NOT screen, annotate, or synthesize — stop once the12references are in Zotero.1314## What you need1516- **OpenAlex** — free, no key required; best for discovery (search, citation17 networks, topics, OA links). See `api/openalex-reference.md`.18- **Crossref** — free, no key required; best for authoritative publisher19 metadata for a known DOI (clean author names, venue, volume/issue/pages, ISSN,20 funders). See `api/crossref-reference.md`, including its Crossref→Zotero field21 map. Use it to enrich a work before adding it to Zotero; fall back to OpenAlex22 values when Crossref lacks a field.23- **The local Zotero database.** This skill writes references straight into24 `zotero.sqlite` via `scripts/zotero_db.py`. Because it writes to the database25 file directly, **Zotero must be CLOSED while adding items** — the script26 refuses to write while Zotero is open (the DB is locked) and always takes a27 timestamped backup before its first write. New items appear the next time the28 user opens Zotero and are flagged unsynced so Zotero uploads them on sync.29 Default DB path is `~/Zotero/zotero.sqlite`; pass `--db <path>` if theirs30 differs.3132 All Zotero interaction is via the `bash` tool running that script:33 - `uv run scripts/zotero_db.py collections` — list collection names (read-only).34 - `uv run scripts/zotero_db.py find --doi <DOI>` — dedup check (read-only, safe35 while Zotero is open).36 - `uv run scripts/zotero_db.py add --json <file|->` — insert one item (needs37 Zotero closed).3839## Workflow4041### Phase 0: Scope4243Read `phases/phase0-scope.md` and follow it. Briefly: clarify the topic, develop44search terms (synonyms, field vocabulary), and set date/language/type filters.45Confirm the search strategy with the user before querying.4647Ask up front:48- **Topic** — a short description plus any specific terms the field uses.49- **Scope** — date range, particular journals or authors to prioritize, any50 methodological or geographic focus.51- **Which Zotero collection to file into** (optional). Run52 `uv run scripts/zotero_db.py collections` to list existing collection names,53 and confirm one with the user (or leave results in the library root). The54 chosen name is passed as `collection` in each item's JSON. The collection must55 already exist — the script won't create one.5657### Phase 1: Search5859Read `phases/phase1-search.md` and follow it. Run OpenAlex queries, retrieve60metadata (title, authors, year, journal, DOI, abstract, cited-by count),61deduplicate, and present the corpus to the user as a numbered list with year,62venue, and citation count so they can judge relevance at a glance.6364Do **not** auto-screen or auto-exclude. The user decides what to keep — your job65is to surface candidates clearly.6667### Phase 2: Add to Zotero6869Once the user says which works to keep (e.g. "add 1, 3, and 7" or "add all"):70711. **Confirm Zotero is closed.** Tell the user to quit Zotero completely before72 you add anything — the script writes to the database file directly and will73 refuse (exit code 2) while Zotero is open.742. **Optionally dedup** each candidate first with75 `uv run scripts/zotero_db.py find --doi <DOI>` and skip ones already present.76 For each kept work that has a DOI, fetch its Crossref record first77 (`api/crossref-reference.md`) and prefer that clean publisher metadata,78 falling back to OpenAlex for anything Crossref is missing.793. **Build one JSON object per work** from the (Crossref-enriched) metadata and add it with80 `uv run scripts/zotero_db.py add --json -` (pipe the JSON on stdin), one call81 per work so a single bad record can't sink the batch. Fields:82 - `itemType` — usually `"journalArticle"`; use `"book"`, `"bookSection"`,83 `"conferencePaper"`, `"preprint"`, or `"report"` when the OpenAlex `type`84 indicates it.85 - `title`; `creators` — array of `{"firstName","lastName"}` (split OpenAlex86 author display names), or `{"name"}` for an organization, **in author87 order**; `date`; `DOI` (bare); `url`; `publicationTitle` (venue); `volume`;88 `issue`; `pages`; `abstractNote`; `tags` (optional); `collection` (the name89 from Phase 0, if any).9091The script prints a JSON result with the new item `key` (and any `skipped_fields`).92After the batch, confirm to the user how many were saved, list any failures, and93tell them they can reopen Zotero to see the new references. Then stop — capture94is done and the user drives what happens next.9596## Reminders9798- **The user is the expert on relevance.** Present, don't pre-filter.99- **Never fabricate a DOI or metadata.** Add only what OpenAlex actually returns;100 leave a field blank if it's missing rather than guessing.101- **One work per `zotero_add` call**, so a single bad record doesn't sink the batch.102- This skill ends at capture. If the user later wants annotation or synthesis,103 that's a separate task.