Annotator Explorer Companion
approvedby Charles Zhao Changlin
Right-click a PDF or EPUB to create its Annotator note and open it in annotation view in one step. - This plugin has not been manually reviewed by Obsidian staff.
Annotator Explorer Companion
Built on Annotator by Elias Sundqvist. Annotator does the real work: it brings Hypothesis into Obsidian and keeps every highlight as plain markdown in your own vault instead of on someone else's server. Thanks to Elias for building and maintaining it.
This plugin adds one thing on top. Right-click a PDF or EPUB, choose Annotate, and you land in the reader ready to highlight. Install Annotator first, since nothing here runs without it.
What it replaces
Annotator keeps highlights in a markdown note that points at the document. Writing that note by hand means creating a file beside the PDF, typing its vault-relative path into YAML frontmatter without typos, opening the note, then switching views through the top-right menu. This plugin does all of that from one right-click.
Why I wrote it
I was reading through a folder of research papers and kept hitting the same friction.
Annotator needs a note whose frontmatter carries annotation-target, and nothing in the
interface tells you so. Right-clicking a PDF offers nothing about annotation. Opening one
gives you Obsidian's ordinary PDF viewer with no way in. The reason is in Annotator's
source, where its own menu handler is gated three ways:
leaf?.view instanceof MarkdownView // an open note, not a file in the explorer
&& file instanceof TFile
&& this.getPropertyValue("annotation-target", file) // which already has the field
The item only shows up on notes that are already configured, so it can never get you started from a PDF.
Worse, getting the note slightly wrong produces a blank pane and no error. My first attempt used a code fence instead of frontmatter, backticks where dashes belong, and Annotator saw no target at all. At least six different mistakes produce that same blank pane:
| Cause | Why it fails |
|---|---|
Code fence instead of --- | Field never parsed |
:: inside YAML frontmatter | Frontmatter takes one colon; :: is a Dataview body field |
| Leading slash on the path | Not resolvable from the vault root |
Doubled extension (.pdf.pdf) | Path does not match the file on disk |
| Missing or misleading extension | Wrong reader selected |
| Source renamed after annotating | Highlights resolve by path and are orphaned |
Generating the frontmatter removes that whole category of mistake. And once you are doing this for twenty papers rather than one, the repetition is reason enough on its own.
The bug that took longest to find
Version 1.0.0 created the note correctly and still opened it as plain markdown, so you had to visit the top-right menu anyway. Half the point was missing.
Annotator ships annotationModeByDefault: true and patches setViewState to redirect
qualifying notes into its own view. The patch gates on getPropertyValue, which reads
Obsidian's metadata cache. Obsidian parses frontmatter asynchronously, so a note written
and opened in the same tick is not in that cache yet. The check comes back undefined and
the note opens as markdown.
That mechanism is fine for notes that already exist, which is why it looked correct when I first read the source. It only fails on freshly created files, and those are the only kind this plugin makes.
The fix has two parts. waitForTargetField polls the metadata cache every 25 ms, up to
two seconds, before opening the note, so Annotator's own auto-switch fires normally.
ensureAnnotationView then checks the leaf and, if it somehow came back as markdown,
asks for type: "pdf-annotator" directly. Annotator's patch only intercepts
type: "markdown", so that request passes straight through to the registered view.
If the cache never populates, the note still opens and a notice points you at the manual menu.
Why a separate plugin
Annotator ships minified, so patching it directly would be unreviewable and the next update would overwrite the change. Registering a second menu handler leaves Annotator alone and keeps this code readable.
Safety
Annotation data is painful to reconstruct, so the plugin will not destroy it.
An existing note is opened rather than overwritten. A note containing annotation-json
is never modified, even when its frontmatter looks incomplete. If a same-named note
exists for unrelated reasons, only the field is added through processFrontMatter and
the body is left alone. Paths are quoted and escaped so a title containing : or "
cannot corrupt the YAML. Each of these has a test behind it.
Installing
Search for Annotator Explorer Companion under Settings, Community plugins, Browse.
To install by hand, download main.js and manifest.json from the
latest release
into <vault>/.obsidian/plugins/annotator-explorer-companion/ and enable it under
Community plugins.
Release assets carry GitHub artifact attestations, so you can verify they were built from this repository:
gh attestation verify main.js --repo ZharlieSineFine/annotator-explorer-companion
Development
Plain JavaScript, no build step. Edit main.js and reload Obsidian.
node --test test.js
Twelve tests cover menu registration, note creation, the metadata-cache race, view
switching, and every safety rule above. The suite stubs the obsidian module, so it runs
without Obsidian installed.
Undocumented APIs
Two Obsidian internals are used here, both guarded with optional chaining and a fallback.
app.plugins.plugins and app.plugins.enabledPlugins check whether Annotator is active,
and if the registry cannot be read the plugin proceeds instead of blocking.
pdfAnnotatorFileModes on the Annotator instance is written only on the fallback path,
to keep Annotator's own mode tracking consistent.
Neither is part of Obsidian's public API and either could break in a future release. When that happens the plugin opens the note in markdown rather than failing outright.
Limitations
Annotator does not run on iOS 16.3 or later, so this does not either. Annotations made on
iOS will not match ones made on desktop, because iOS percent-encodes spaces in annotation
URIs and desktop does not (see
issue #89). Notes are
always created beside their source file, with no setting to change that yet. Remote
https:// targets have no file to right-click and still need a note written by hand.
Credits and license
Annotator by Elias Sundqvist, building on Hypothesis. All annotation functionality is theirs. This is an unaffiliated companion and is not endorsed by the Annotator project.
MIT.
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.