## Implement: biblio zotero push-tags — write enrichments back to Zotero Phase
Implement: biblio zotero push-tags — write enrichments back to Zotero¶
Phase 3 of the pool ecosystem spec (docs/specs/biblio/pool-ecosystem.md).
What¶
Add biblio zotero push-tags command and MCP tool that writes biblio enrichments (tags, notes, resolved metadata) back to Zotero items via the API.
Dependencies¶
- pyzotero (same as zotero pull)
- Zotero API write permissions (API key must have write access)
- Items must have been pulled from Zotero originally (need item key mapping)
Behavior¶
# Push all enriched tags back to Zotero
biblio zotero push-tags
# Push tags for specific papers
biblio zotero push-tags --citekeys smith2024,doe2023
# Push from a specific project's library.yml
biblio zotero push-tags --source pixecog
# Push new papers (ingested via OpenAlex) to Zotero
biblio zotero push --new
What gets pushed back¶
| biblio enrichment | Zotero target | Example |
|---|---|---|
| autotag tags | Zotero tags | method:place-cells, domain:hippocampus |
| concept categories | Zotero tags (prefixed) | concept:sharp-wave-ripple |
| reading status | Zotero tag | status:reading, status:cited |
| LLM summary | Zotero note (child item) | Structured summary as HTML note |
| Resolved DOI | Zotero Extra field | If DOI was missing in Zotero |
| OpenAlex ID | Zotero Extra field | OpenAlex: W1234567890 |
Implementation¶
- Push logic —
packages/biblio/src/biblio/zotero_sync.py(extend) push_tags(citekeys, zotero_client)— read library.yml, map to Zotero tags, update itemspush_notes(citekeys, zotero_client)— create/update child note items with summaries-
push_new_items(citekeys, zotero_client)— create new Zotero items from biblio BibTeX -
Citekey ↔ Zotero item key mapping
- Maintained in
.projio/biblio/zotero-sync.yml - Built during
zotero pull, updated duringzotero push -
Falls back to DOI matching if citekey mapping missing
-
Conflict detection
- Check item version before writing (Zotero uses version numbers)
-
If item was modified in Zotero since last sync, warn and skip (or force with --force)
-
MCP tool:
def biblio_zotero_push( citekeys: list[str] | None = None, push_tags: bool = True, push_notes: bool = False, push_new: bool = False, force: bool = False, ) -> dict # {"updated": N, "created": N, "conflicts": [...], "errors": [...]}
Key files¶
packages/biblio/src/biblio/zotero_sync.py— extend from pull implementationpackages/biblio/src/biblio/library.py— read tags/statuspackages/biblio/src/biblio/autotag.py— read autotag resultspackages/biblio/src/biblio/concepts.py— read concept resultspackages/biblio/src/biblio/summarize.py— read summaries
Related Notes¶
- issue-arash-20260403-210002-675833.md — Companion issue: zotero pull is the prerequisite for push-tags (items must be pulled first)
- issue-arash-20260403-201609-055675.md — Parent spec defining the biblio ↔ Zotero integration model this tool implements
- issue-arash-20260403-205942-590539.md — Related pool ecosystem phase — both are parts of the pool-ecosystem spec
- issue-arash-20260403-193112-105596.md — Enrichment pipeline redesign directly feeds what gets pushed back to Zotero