# Zotero Org Export Annotations Export PDF and EPUB annotations from Zotero to Org-mode files for use with Emacs, org-roam, and citar. ## Features - Export annotations to individual Org files named by citation key - Automatic export after Zotero sync completes - Export when closing a PDF/EPUB reader tab - Configurable output directory - Optional attachment of Org files to Zotero items ## Requirements - **[Zotero](https://www.zotero.org/) 7.0+** - **[Better Notes](https://github.com/windingwind/zotero-better-notes)** plugin — must be installed before this plugin - **[Pandoc](https://pandoc.org/)** — for Markdown to Org conversion ## Installation 1. Install the **Better Notes** plugin first (see its own instructions) 2. Install **Pandoc** and ensure it is on your `PATH` (or note its full path) 3. Download the latest `.xpi` file from [Releases](../../releases) 4. In Zotero, go to **Tools → Add-ons** 5. Click the gear icon (top-right) and select **Install Add-on From File...** 6. Select the downloaded `.xpi` file and restart Zotero if prompted ## Configuration After installation, open **Tools → Org Export Preferences** to configure: | Preference | Default | Description | | ----------------------- | --------- | --------------------------------------------------------------- | | Notes Directory | _(empty)_ | Directory where Org files will be saved. Supports `~` for home. | | Pandoc Path | `pandoc` | Full path to the pandoc binary if not on `PATH` | | Attach Org file to item | `false` | Link exported Org files as Zotero attachments | | Auto-export on sync | `true` | Export automatically after Zotero sync completes | | Export on tab close | `true` | Export when closing a PDF/EPUB reader tab | | Show notifications | `true` | Display a progress notification during export | | Debug mode | `false` | Enable verbose logging to the Zotero error console | ## Usage ### Manual Export - **Export all items**: **Tools → Export All Annotations to Org** - **Export selected items**: Right-click one or more items → **Export Annotations to Org** ### Automatic Export When enabled in preferences, exports happen automatically: - After a Zotero sync completes (only items with new/changed annotations are exported) - When you close a PDF or EPUB reader tab ### Output Format Files are written to the configured Notes Directory, named by citation key: ``` ~/org/notes/smith2020.org ~/org/notes/doe2019.org ``` Each file contains: ```org #+title: The Full Title of the Referenced Work * Annotation heading Converted annotation text... ``` Only items that have a citation key (via Better BibTeX or the `citationKey` field) will be exported. ## For Maintainers This section covers building, developing, and releasing the plugin. ### Architecture ``` src/ ├── index.ts # Entry point: mounts addon to Zotero global ├── addon.ts # Core addon class (logging, init, module wiring) ├── hooks.ts # Lifecycle hooks (startup/shutdown, menu actions) └── modules/ ├── prefs.ts # Typed read/write for all preferences ├── exporter.ts # Attachment detection, sync checking, batch export ├── converter.ts # Markdown → Org via pandoc, file I/O ├── notifier.ts # Zotero event handlers (sync finish, tab close) └── menu.ts # Menu registration (Zotero 7 + 8 compatible) addon/ # Static plugin files copied verbatim into the XPI ├── manifest.json ├── bootstrap.js # Zotero plugin lifecycle entry point ├── prefs.js # Default preference values └── content/ ├── preferences.xhtml # Preferences pane UI (XUL) ├── scripts/preferences.js ├── icons/ └── locale/en-US/ # Fluent (.ftl) string bundles ``` The build system uses [zotero-plugin-scaffold](https://github.com/windingwind/zotero-plugin-scaffold) with esbuild, which bundles `src/` into a single `index.js` and packages everything as an XPI. ### Prerequisites **With Nix (recommended):** ```bash # Requires Nix with flakes enabled nix develop ``` This provides Node.js 20, npm, TypeScript, ESLint, Prettier, and Pandoc. **Without Nix:** - Node.js 20+ - npm - Pandoc (for manual testing) ```bash npm install ``` ### Environment Setup Copy the environment template and fill in your local paths: ```bash cp .env.example .env ``` Edit `.env`: ```bash # Path to the Zotero binary (required for the dev server) ZOTERO_PLUGIN_ZOTERO_BIN_PATH=/path/to/zotero # Path to a Zotero development profile directory ZOTERO_PLUGIN_PROFILE_PATH=/path/to/zotero-dev-profile ``` Create a dedicated Zotero profile for development to avoid affecting your main library. ### Development Workflow ```bash # Start the dev server — builds and hot-reloads the plugin into a running Zotero instance npm start # One-off build — outputs XPI to .scaffold/build/ npm run build # Lint TypeScript source npm run lint npm run lint:fix # auto-fix # Format source files npm run format npm run format:check # check without writing ``` The dev server (`npm start`) watches for changes in `src/` and `addon/`, rebuilds, and reloads the plugin inside Zotero automatically. Zotero must already be running with the configured profile. ### Testing There are no automated tests. To test manually: 1. `npm run build` to produce the XPI 2. Install the XPI in a Zotero 7 instance via **Tools → Add-ons → Install Add-on From File...** 3. Exercise the export functionality manually via the Tools menu and right-click context menu ### Releasing Releases are created by pushing a version tag. The CI/CD pipeline (Gitea Actions) will build the XPI and publish a release automatically. To cut a release locally: ```bash npm run release ``` This runs [bumpp](https://github.com/antfu/bumpp) interactively to select the new version, then: 1. Updates `package.json` version 2. Commits and tags the version 3. Pushes the commit and tag to the remote 4. Builds the XPI Once the tag is pushed, Gitea Actions takes over and creates the release with the XPI attached. ### Code Style - **Formatter**: Prettier (config in `.prettierrc`) — double quotes, 2-space indent, semicolons - **Linter**: ESLint with TypeScript-ESLint (config in `.eslintrc.js`) — strict mode - **Naming**: PascalCase for classes/types, camelCase for functions/methods, UPPER_SNAKE_CASE for constants - **Imports**: relative paths, `import type` for type-only imports, no namespace imports - **Error handling**: always catch with a typed `error as Error`; use `_error` for non-critical ignores See `AGENTS.md` for the full style guide used during AI-assisted development. ## License GPL-3.0-or-later ## Credits Based on the [zotero-plugin-template](https://github.com/windingwind/zotero-plugin-template) by windingwind.