Follow @plannotator on X for updates
Missed recent releases?
| Release | Highlights |
|---|---|
| v0.27.12 | Unified decision control, token hover cards, local-vs-remote diff, approval notes |
| v0.27.11 | OpenCode server leak fix, durable local feedback archive, unknown-subcommand fix |
| v0.27.10 | Auto-viewed files on scroll, annotation undo/redo, OpenCode 2 slash commands restored, npm 12 agent terminal fix |
| v0.27.9 | WebMCP browser-agent tools, HTML refresh from disk, host seams, lazy renderers, Windows uninstall fix |
| v0.27.8 | Pi keeps its prompt cache across plan transitions, thumbs-up returns to HTML annotation, embed picker seam |
| v0.27.7 | Pi host crash fix on Windows, Call Flow tree cap, jj fork-point base, plannotator knowledge skill + llms.txt |
| v0.27.6 | Live app annotation lands on Pi, one interaction model for HTML pages |
| v0.27.5 | Annotate your running app, Agent TUI placement, collapsed lockfiles, VS Code theme fix |
| v0.27.4 | Portable Guided Review exports, guides.show share links, guide CLI, jj Call Flow |
| v0.27.3 | Folder watcher freeze fix on large repos, first SBOM-attested release pipeline |
| v0.27.2 | Mobile plan and code review, Codex CLI 0.147 fix, configurable markdown extensions |
| v0.27.1 | Open-in-editor launch fix, file headers respect Viewed/Git-add visibility toggles |
What's New in v0.27.13
Six pull requests, four of them from community contributors, two from first-time contributors. The headline answers a request straight from X: open a code review against the base you actually mean, not always the trunk. Alongside it: a security hardening of the document endpoint, the end of our longest-standing CI flake, and a Amp delivery fix.
Open a review on a specific base
plannotator review always opened against the detected trunk, even when you were reviewing one layer of a stacked branch. A user on X put it plainly: "it always opens vs. main even if it explicitly understands that I'm reviewing a stack."
Now the review can open exactly where you point it:
# stack: main → feature/part-1 → feature/part-2 (you are here)
plannotator review --base feature/part-1
# opens on "All changes since feature/part-1": just what this layer adds
plannotator review --base feature/part-1 --diff-type merge-base
# the committed-only view of the same layer--base takes anything git resolves: a branch, origin/branch, a tag, a commit, HEAD~3. --diff-type picks the opening view from the same nine modes the dropdown offers. Both are a starting state, nothing more: the session opens there, everything stays changeable in the UI, and neither flag ever touches your saved defaults. A base that does not exist fails at launch with a clear message and a "did you mean" suggestion instead of silently producing a wrong diff.
This matters most when an agent opens the review for you. The agent knows which layer it just built, so it can hand you a review already looking at the right thing instead of telling you which dropdown to click. The installed skills teach exactly that: reviewing a stack layer, pass --base <the branch below yours>.
The flags work across every host that launches reviews through the CLI, and error honestly on surfaces where a base has no meaning (jj, GitButler, Perforce, multi-repo workspaces, and PR URLs, whose base comes from the platform). #1484
One behavior change shipped with this. The review command used to silently ignore flags it did not recognize; a typo like --bse main opened a review as if you had typed nothing, and in the worst case an unknown flag could swallow the PR URL next to it. Unknown dash-prefixed flags now fail loudly with a usage hint, matching how annotate has always behaved. Plain words stay tolerated, so slash-command hosts that forward your raw sentence keep working. OpenCode and Pi slash commands also now reject CLI-only transport flags such as --tailscale that they previously accepted and ignored. #1483
Symlinks can no longer read outside the project
A symlink committed into a repository you are reviewing could point anywhere on your disk, and the endpoint that serves linked documents would follow it: the requested path looked like it was inside the project, but the content came from outside it. Document reads are now gated on real-path containment in both server runtimes: a path must land inside the project both as written and after resolving symlinks, or the request is refused.
Legitimate symlink setups keep working, including symlinked project roots (macOS temp directories) and links that resolve within the project. Three edge behaviors changed on purpose: a symlink escaping the project returns 403 on every path through the endpoint, HTML files over the 2MB annotate cap now return 413 where one path previously served them in full, and a file that exists but cannot be opened returns 500 instead of 404.
Contributed by @bendrucker in a first contribution that went well beyond its own scope: along the way he reproduced our longest-standing CI flake, disproved our working theory with actual experiments, and traced it to the real root cause below. #1437
The CI flake is dead, and tests stay out of your data
Four annotate-server tests had been failing intermittently on CI for weeks (#1464), passing on rerun, resisting diagnosis. The root cause turned out to be a single line: shared storage captured the data directory once at module import, so a test that imported it under a temporary override poisoned every later test in the process, and test-file discovery order decided who got hit. The same freeze meant a full test run could write into a contributor's real ~/.plannotator.
Storage now resolves its directory per call, and the test suite sandboxes PLANNOTATOR_DATA_DIR for every run, with regression tests locking both halves down. Two contributors converged on the same root cause independently within a day, from different starting points: @FNDEVVE working from our test-isolation issue, and @bendrucker debugging his own PR's CI failures. Closes #1455 and #1464. #1473
Amp: feedback is routed by decision, never guessed from prose
The Amp plugin classified review outcomes by searching the rendered feedback text for phrases, so a genuine comment like "this path has no feedback loop, add one" pattern-matched as no-action and was silently dropped. The CLI now offers plannotator review --json, emitting one structured { decision, message } record from the same builder as the plaintext output, and Amp routes purely on the decision field. The prose classifier is gone. An outdated CLI produces a recoverable update notice with the captured output, never a guessed decision.
Contributed by @FNDEVVE, closing #1456. #1476
Additional Changes
- Selection toolbar stays on screen on phones: selecting short text near a screen edge in compact touch layouts overflowed the floating toolbar past the viewport, clipping its buttons. It now clamps inside the screen (respecting notch safe areas) and keeps its centered position whenever that fits. Desktop placement is untouched. Contributed by @katya4oyu in their first contribution. #1471
- The view dropdown follows the live base: the "All changes since " option label was baked at session start from the detected trunk and never updated, so it could contradict the base picker sitting next to it. It now renders from the active base.
Install / Update
macOS / Linux:
curl -fsSL https://plannotator.ai/install.sh | bashWindows:
irm https://plannotator.ai/install.ps1 | iexClaude Code Plugin: Run /plugin in Claude Code, find plannotator, and click "Update now".
Pi: Update @plannotator/pi-extension to 0.27.13 and restart Pi.
OpenCode: Clear cache and restart:
rm -rf ~/.bun/install/cache/@plannotatorWhat's Changed
- feat(review): open a review on a specific base and diff type in #1484
- fix(review): strict argument parsing for unknown review flags in #1483
- fix(doc): deny symlink escapes on /api/doc reads by @bendrucker in #1437
- fix(test): isolate test-run data from contributor history by @FNDEVVE in #1473
- fix(amp): relay structured decisions without prose classification by @FNDEVVE in #1476
- fix(ui): keep selection toolbar within compact touch viewport by @katya4oyu in #1471
New Contributors
- @bendrucker made their first contribution in #1437
- @katya4oyu made their first contribution in #1471
Community
This release is mostly the community's. @bendrucker shipped the symlink containment work through two rebases we caused, and when CI failed on his branch he did the diagnosis himself: reproduced it deterministically, tested and disproved our working theory, and root-caused a flake that had dogged this project for weeks, then filed the follow-up (#1477) for the remaining cases. @FNDEVVE swept our own issue tracker and closed two filed issues in as many days, with fixes careful enough that one of them independently matched bendrucker's root cause line for line. @katya4oyu fixed a real phone papercut with a minimal, well-tested change that read the repo's conventions closely enough to regenerate a build manifest most first PRs miss. And the headline feature exists because a user on X told us the review always opened against the wrong base when reviewing a stack. They were right.
Thank you. Plannotator gets better because you tell us where it falls short.
Full Changelog: v0.27.12...v0.27.13