Home
cd ../playbooks
Research & WritingIntermediate

Zotero from the Shell

Read and write a Zotero library entirely from the shell with zotero-cli — six search modes (items, semantic, tag, citekey, notes) picked correctly for the query, a find-keys-then-act-on-keys core loop, PDF annotation with a dry-run verification pass before writing, and the token-efficiency case for a CLI over an MCP server's always-loaded tool schemas.

5 minutes
By 54yyyu (zotero-mcp)Source
#zotero#research#citations#cli#academic-research#pdf-annotation

A Zotero MCP server's tool schemas cost real context on every single request whether you use them or not — a shell command costs only what you actually run, and for a researcher scripting through hundreds of papers in a session, that difference compounds fast.

Who it's for: researchers and academics managing citations and reading notes in Zotero via the command line, anyone scripting bulk operations across a Zotero library (tagging, collection filing, bibliography export), engineers choosing between a Zotero MCP server and a CLI tool for token-efficiency reasons, PDF-heavy researchers who need reliable page-range reading and figure/table/equation annotation

Example

"What does my Zotero library say about attention mechanisms in transformers?" → A semantic search (not exact keyword search) run first to catch conceptually related papers regardless of wording, results returned as compact keys, then targeted metadata or full-text page-range reads only for the papers that actually matter — instead of dumping every matching paper's full text into context

CLAUDE.md Template

New here? 3-minute setup guide → | Already set up? Copy the template below.

# Zotero from the Shell

Read and write a Zotero library from the shell with the `zotero-cli` command — search papers by keyword or meaning, read PDF full text and page ranges, get and set metadata, manage collections/tags/notes/annotations, add items by DOI/URL/ISBN, and export bibliographies. Use whenever the user asks about their Zotero library, references, citations, saved papers, or reading notes.

Prefer `zotero-cli` over a Zotero MCP server when shell access is available — an MCP server's tool schemas cost real context on every request whether or not they're used, while a CLI call costs only what's actually run.

## Setup Check

Before the first real call:

```bash
zotero-cli config          # prints the resolved Zotero settings
```

If that fails, Zotero isn't reachable. Local mode needs the Zotero desktop app running with its local API enabled; web mode needs `ZOTERO_API_KEY` and `ZOTERO_LIBRARY_ID`. Say so rather than guessing at library contents.

## Always Pass --json When You Will Read the Output

Default output is Markdown for humans. `--json` gives one object per invocation with a stable shape, so output never needs to be parsed from prose:

```json
{"ok": true, "command": "search", "schema": 1, "data": {...}}
{"ok": false, "command": "search", "schema": 1, "error": {"message": "...", "code": "..."}}
```

Both go to stdout; `[INFO]`/`[WARN]` diagnostics go to stderr. Check `ok` before using `data`. Run `zotero-cli --json-schema` for the full contract.

## The Core Loop: Find Keys, Then Act on Keys

Almost every task is: find keys, then act on them. Item keys are 8 characters and are the currency of every command.

```bash
# 1. find — use --detail keys_only to keep the result small while browsing
zotero-cli --json search "attention mechanisms" --limit 10 --detail keys_only

# 2. act — metadata, full text, or a page range
zotero-cli --json get metadata ABCD1234
zotero-cli --json get fulltext ABCD1234
zotero-cli --json read ABCD1234 --start-page 3 --end-page 8
```

Pipe keys straight into the next call:

```bash
zotero-cli --json search "diffusion models" --limit 5 --detail keys_only \
  | jq -r '.data.items[].key' \
  | while read -r key; do zotero-cli --json get metadata "$key"; done
```

## Choosing a Search Mode

| Mode | Use it for | Command |
|---|---|---|
| `items` (default) | A title, author, or phrase you already know | `search "Vaswani attention"` |
| `semantic` | A topic or idea, no exact wording | `search --mode semantic "why transformers scale"` |
| `tag` | Items filed under a tag | `search --mode tag "to-read,important"` |
| `advanced` | Structured field conditions | `search --mode advanced --conditions '[...]'` |
| `citekey` | A BibTeX citation key | `search --mode citekey smith2020` |
| `notes` | Text inside notes, not item fields | `search --mode notes "research question"` |

`semantic` needs the search index built (`zotero-cli db status` to check, `zotero-cli db update` to build). If the index is empty, fall back to `items` mode and say why, rather than reporting no results.

Every search covers one library — the active one. When you don't know which library holds something, or a search comes up empty and the item might be in a group library, add `--all-libraries`:

```bash
zotero-cli search "Cladder-Micus" --all-libraries
```

Each result is then labeled with its library name. This needs the SQLite backend (the local-mode default) and errors clearly if that's not in use — try it once and fall back to per-library searches if refused. Tag filters work with it; `--collection` does not, since a collection lives inside one library.

## Reading Efficiently

`get fulltext` on a book-length PDF returns a lot of text. When only one section is needed, use the outline to find it and read only those pages:

```bash
zotero-cli --json outline ABCD1234
zotero-cli --json read ABCD1234 --start-page 42 --end-page 55
```

For "what does my library say about X," prefer `search --mode semantic` followed by targeted `get metadata` calls over reading whole papers.

## Paging

Listings cap at `--limit`. When more exists, the response says so and names the next offset:

```bash
zotero-cli --json get collection-items QS7TQPPA --limit 100 --offset 100
```

Keep going until `data.count` is less than `--limit`.

## Writing

Write commands report what they did as text under `data.text`.

```bash
zotero-cli add doi 10.1038/s41586-021-03819-2 -c "Reading List"
zotero-cli edit ABCD1234 --title "Corrected Title" --add-tags reviewed
zotero-cli notes create --item-key ABCD1234 --text "Key finding: ..."
zotero-cli batch --item-keys A1B2C3D4,E5F6G7H8 --add-tags screened
```

`add` is idempotent by default — re-running it files the existing item into the named collection rather than creating a duplicate. Use `--if-exists skip` to never touch an existing item.

Before a destructive change (`delete`, `duplicates merge`, a `batch` over many items), confirm with the user and show what will be affected. `delete item` refuses to delete notes unless `--allow-note` is passed.

Writes in local mode need a one-time authorization step (Zotero 7 or newer) or web API credentials. A write refused for that reason will say so explicitly.

## Reading and Annotating a Paper

```bash
zotero-cli get children ITEM_KEY                          # the PDF's attachment key
zotero-cli read ITEM_KEY --start-page 1 --end-page 99     # end page clamps to the last page
zotero-cli path ATTACHMENT_KEY                            # the PDF file on disk
```

Extracted text is reliable for prose and unreliable for math, figures, and tables — symbols drop out and table cells run together. `read` flags each page where that happens ("Garbled in this text: Equation (1), Table 2"). For those pages, view the page itself as an image:

```bash
zotero-cli read ITEM_KEY --start-page 4 --format image                              # PNG per page, up to 10
zotero-cli read ITEM_KEY --start-page 4 --format image --rect 0.35,0.49,0.3,0.05    # zoom into one region
```

To annotate: plan everything, check it, then write it in one run.

1. `zotero-cli --json layout ATTACHMENT_KEY` lists figure, table, and equation boxes with their captions and a paste-ready `rect` argument.
2. Write one JSON object per line: `{"page": 4, "text": "exact words", "comment": "...", "color": "yellow"}` for a highlight, or `{"page": 3, "rect": "x,y,w,h", "comment": "..."}` for a box. Copy highlight text exactly from `read` output — it's matched against that page and two pages either side.
3. `zotero-cli annotations batch --attachment-key ATTACHMENT_KEY --file plan.jsonl --dry-run` shows the words each highlight would cover. Fix every miss before proceeding.
4. Run it again without `--dry-run`. Anything that didn't land is listed under `data.results` with `ok: false`, and the exit code is 1.

Colors follow Zotero's names: yellow, red, green, blue, purple, magenta, orange, gray. Three or four colors with fixed meanings read better than eight — record what each one means in a note on the item.

## When Something Looks Wrong

- **Empty search results**: check `zotero-cli config` and, for semantic mode, `zotero-cli db status`. Don't report "you have no papers on X" until the library is confirmed reachable and indexed.
- **`ok: false`**: read `error.message` — it names the cause directly.
- **A partial-results note on a search** means the scan was cut short, not that nothing else matched — narrow the query and re-run.
- **An item marked `"deleted": true`** is in the trash. Don't treat it as part of the live library.

## Full Command Reference

`zotero-cli <command> --help` covers any command not shown above.

Get new playbooks like this one

One email a week with new Claude Code workflows. Free, like everything here.

No spam. Unsubscribe anytime.

README.md

What This Does

A complete working reference for zotero-cli, a shell command that reads and writes a Zotero library directly — chosen deliberately over a Zotero MCP server when shell access is available, since an MCP server's tool schemas load into context on every request regardless of use, while a CLI invocation costs only what actually runs. The core pattern is find-keys-then-act-on-keys: every search returns compact 8-character item keys (kept small with --detail keys_only while browsing), which then feed directly into metadata, full-text, or page-range reads, and pipe cleanly into a loop for bulk operations. Six distinct search modes get picked by what's actually known — exact-phrase items search when the title or author is known, semantic search when only the idea or topic is known (built on a search index that needs a one-time build check), tag, citekey, and notes modes for their specific narrower cases — with an explicit warning against reporting empty results as "you have no papers on X" before confirming the library is actually reachable and, for semantic search, actually indexed.

The PDF-handling section is unusually thorough: it flags exactly where extracted text becomes unreliable (math, figures, and tables — symbols drop out, table cells run together) and gives the fallback (render the specific page as an image, optionally zoomed to one region) rather than pretending full-text extraction always works. Annotation follows a deliberate plan-check-write sequence — list figure/table/equation boxes with paste-ready coordinates, write highlight/comment instructions as JSON, dry-run the batch to see exactly which words each highlight would actually cover, fix every miss, then commit for real — which catches the common failure of a highlight silently landing on the wrong text before it's permanently written to the library.


Quick Start

Step 1: Create a Project Folder

mkdir zotero-workspace && cd zotero-workspace

Step 2: Download the Template

Click Download above, then:

mv ~/Downloads/CLAUDE.md ./

Step 3: Work With Your Library

claude

Ask about papers in your Zotero library, request a search by topic or exact title, or ask to read, annotate, or tag specific items. Claude will pick the right search mode for the query, use --json output for reliable parsing, and follow the find-keys-then-act-on-keys pattern for anything requiring multiple items.


Tips & Best Practices

  • Always run zotero-cli config (and db status for semantic search) before reporting empty results as "nothing found" — an unreachable library or an unbuilt search index produces the same empty-looking result as a genuine no-match, and conflating them gives the user wrong information.
  • Use --detail keys_only while browsing search results and only fetch full metadata or text for the specific items that matter — this is both faster and keeps output manageable across a large library.
  • For annotation specifically, never skip the --dry-run pass — verifying which exact words a highlight will cover before writing it permanently is the difference between a clean annotation and one that has to be manually cleaned up in the Zotero app afterward.

Limitations

  • Requires zotero-cli installed and either the Zotero desktop app running with its local API enabled, or web API credentials configured — without one of those, zotero-cli config will fail and nothing else in this workflow works.
  • Semantic search specifically depends on a built search index; a fresh Zotero library or one that hasn't run db update will silently have no semantic results until that index exists.
  • PDF text extraction has known, flagged unreliability for math notation, figures, and tables — treat those specific pages' extracted text as a lead to verify visually via the image-rendering fallback, not as ground truth.

$Related Playbooks

Research & Writing

Meeting Insights Analyzer

Analyze meeting transcripts to reveal communication patterns, behavioral tendencies, and leadership effectiveness with timestamped feedback.

10 minutes
Intermediate
Research & Writing

Writing Enhancement Coach

Get iterative feedback on outlines, research assistance, and section-by-section writing guidance for articles and essays.

5 minutes
Beginner
Research & Writing

Business Document Generator

Create professional business documents including project proposals, business plans, and annual budgets from templates.

5 minutes
Beginner
Research & Writing

AI Writing Pattern Remover

Audit and rewrite content to remove AI-isms that make text sound machine-generated

5 minutes
Beginner
Research & Writing

Article Writing Pipeline — From Idea to Published Draft

Turn scattered blog ideas into polished articles with a structured writing pipeline. Score angles, build SEO outlines, and generate first drafts — all saved as files you can edit and publish.

5 minutes
Beginner
Research & Writing

Bulk Document Synthesizer

Convert large collections of PDFs and documents into markdown, analyze them against a relevance matrix, and synthesize findings into a cohesive narrative report with citations.

10 minutes
Intermediate
Research & Writing

Deep Research Assistant

Conduct comprehensive research on any topic. Synthesize information from multiple angles, provide structured analysis, and generate detailed research reports.

10 minutes
Advanced
Research & Writing

Content Research Writer

Collaborative writing assistant for outlining, research, citations, and section-by-section feedback on articles, blogs, and technical content.

5 minutes
Beginner
Research & Writing

Critic Agent

Make Claude self-correct its own writing by spinning up an internal critic that reviews drafts against your voice and style rules — up to 3 rounds, no manual editing needed.

10 minutes
Intermediate
Research & Writing

Humanizer

Remove AI writing patterns from any text to make it sound natural, specific, and human.

5 minutes
Beginner
Research & Writing

Fact Checker

Verify claims against multiple sources, assess accuracy with confidence scores, detect bias, cross-reference evidence, and produce structured verification reports.

10 minutes
Intermediate
Research & Writing

Literature Review Builder

Track papers with methodology and findings, group by theme, and draft a narrative literature review organized by insight rather than by source.

10 minutes
Advanced

Browse all Research & Writing playbooks →