Annotate replies, documents, or live HTML pages, then send feedback to the originating OpenCode session.
This is an unofficial OpenCode plugin. Plannotator TUI provides text review; the Annotate HTML-derived browser companion provides webpage review. This repository owns explicit routing, native messaging, session targeting, terminal handoff and confirmed feedback delivery.
Published on npm as @nxxxsooo/opencode-annotate. It replaces opencode-plannotator-tui
(0.4.2 and earlier); to switch, run
opencode plugin remove opencode-plannotator-tui@latest and then install this package as below.
/annotate Review the last completed assistant reply
/annotate docs/plan.md Review a Markdown document
/annotate "docs/release plan.md" Review a path containing spaces
/annotate ~/Documents/notes.txt Review a plain-text document
/annotate-pick Choose a recent reply or mid-turn progress update
/annotate-selection Review the message containing your last transcript selection
/annotate-web Open this session for browser pairing
/annotate-web page.html Review the specified local HTML in Chrome
/annotate-web https://example.com Review the specified webpage
/annotate-web off Revoke this session's browser pairing
/annotate-last always reviews the latest completed reply; any supplied argument is ignored.
Progress updates written during a long tool run are not replies, so /annotate skips them.
Reach them with /annotate-pick, or drag over text in the transcript and run
/annotate-selection: the plugin opens the reply or progress update containing that text,
or just the selected text when it spans messages. Numbered /annotate N is retired.
Requires OpenCode 2.0.22+ and a separately installed plannotator-tui on your PATH.
Tested with OpenCode 2.1.2 and Plannotator TUI 0.9.4 on macOS; unit tests also run on
Linux. Windows terminal handoff has not been verified.
Install the upstream TUI on macOS or Linux:
brew install plannotator/tap/plannotator-tuiHomebrew 6 may first require brew trust plannotator/tap. Alternatively, use
cargo install plannotator-tui --locked or the upstream
prebuilt binaries.
Then install the plugin:
opencode plugin add @nxxxsooo/opencode-annotate@latestOpenCode detects its TUI-only entrypoint and adds it to your global cli.json.
It does not need a server-plugin entry. Reopen the terminal client if its command
list has not refreshed.
Manual configuration, preserving other entries:
{
"plugins": ["@nxxxsooo/opencode-annotate@latest"]
}Set "inheritTheme": true in the plugin's options, alongside binary. It requires
the extended color-capable Plannotator fork
(nxxxsooo/plannotator-tui, branch
feat/layout); upstream 0.9.4 does not support it. The same fork adds [ui].doc_width
to cap the text column on wide terminals. See TUI theme integration.
Each review uses OpenCode's current resolved colors for the canvas, text, Markdown,
borders, highlights, cursor and selection. The plugin asks the chosen binary for its
effective configuration, copies it into that review's private directory, and validates
the themed copy before taking over the terminal. Your original settings stay intact.
Launchers must honor an existing PLANNOTATOR_TUI_CONFIG.
Requirements: macOS and Chrome 116+, plus Node 22+ for the native host.
- Clone this repository and load its
browser/directory as an unpacked extension inchrome://extensions. Allow file URL access if reviewing local HTML. - Run
npm run install:bridgein the clone to register the native host. It allows only this companion's fixed extension ID and resolves Node absolutely. The host starts on demand and opens no HTTP port. - Reopen the OpenCode terminal client; the shared service needs no restart.
Run /annotate-web in a target session, then open the Chrome extension. A sole live
session is shown automatically; with several sessions, choose one once. Click the
destination beside To to change or refresh it. Its title stays visible beside Send,
including while disconnected, with its directory available on hover and in the chooser.
A sole target is only preselected: no binding or model turn occurs until
the user clicks Send & continue. A disconnected destination never silently switches to another session.
Choose Pick element or select text, then write a comment or question. The composer
appears for that selection. Send N notes & continue saves the current feedback and
sends pending notes in one action; Add note collects feedback locally for a batch.
Cmd/Ctrl+Enter adds a note or saves an edit. This sends pending notes to that captured
session and starts a normal model turn; pairing and saving notes make no model call.
Switching terminal tabs never changes the paired target. Revoke with /annotate-web off.
The numbered queue matches the page markers. Click a note's quoted target to show it on the page without activating the element; Edit changes the feedback, and Undo restores a deleted note. The delivery bar shows the pending count, destination, and sent state. More review options contains Markdown copy, JSON export, and a preview of all saved notes.
/annotate, /annotate-pick and /annotate-selection always use the TUI; Markdown and
plain-text files do too. Only /annotate-web enters the browser workflow; passing a URL or
HTML file to /annotate points you there. A reply containing HTML links or code fences does
not change the default.
Written drafts autosave locally and restore after panel reload or a return to the same URL, including SPA routes. Selecting another target with unfinished feedback offers Add/Save & switch, Keep editing, or Discard & switch. Storage failures keep the input and offer a retry; competing panels require an explicit choice of draft. Saved-note revision checks likewise prevent stale tabs overwriting newer feedback. Full JSON/Markdown exports include redacted URLs, exact selected text/context, verified selector hints, styles and accessibility. Missing/changed/ambiguous targets are labeled in the sidebar instead of silently rebound. Comments and drafts live in extension-owned UI/storage; the page receives only selection metadata and numbered markers, not your written feedback.
Native delivery requires an open, paired local TUI. If the receiver closes, feedback stays pending. A failed batch retains its original target and ID for safe retry; if that target is permanently gone, export the notes before starting a new review. Retry N notes & continue retries that original batch; newly composed feedback stays local for the next send. Changed sent notes become new pending revisions; unchanged edits send nothing new. Clipboard failures expose a selectable preview. Browser-internal pages, PDF, cross-origin iframes, Canvas and remote SSH TUI clients are outside this version's scope. Page Context is retired only after exporting its drafts and verifying this replacement.
See implementation plan and
shipped-artifact evaluation, plus
browser provenance. npm test, npm run test:smoke, and
npm run test:browser verify each layer; the browser test uses an existing Playwright installation
(PLAYWRIGHT_MODULE) and browser executable (CHROMIUM_PATH) in an isolated profile.
After updating the unpacked browser/ files, open chrome://extensions and click
Reload for OpenCode Annotate. Return to the target webpage and open Annotate
using its extension icon or Alt+Shift+A.
A newly opened sidebar can load the updated panel.mjs while Chrome still runs an
older worker.mjs. With the compact workspace, that mismatch produces
Cannot read properties of undefined (reading 'value'): the sidebar expects a
draft record that the older worker does not return. Reload the whole extension;
reopening only the sidebar does not ensure the background code is refreshed.
Saved extension-local data survives an extension reload.
For diagnosis, compare the running worker's source (DevTools/CDP
Debugger.getScriptSource) with browser/worker.mjs in the loaded checkout.
The manifest version alone cannot identify edits to an unpacked extension.
- Run
/annotateor/annotate path/to/file.mdin a session. - Select text by dragging, or press
vand use movement keys. - Press
cto comment,afor “looks good,” ordto request deletion. Without a selection,ccomments on the current block. Enter saves a comment. - Press
qto return to OpenCode. - Choose Send and continue to submit the annotations. Escape or Cancel cancels.
The upstream E action copies to the clipboard. This adapter's automatic
delivery path is q → confirm and does not need clipboard access.
Opening a review makes no model call. Confirming sends a normal user prompt and resumes the original session, even if the active tab changes. Empty and cancelled reviews submit nothing.
Replies: the latest completed text reply, with paginated history lookup.
Reasoning, in-progress messages and tool-call commentary are excluded.
Pass a positive integer to select the Nth most recent eligible reply: 1 is the
default, 2 is the previous reply, and so on. If there are too few replies, the
plugin reports that instead of opening another reply.
Documents: local UTF-8 .md, .mdx, .markdown and .txt files up to 2 MiB.
Relative paths resolve against the captured session's working directory, not the
directory from which the terminal client happened to start. Absolute and ~/
paths work too. The file must exist on the machine running the terminal client.
The TUI reads a fixed snapshot and does not edit the original document. Feedback includes the original path and snapshot hash, with instructions to re-read the current file before applying suggestions. Document review works even before the session has an assistant reply.
@latest selects the npm release channel. OpenCode caches installed packages;
it does not follow this repository's commits. Update just this plugin with:
opencode plugin update @nxxxsooo/opencode-annotate@latestReopen your terminal client to load updated package code. No shared background
service restart is required. Check the installed version with opencode plugin list.
To remove it:
opencode plugin remove @nxxxsooo/opencode-annotate@latestSet binary if Plannotator TUI is installed outside the terminal client's PATH:
{
"plugins": [
{
"package": "@nxxxsooo/opencode-annotate@latest",
"options": { "binary": "/path/to/plannotator-tui" }
}
]
}The adapter launches Plannotator TUI in the current terminal, not through Herdr;
[herdr] placement and popup dimensions do not affect /annotate. Layout is
owned by the selected binary, while font family and size belong to the terminal.
The adapter supplies PLANNOTATOR_TUI_THEME to follow OpenCode's light/dark mode,
overriding Plannotator TUI's configured theme. Use binary to select a custom
build or launcher without replacing the system installation.
Each review has its own private temporary source and annotation store. Successful, empty and cancelled reviews are cleaned up. Failures and archived notes retain the store, and a status message gives its directory.
review.json records the session, original source and relative snapshot path.
feedback.md holds exported feedback when available. To recover a retained review:
PLANNOTATOR_DATA_DIR="<retained-directory>/data" \
plannotator-tui "<retained-directory>/<snapshot>"Use the snapshot value from review.json. Press H to restore archived notes,
then E to copy them for pasting into OpenCode. An upstream E → F archive is
preserved even when --export reports “No annotations.”
npm ci
npm run check
npm run test:smokeUnit tests use the real upstream annotation/export binary. The optional smoke test
also requires Python 3, tmux and OpenCode. It runs a detached terminal, verifies
commands and feedback through the actual API, then removes its test session.
Its submission uses resume: false, so it makes no model call or visible window.
Set ANNOTATE_TUI_BINARY to test a custom binary or launcher through the plugin's
real configuration path. For a build with a centered 120-column viewport, also
set ANNOTATE_EXPECT_MARGIN=10 to assert blank margins in the 140-column smoke
terminal. These variables configure the test, not the shipped plugin.
For development loading, run npm run install:plugin to replace the npm entry in
cli.json with this checkout's absolute directory. It backs up the CLI preferences and
keeps options.binary and unrelated settings. Use only one installation at a time.
See release instructions and changelog.
这是非官方 OpenCode 批注插件:文本用 Plannotator TUI,网页用 Chrome 伴随扩展。
/annotate:批注上一条完整回复。/annotate 文档.md:批注文档,支持中文、空格和相对路径。/annotate-pick:从最近的回复和运行中的进度说明里选一条批注。/annotate-selection:先在会话里拖选文字,再批注包含这段文字的消息。/annotate-last:固定批注最新一条完整回复,忽略附带参数。/annotate-web:配对 Chrome;/annotate-web 页面.html、/annotate-web https://…批注网页;/annotate-web off撤销配对。- 选中文字 →
c写批注 → Enter 保存 →q返回 →「Send and continue」。 - 文档采用独立快照,反馈附原文件路径,确认后发回发起批注的会话。
- 更新:
opencode plugin update @nxxxsooo/opencode-annotate@latest,然后重新打开终端客户端。
MIT licensed. The annotation UI is maintained upstream by the Plannotator project.