zotero-plugin

Build, debug, and release Zotero 7-9 plugins using classic bootstrap or TypeScript toolkit stacks.

Updated Apr 18, 2026
One-click install
npx skills add https://github.com/ppavlidis/skillz --skill zotero-plugin-ppavlidis
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: zotero-plugin
Source: https://github.com/ppavlidis/skillz/tree/main/skills/zotero-plugin
Command: npx skills add https://github.com/ppavlidis/skillz --skill zotero-plugin-ppavlidis

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve? Zotero plugin development involves undocumented pitfalls—silent timer failures, React re-renders stripping injected UI, missing update URLs—that cause hours of debugging. This Skill encodes production-tested patterns for the full plugin lifecycle so these failures are avoided from the start. ## Core Features & Use Cases - Two-stack guidance: Covers both the classic bootstrapped stack (bootstrap.js + plain JS + manifest.json) and the TypeScript stack (zotero-plugin-scaffold + zotero-plugin-toolkit), with detection rules for existing repos. - Lifecycle and UI patterns: Startup promise sequencing, per-window add/remove tracking, XUL menu injection, ProgressWindow notifications, Notifier observers, MutationObserver re-injection, and preference panes with Fluent localization. - Build and release: XPI packaging, updates.json auto-update wiring, and GitHub release tagging. - Use Case: You want to add a context-menu item that finds PDFs for selected Zotero items. The Skill provides the manifest fields, bootstrap lifecycle, menu injection code, HTTP probing with magic-byte PDF verification, and release steps. ## Quick Start Help me create a Zotero plugin that adds a Tools menu item and shows a ProgressWindow notification when clicked.

Frequently Asked Questions about zotero-plugin

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I create a Zotero plugin from scratch?

Choose between the classic bootstrapped stack (bootstrap.js, plain JS, manifest.json, no build step) or the TypeScript toolkit stack (zotero-plugin-scaffold with hot reload and typed prefs). Then implement the startup lifecycle, inject UI per window, and package an XPI with an updates.json for auto-updates.

Classic bootstrap vs zotero-plugin-scaffold: which should I use?

Use classic bootstrap for small plugins with one feature and no build step. Use the toolkit stack when the plugin exceeds roughly 500 lines, needs typed preferences via zotero-types, Fluent localization, or a dev server with hot reload.

Why is my Zotero plugin not loading or updating?

Zotero silently ignores plugins whose manifest.json lacks an update_url, and installed plugins never update without an updates.json entry pointing to the GitHub release download URL. Also verify the plugin ID is in email format and strict_max_version covers your Zotero version.

Why does my injected UI disappear from the Zotero tab bar?

The tab bar is React-rendered, so re-renders strip injected elements. Use a MutationObserver that watches for removal, debounces, disconnects before re-injecting, and reconnects after—otherwise re-injection triggers the observer again in an infinite loop.

Does Zotero.setTimeout exist for scheduling plugin tasks?

No, Zotero.setTimeout does not exist and calling it fails silently, leaving timers that never fire. Use the plain window setTimeout and clearTimeout functions instead.

How do I add a preference pane to a Zotero plugin?

Register an XHTML pane at startup with Zotero.PreferencePanes.register, passing pluginID, src, label, and icon. Wire checkbox listeners in a load handler that read and write via Zotero.Prefs with the extensions branch scoped by the trailing true argument.