Follow @plannotator on X for updates
Missed recent releases?
| Release | Highlights |
|---|---|
| v0.17.10 | HTML and URL annotation, loopback binding by default, Safari scroll fix, triple-click fix, release pipeline smoke tests |
| v0.17.9 | Hotfix: pin Bun to 1.3.11 for macOS binary codesign regression |
| v0.17.8 | Configurable default diff type, close button for sessions, annotate data loss fix, markdown rendering polish |
| v0.17.7 | Fix "fetch did not return a Response" error in OpenCode web/serve modes |
| v0.17.6 | Bun.serve error handlers for diagnostic 500 responses, install.cmd cache fix |
| v0.17.5 | Fix VCS detection crash when p4 not installed, install script cache path fix |
| v0.17.4 | Vault browser merged into Files tab, Kanagawa themes, Pi idle session tool fix |
| v0.17.3 | Sticky lane repo/branch badge overflow fix |
| v0.17.2 | Supply-chain hardening, sticky toolstrip and badges, overlay scrollbars, external annotation highlighting, Conventional Comments |
| v0.17.1 | Pi PR review parity, parseRemoteUrl rewrite, cross-repo clone fixes, diff viewer flash fix |
| v0.17.0 | AI code review agents, token-level annotation, merge-base diffs |
| v0.16.7 | Gemini CLI plan review, install script skills directory fix |
What's New in v0.18.0
v0.18.0 adds focus & wide modes for annotate, first-class OpenCode detection, word-level inline plan diffs, content negotiation for URLs that publish Markdown (via Cloudflare), and inline color swatches in the plan viewer. 13 PRs, 7 from external contributors — 6 of them first-timers.
Word-Level Inline Plan Diff
The old plan diff stacked the full old block above the full new block whenever a paragraph was modified. A single word change showed the same paragraph twice with no visual cue to where the edit actually happened. Readers ended up comparing two nearly identical blocks line by line to find the delta.
The new default Rendered mode performs a second-pass word diff on modified blocks and highlights only the changed tokens inline. A one-word reword now reads as a single paragraph with <ins> and <del> markers on exactly the changed words. Inline code spans, markdown links, and fenced code blocks are preserved as atomic units through a sentinel substitution pass, so diff markers can't split them.
A third mode switcher tab, "Classic," keeps the legacy block-level stacked rendering for users who prefer it. Raw git-style output is unchanged. Modified blocks are click-to-annotate directly, with both the old and new content captured in the exported feedback so comments on struck-through words keep their context.
Amber borders on modified blocks complete the green/red/yellow convention used by GitHub and VS Code.
- #565 by @backnotprop, closing #560 requested by @pbowyer
Wide and Focus Modes
Wide markdown tables were unreadable because both side panels (TOC on the left, annotations on the right) stayed fixed while the reader width was capped. Tables wrapped awkwardly or required horizontal scrolling inside a narrow column.
Two new toggles sit above the document and next to the lightning-bolt action:
- Wide hides both panels and removes the reader width cap. Wide tables and code fences get the full document area.
- Focus hides both panels but keeps the normal reader width. Distraction-free reading without stretching the content.
Enabling either mode collapses the left sidebar, hides the annotations panel and resize handle, and toggles the width cap accordingly. Exiting restores the exact previous layout, including which sidebar tab was open. Opening any sidebar or annotations panel automatically exits.
Available in plan review, annotate, and linked-doc overlays. Archive mode and plan-diff view keep the standard layout.
- #578 by @dgrissen2
First-Class OpenCode Detection
The origin detection chain in the hook server didn't include OpenCode. Every OpenCode invocation fell through to the claude-code default, which loaded the wrong UI variant: missing agent-switch toggle, wrong agent badge. The opencode origin key was already defined in AGENT_CONFIG with its badge styling in place, but the detection side was never wired up.
OpenCode is now detected via OPENCODE=1, the canonical runtime flag set unconditionally by the OpenCode binary. The full priority order is:
PLANNOTATOR_ORIGIN > Codex > Copilot CLI > OpenCode > Claude Code (default)
The PLANNOTATOR_ORIGIN environment variable was documented in the source but never read. It now functions as an explicit override at the top of the chain, validated against AGENT_CONFIG so invalid values fall through to env-based detection instead of breaking.
Content Negotiation for Markdown-Serving URLs
When you run plannotator annotate https://..., the tool goes through Jina Reader (or Turndown as a fallback) to convert HTML to markdown. But a growing number of sites — including Cloudflare's developer docs — now publish Markdown directly when you ask for it. Routing those through an HTML-to-markdown converter is wasteful and loses fidelity.
URL annotation now tries Accept: text/markdown, text/html;q=0.9 first, with a 5-second timeout. If the server returns content-type: text/markdown, the response is used directly — one fetch, no conversion. If the server returns HTML or the request fails, it falls through silently to the existing Jina/Turndown pipeline. Local URLs skip negotiation entirely.
A new content-negotiation source type is recorded on the result so the UI can indicate which path produced the content.
- #557 by @backnotprop
Hex Color Swatches in the Plan Viewer
Frontend plans reference hex color values constantly — design tokens, Tailwind overrides, CSS variable assignments, component palette decisions. Reviewers had to mentally decode every #ff6600 or open a color picker to follow the author's intent.
The plan viewer now renders a small filled swatch inline, immediately to the left of the hex code. The swatch is a 14×14 rounded square matching the referenced color. Supports 3-, 4-, 6-, and 8-digit hex with a negative lookahead that excludes URL anchors, CSS id selectors, and any identifier that continues with word characters.
The color value is constrained by the regex before reaching React, and rendered via the React style object — not cssText — so there's no CSS injection path. 19 tests cover valid patterns, false-positive guards, and injection attempts.
Self-Hosted Paste Service Support
Short-link sharing for larger plans routes through a paste service at plannotator-paste.plannotator.workers.dev. Self-hosted deployments had no way to point at their own paste service — the URL was hardcoded in the OpenCode plugin.
The PLANNOTATOR_PASTE_URL environment variable now configures a custom paste endpoint. The OpenCode plugin reads it via a new getPasteApiUrl dependency that flows through command handlers (annotate, annotate-last, archive) and the review server. The Landing component accepts a shareBaseUrl prop with a fallback to the default. CORS documentation in the paste service now includes explicit guidance for self-hosters.
Backward compatible: unset PLANNOTATOR_PASTE_URL continues to use the hosted default.
- #582 by @backnotprop, closing #580 reported by @ndesjardins-comact
OpenCode Review: Reuse the Existing Local Server
On subsequent review commands, the OpenCode AI review path tried to start a second opencode serve and collided with the existing local server on port 4096. The first opencode serve wasn't being cleaned up, so port conflicts were guaranteed on the second invocation.
The review flow now attaches to the default local OpenCode server at 127.0.0.1:4096 if one is already running. If nothing is listening, it spawns a new instance as before. No extra lifecycle management, no extra ports — just reuse what's already there.
The PR also fixes two local-testing issues uncovered along the way: the source-loaded OpenCode plugin was resolving bundled HTML from the wrong directory, and the sandbox + postinstall paths were not using the documented plugins/ and commands/ directories.
- #567 by @oorestisime, closing #513 reported by @alexey-igrychev
Additional Changes
~expansion in user-entered file paths — The shared path resolver now expands home-relative~in annotate entrypoints and the Bun and Pi reference handlers, so file, folder, vault, and linked-document paths all handle~consistently. #572 by @AlexanderKolberg- Thumbs-up quick label on the annotation toolbar — A one-click "Looks good" 👍 button sits before the existing quick labels menu, with green hover styling to match the semantic. #588 by @backnotprop
- Save as PDF discoverability — The action menu label is now "Print / Save as PDF" with a subtitle explaining how to choose Save as PDF in the system print dialog. No new print pipeline — just making the existing capability findable. #587 by @backnotprop
- Disable auto-invocation of plannotator slash commands in Claude Code — The four plannotator Claude Code command definitions (annotate, archive, last, review) now carry
disable-model-invocation: true, preventing the model from running them automatically. #586 by @backnotprop - Stop forcing an agent cycle in OpenCode —
agent_cycleassumed only a build and plan agent and broke when users had other agents defined. Removed. #564 by @andreineculau - RSS feed link in the marketing layout — The blog's RSS feed is now advertised in the shared
<head>so feed readers and browsers can discover it automatically. #573 by @dotemacs
Install / Update
macOS / Linux:
curl -fsSL https://plannotator.ai/install.sh | bashWindows PowerShell:
irm https://plannotator.ai/install.ps1 | iexPin a specific version:
curl -fsSL https://plannotator.ai/install.sh | bash -s -- --version v0.18.0Claude Code Plugin: Run /plugin in Claude Code, find plannotator, and click "Update now".
Copilot CLI:
/plugin marketplace add backnotprop/plannotator
/plugin install plannotator-copilot@plannotator
Gemini CLI: The install script auto-detects ~/.gemini and configures hooks, policy, and slash commands.
OpenCode: Clear cache and restart:
rm -rf ~/.cache/opencode/packages/@plannotator ~/.bun/install/cache/@plannotatorThen in opencode.json:
{
"plugin": ["@plannotator/opencode@latest"]
}Pi: Install or update the extension:
pi install npm:@plannotator/pi-extensionVS Code Extension: Install from the VS Code Marketplace.
What's Changed
- feat(annotate): content negotiation for Markdown for Agents by @backnotprop in #557
- feat(viewer): render color swatches next to hex color codes by @Pran-Ker in #562
- don't change current agent by @andreineculau in #564
- feat(plan-diff): word-level inline diff rendering by @backnotprop in #565
- fix(opencode): reuse local server for review flows by @oorestisime in #567
- Add ~ support for user-entered file paths by @AlexanderKolberg in #572
- Fix for RSS feed by @dotemacs in #573
- Add annotate wide mode by @dgrissen2 in #578
- Add configurable paste service URL for self-hosting by @backnotprop in #582
- Prevent model from auto-invoking plannotator slash commands by @backnotprop in #586
- Surface Save as PDF via existing print flow by @backnotprop in #587
- Add thumbs up quick label button to annotation toolbar by @backnotprop in #588
- feat: detect OpenCode origin + activate PLANNOTATOR_ORIGIN override by @HeikoAtGitHub in #590
New Contributors
- @Pran-Ker made their first contribution in #562
- @andreineculau made their first contribution in #564
- @oorestisime made their first contribution in #567
- @AlexanderKolberg made their first contribution in #572
- @dotemacs made their first contribution in #573
- @HeikoAtGitHub made their first contribution in #590
Contributors
@Pran-Ker shipped inline hex color swatches in the plan viewer, with a carefully constrained regex, a negative lookahead to avoid URL anchors and CSS selectors, and 19 tests including explicit injection guards.
@andreineculau removed the agent_cycle call that assumed everyone had only build and plan agents in OpenCode, fixing a bug introduced by #40.
@oorestisime fixed the OpenCode review port collision by reusing the existing local opencode serve at 127.0.0.1:4096 instead of spawning a second one, and cleaned up two local-testing path issues along the way.
@AlexanderKolberg added ~ home-directory expansion to the shared path resolver so annotate entrypoints and the Bun and Pi reference handlers all treat ~/file.md the same way.
@dotemacs added the RSS autodiscovery <link> to the marketing site layout so feed readers and browsers can pick up the blog feed automatically.
@dgrissen2 returned with annotate wide mode — a toggle that collapses both side panels and removes the reader width cap, gated to annotate sessions only, with layout restoration on exit. This follows their prior work on linked-doc navigation, image lightboxing, smart file resolution, and the purple P favicon.
@HeikoAtGitHub wired OpenCode into the origin detection chain (via OPENCODE=1) and activated the PLANNOTATOR_ORIGIN override that had been documented but never read, with seven headless detection tests covering the new priority order.
Community issue reporters:
- @pbowyer filed #560 with a detailed request for word-level diffs and diff display options — that issue directly shaped the design of the new Rendered/Classic/Raw mode switcher.
- @ndesjardins-comact reported #580, the hardcoded share URL blocking custom-domain usage, which drove the
PLANNOTATOR_PASTE_URLwork. - @alexey-igrychev reported both #513 (the
opencode serveport collision) and #514 (empty response bubbles in the OpenCode AI tab).
Full Changelog: v0.17.10...v0.18.0