pi-zotero-web
Zotero Web API integration for pi: CRUD on items + PDFs, library search, tags & collections, citation export, full-text, duplicate detection on create, and /login zotero key management.
Package details
Install pi-zotero-web from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-zotero-web- Package
pi-zotero-web- Version
0.2.2- Published
- Sep 2, 2026
- Downloads
- 948/mo · 200/wk
- Author
- kentaroh-toyoda
- License
- MIT
- Types
- extension
- Size
- 64.2 KB
- Dependencies
- 0 dependencies · 3 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-zotero-web
Zotero integration for pi via the Zotero Web API.
- CRUD on paper metadata + PDFs — create, read, update, delete items and attachments; upload/download PDF files (full 4-step Zotero file upload flow).
- Library search — keyword, title/author/year, and full-text (
qmode=everything) search. - Tags & collections — manage tags, list/create/rename/delete collections, and move items in/out of collections.
- Citation export — export items as BibTeX, BibLaTeX, CSL JSON, RIS, CSV, MODS, COinS, bookmarks, or a formatted bibliography.
- Schema & full-text — read the item-type/field/creator schema, and get/set extracted full-text content for attachments (enables headless full-text search).
- API key management via
/login zotero— the key (and resolved user id) are stored in~/.pi/agent/auth.json; the login re-prompts up to 3 times on a rejected key;/logout zoteroremoves it.
Requirements
- A Zotero account with a personal library.
- A Zotero API key created at https://www.zotero.org/settings/keys with Allow library access and Allow file access (write access is needed for create/update/delete/upload).
Install
Install the published npm package (writes to ~/.pi/agent/settings.json):
pi install npm:pi-zotero-web
# or pin a version:
pi install npm:pi-zotero-web@0.2.2
Add -l to install into project settings (.pi/settings.json) instead of user settings.
Alternatively, test it from a checkout without installing:
pi -e ./index.ts
Configure
Run /login zotero and paste your Zotero API key. It is verified against /keys/current and stored (with your user id) in ~/.pi/agent/auth.json:
{
"zotero": {
"type": "api_key",
"key": "<your-key>",
"env": { "ZOTERO_USER_ID": "12345" }
}
}
To use a group library instead of your personal library, add "ZOTERO_GROUP_ID": "<group-id>" under env.
Remove the stored key with /logout zotero.
Tools
All tools are registered for the agent to call automatically. You can also prompt for them directly (e.g. "Search my Zotero library for papers on diffusion policies").
| Tool | Actions / params | Description |
|---|---|---|
zotero_search |
q, qmode, itemType, collectionKey, tag, limit, top |
Search the library. qmode=everything includes full text. Returns key/version/metadata. |
zotero_item |
action=get|create|update|delete, itemKey, version, item, forceCreate |
CRUD on an item. Use the version returned by search/get for update/delete. On create, the library is first searched for an existing item with the same DOI (or title + first author); a match is returned with duplicate:true instead of creating. Pass forceCreate:true to bypass. |
zotero_template |
itemType, linkMode |
Fetch an item template to build valid create/update payloads. |
zotero_attachment |
action=list|upload|download|delete, itemKey/parentKey, filePath, version, title, contentType |
Manage PDF/attachment files. Upload reads a local file; download writes to a local path. |
zotero_tags |
action=list|get|set, itemKey, version, tags, limit |
List library tags or tags on an item, or replace an item's full tags array (tags: [{tag, type:0|1}], type 0=manual, 1=automatic). |
zotero_collection |
action=list|get|items|create|rename|delete|add|remove, collectionKey, parentKey, name, version, itemKeys/items, top, limit |
Manage collections (folders): list/get/create/rename/delete, list items in a collection, and add/remove items to/from a collection (requires each item's current version + collections). |
zotero_export |
format, itemKeys, collectionKey |
Export items as BibTeX, BibLaTeX, CSL JSON, RIS, CSV, MODS, COinS, bookmarks, or a formatted bibliography (bib). Select by itemKeys or a collectionKey. |
zotero_schema |
action=itemTypes|itemFields|itemTypeFields|creatorTypes|creatorFields, itemType |
Read-only access to Zotero's item-type schema (public endpoints, no auth) so the agent can build valid create payloads for exotic types. |
zotero_fulltext |
action=get|set, itemKey, content, indexedChars/totalChars or indexedPages/totalPages |
Get or set extracted full-text content for an attachment, enabling qmode=everything search without the desktop client. |
Typical workflows
Create a paper from a DOI/metadata:
zotero_template(orzotero_schemafor exotic types) → base object.- Fill
title,creators,abstractNote,DOI,date, etc. (the agent can fetch these from the web). zotero_itemwithaction=create, passing the filled item.
Duplicate detection.
createchecks the library for an existing item matching the new one (by DOI, then by normalized title + first author) and returns the existing entry withduplicate:trueinstead of creating a second copy. PassforceCreate:trueto always create. Batches (an array of items) always create without dedup to avoid ambiguous matches.
Attach a PDF to an existing item:
zotero_attachmentwithaction=upload,parentKey=<itemKey>,filePath=/path/to/paper.pdf.
Download a PDF:
zotero_attachmentwithaction=download,itemKey=<attachmentKey>,filePath=./paper.pdf.
Organize and export:
zotero_collectionaction=create→ new collection;action=addto file items into it (pass each item's currentversion+collections).zotero_exportwithformat=bibtex,collectionKey=<key>→ BibTeX for the whole collection.
Make an uploaded PDF searchable headlessly:
- Extract text locally (e.g. via a PDF tool), then
zotero_fulltextaction=setwithcontent+indexedChars/totalChars(text) orindexedPages/totalPages(PDF). Nowzotero_searchwithqmode=everythingwill find it.
Testing
Unit tests use Node's built-in test runner with a mocked fetch (no real network):
npm test
The pi host packages (@earendil-works/pi-coding-agent, @earendil-works/pi-ai, typebox) are provided by pi at runtime. For tests, they're symlinked into node_modules/@earendil-works* from the global pi install. If you move this checkout, re-create those symlinks (or npm install a local pi-coding-agent).
How it works
provider.tsregisters a native pi-aiProvidernamedzoterothat declares no LLM models (so it never appears in/model). Its only purpose is authentication:/login zoteroruns the provider'sapiKey.loginflow, which verifies the key and stores it.- Tools read the stored credential via
ctx.modelRegistry.getProviderAuth("zotero")and call the Zotero Web API (https://api.zotero.org) with theZotero-API-Keyheader. - File upload implements Zotero's full 4-step flow (create attachment item → upload authorization → S3
prefix+file+suffixPOST → register upload).
License
MIT