我在 Pico CSS 的倉庫裏改了 3 行代碼,又用 plannotator 落了 2 條逐行批註;一次發回之後,agent 照着第 1 條改對了,我也複覈過它的改動。意見帶行號送達、決定留檔,這兩件事它做到了。
但是它的招牌功能,Codex 和 Claude 的桌面版都有內建版,所以只用一家桌面版的人多數不用多裝它。而它多出來的有三樣:能批註代碼以外的文件、多家 agent 共用的 Inbox、給腳本用的批准閘門,都落在桌面版管不到的地方。
它是什麼,怎麼裝
plannotator 是一個裝在本機的瀏覽器審查工作臺,這一輪裝到的版本是 v0.28.64。agent 寫完計劃或者改完代碼之後,它就在本機開一個網頁;你在網頁裏逐行批註、批准或者打回,寫下的意見會帶着文件、行號和那一行的原文回到 agent 手裏,然後 agent 再接着按意見改。
倉庫:github.com/backnotprop/plannotator
我注意到它,是因爲它在我看的 GitHub 熱榜摘要裏一天漲了 412 顆星,在連續十輪的摘要記錄裏第一次排到總榜第 1。我自己動手查的時候,它的星數已經到了 10,775 顆。星多隻能說明圍觀的人多,東西到底行不行,還得裝上跑過纔算數。
裝它只有一條命令,從它的官網拉一個腳本下來跑。腳本把一個 205 MB 的 binary 裝到你自己電腦的 ~/.local/bin 裏,這就是它的本體。安裝命令加上 —minimal 之後,它就只裝這一個文件,別的配置一律不動。
完整安裝動的配置就多了。這一輪它改了我的 ~/.codex/config.toml,在文件末尾加了一段打開 hooks 的配置,又新建了 ~/.codex/hooks.json,裏面是一個 Stop hook。agent 每次停下來,這個 hook 就有機會先把審查頁遞到我面前。
它還往 ~/.agents/skills 和 ~/.claude/skills 裏各裝了 5 個技能,給 OpenCode 放了 4 個命令文件,另外下載了一個 67 MB 的 sem 側車,負責算語義 diff。這些改動裝完都能逐項查到,安裝器沒有藏,但是你裝之前得知道,它接的正是 agent 和你之間的那道關口。

審代碼這一輪
試驗田是 picocss/pico,我在它的本地分支上改了兩個文件,一共 3 行:給 tooltip 的樣式加一行寬度的上限,給它的顯示觸發補一行 &:focus-visible,鍵盤聚焦時也能顯示,再給 loading 樣式裏的按鈕和鏈接加一行進度光標。改的都是這個倉庫裏真實存在的缺口,改完先編譯過一遍,確認沒把樣式弄壞。
改完我在倉庫裏跑 plannotator review,這條命令會一直等在那裏,直到審查結束才退出。這一輪跑的是命令行手動啓動的審查面,因爲測試機上的 Codex 沒有登錄,我沒能拿真會話驗過 plannotator 靠 hook 自動接上的那條路。瀏覽器裏打開的是分屏 diff,文件樹寫着 2 個文件、新增 3 行,跟我自己用 git diff 看到的完全對得上。

第 1 條批註,我落在 _tooltip.scss 第 27 行,就是我新加的那一行 max-width 上。毛病不在這一行本身,而在它跟同一條規則裏的老設置打架:那條規則裏本來就寫着 white-space: nowrap,不許文本換行,還配了 text-overflow: ellipsis,裝不下的部分直接截斷成省略號。
我只給氣泡封了一個寬度上限,但是換行還是不許,長 tooltip 最後只會被截斷成一串省略號,用戶讀不到全文。我的批註就寫這一件事:要麼放開換行,要麼別加這個寬度上限,兩個設置不能同時留着。
第 2 條批註落在 _loading.scss 第 44 行,是我加的那一行 cursor: progress。我寫的要求是,進度光標只落在了按鈕和鏈接上,_loading.scss 裏通用規則的普通 busy 容器也應該一併加上,省得同一個頁面上忙起來的樣子不一致。兩條批註都寫完之後,我點頂欄的 Send Feedback 一次發完;命令隨即退出,意見就變成了它的標準輸出,格式是 JSON。
回到 agent 手裏的意見,帶着文件路徑、行號,而且行號還分新舊兩側,被批註那一行的原文也在,前後各兩行上下文也在。意見末尾還附了一段它自動拼上的規矩:agent 要先逐條給出裁定、附上代碼證據,裁定談完之前不許改代碼,而且只許處理這幾條意見,不許自己擴大審查範圍。
agent 先裁定再動手。第 1 條它判 Confirmed,因爲證據就在同一條規則裏:max-width、nowrap 和 ellipsis 三樣同時在場,長文本被截斷躲不掉。
它給的改法是把 white-space: nowrap 改成 normal,放開換行。改完之後我重新編譯了一遍,產物裏那條規則已經是 white-space: normal,再看 git diff,已經變成 2 個文件、新增 4 行、刪掉 1 行。這一條批註從寫下到改對,我全程對得上賬。
第 2 條它判了 Partly,理由是普通容器不是交互元素,進度光標只在鼠標懸停到它上面的時候纔出現,收益有限。這個問題後來在 Inbox 里正式問到了我頭上,我選的是隻保留按鈕和鏈接,所以這一條就按已經裁定過的擱置項留着,沒有再改。
Inbox 異步問答
Inbox 是用 plannotator inbox —background 起的常駐服務,agent 可以隨時往裏面留消息,也可以留帶選項的結構化問題。這一輪它留給我的就是剛纔那個光標問題:一道單選題,兩個選項,其中一個標着 Recommended,問題掛在頁面的「Waiting on you」下面等我處理。
我點了一下 Accept recommended,但是選好的答案這時還只是一條草稿,並沒有真的發出去,我再點一次 Send 纔算提交。提交之後我從 agent 那一側把線程讀回來覈對:問題已經標成已回答,我的答案作爲一條新消息進了線程,正文是結構化的答覆格式,agent 下一輪直接就能讀到。

這條流解決的是等人的問題。agent 把問題留下就接着做它自己的事,不用停在原地等我回復,我也不用守着某一個會話窗口,幾個問題攢在一起答也行。等到好幾家 agent 同時跑起來的時候,問題是散在各自對話裏,還是集中在一個箱子裏,找起來完全是兩回事。
跟桌面版逐項對完之後
計劃批准這一項,兩家桌面版都有原生做法。桌面版這一側,我查的是兩家的官方文檔,沒有親手裝來實測;文檔裏寫有,也不等於我驗過它實際用起來怎麼樣。Codex 桌面版有 plan mode,動手之前先把任務拆成一串能審的步驟,遇到不清楚的地方它會追問,你批准之後它才執行。
Claude 桌面版有 Plan 權限模式,還有一個 Plan 窗格。那個模式下它只讀文件、只跑命令探查,並不動你的代碼;等你看完計劃,把模式切到執行,它才接着往下走。兩家的計劃都擺在對話裏面,沒有逐行批註,你想糾正計劃,只能在對話裏打字說給它聽。
逐行批註這一項,Claude 桌面版的內建版本跟 plannotator 的逐行批註幾乎是同一個形狀。在 Claude 桌面版的 diff 視圖裏,你把鼠標停在某一行上,點那個 + 號就能寫評論,好幾行都寫完之後,一次全部提交,它的官方文檔原話是,Claude 讀完你的評論就會照着改。點行、寫意見、一次發回、agent 照改,這個循環桌面版已經內置了。
Codex 桌面版在審查這一塊鋪得更寬。它有 review pane,你能對着 diff 留言,也能暫存改動,還能按塊接受或者回退;桌面 App 裏還內置了 Code Review 插件,PR 的描述、改動文件、評論和檢查狀態擺在同一屏,插件裏還有一個 PR 收件箱,能按負責人、團隊過濾,也能只看我寫的 PR。
審完點 Submit review,Comment、Approve 或者 Request changes 就直接發到 GitHub 上,它另外還有云端的自動審查。所以兩個招牌功能擺在一起比,桌面版用戶並沒有缺什麼。你就在 Codex 或者 Claude 桌面版裏寫代碼,再裝一個 205 MB 的 binary,還要讓它改你 agent 的 hook 配置,換來的計劃批准和逐行批註,你已經有了。
它真正多出來的有三樣,桌面版的官方文檔裏都找不到對應功能。第一樣是批註代碼以外的東西:agent 寫的計劃文件、說明文檔能打開來逐段批註再發回去。plannotator 說,網頁和 agent 上一條回覆也能拿來批註,但是那兩樣我這一輪沒有測。
這一輪試的那份計劃文件叫 plan-tooltip-loading.md,寫的是 tooltip 和 loading 兩處改法,還列了一節風險,第 18 行是風險節的第一條,批註就落在那一條上。批註標的行號跟文件裏的實際行號一致,發回去的反饋裏寫的行號也還是這個行號。
第二樣是 Inbox,而且它不挑廠商。這一輪同一次安裝,把 Codex、Claude 和 OpenCode 三家都接到了同一個 binary 上,用同一套批註格式(Claude 那一側我只驗到安裝層,沒有跑它的真會話)。Codex 和 Claude 兩家桌面版的會話管理和收件箱都只管自家的 agent,幾家 agent 共用一個審查面和一個問題箱,目前只有 plannotator 在做。
第三樣是給腳本用的批准閘門。
annotate 命令加上 —gate,頁面頂欄會多出一個 Approve 按鈕,再配上 —require-approval 和 —result-file,批准這個動作就變成了一個有憑據的結果:我這一輪點了 Approve,result 文件當場寫好,命令的退出碼是 0。這樣一來,流水線裏的腳本直接看命令的退出碼,就能判斷人批准了沒有,不用再靠人回想自己當時批過沒有。
沒跑通的和硌人的地方
計劃審查的自動觸發,是它的招牌功能之一,這一輪我沒有跑通。按它自己的設計,agent 退出 plan mode 的時候,hook 應該自動把審查頁彈出來,人不用敲任何命令。
但是真會話這條路斷在登錄上,因爲測試機上的 Codex 沒有登錄。所以我改用手工辦法,照着 Codex 的 Stop 事件格式造了一份數據,再餵給 plannotator 的 hook 入口,想看看 plannotator 認不認。
它給我的回應是什麼都沒有:退出碼 0,沒有任何輸出,也沒有新會話,就這麼靜默地放行了。更麻煩的是沒地方查原因,~/.plannotator 下面連一個日誌目錄都沒有,我沒法分辨是那份數據的格式不對,還是 plannotator 對什麼算一份計劃這件事另有一套判斷標準。順帶說一句,它給會話貼的來源標籤也不準,這一輪所有會話都是裸命令啓動的,記錄裏一律寫着 claude-code。
第一次打開審查頁,也得先做一番清理才能開始審。新用戶面前一共有四層彈窗:一層讓你選計劃的顯示樣式,一層推一個實驗功能,還有一層介紹 Guided Reviews;剩下的一層是 Inbox 的推廣,上面還帶着影片。換一個會話,它們還會換個順序再出現。彈窗清完,主區域默認還是空的,你得先去左側文件樹裏點中一個文件,diff 才加載出來。
remote 模式的風險是這一輪實測真查到的問題。打開 PLANNOTATOR_REMOTE=1 之後,它就把服務綁在 0.0.0.0 的 19432 端口上;我試着在本機不帶任何口令打開審查頁,服務器直接返回 200,頁面上也沒有任何登錄校驗。它同時會生成一條帶長令牌的分享鏈接,diff 就打包在鏈接裏面,所以鏈接一旦泄露,泄露的就是你的代碼改動。
所以在遠程機器上用它,正確的做法是把端口放進 SSH 隧道里,或者用它自帶的 tailscale 方式,不要把 19432 直接對着不可信的網絡開。tailscale 這一路我這輪沒有測通,因爲這臺機器上的 tailscale 也沒有登錄,但是 plannotator 走這一路失敗的時候報錯很乾淨,直接告訴你 tailscale 沒有登錄、退回本地模式怎麼跑。
還有兩個小賬。一個是 annotate 的存檔保真度:存檔裏被批註的那段原文會被截斷,斷在半個詞的位置上,日後想靠存檔把批註定位回原文,只能靠段落編號和上下文補。另一個是團隊分享,它有 guide share 能把批註做成鏈接發給隊友,但是這一輪我沒有測,因爲生成鏈接要把內容傳到外面去,它實際用起來怎麼樣,我這裏沒有結論。
誰該裝,誰不用裝
如果你只用一家桌面版,不管是 Codex 還是 Claude,我的建議都是不用裝,除非你明確想要前面那三樣裏的至少一樣:批註計劃和文檔、拿 Inbox 攢問題、或者把批准做成腳本能驗的閘門。三樣都用不上,就不要給自己多加這一層,而且它的短板也很清楚,它替代不了桌面版那一整套 PR、CI 檢查和自動合併的生態。
如果你主要在終端裏用 CLI 寫代碼,或者你手上同時有好幾家 agent 在跑,那麼這一層就該裝上。它給的是 CLI 世界裏原來缺的東西:一頁正經的分屏 diff,意見帶着行號和原文準確送回 agent,而且審查和批註的決定都在 ~/.plannotator 裏留兩份存檔,一份 JSONL 一份 Markdown。gate 的批准則只在總賬裏留一行。
這一輪的 2 條批註、1 次 gate 批准和 Inbox 的全部問答,我逐條對過賬,文件、行號、內容都沒有錯位。它沒有解決的那件事也得說在前面:agent 寫得對不對,它不替你判斷。批註寫得準不準、審查時看不看得仔細,到頭來還是人的事,它能保證的只有兩件,意見送得準,還有意見留得住。你要是已經不逐行看 agent 的改動了,那麼再好的審查工具擺在面前,也不會有人去點開它。
我自己的用法已經定了:幾家 agent 同時跑的場合,我會把問題都攢進它的 Inbox,計劃文件先過一遍 gate 再放行;只用一家桌面版的會話,我就不再繞這一層,直接在桌面版裏審。這篇要是幫你省下一次裝上又卸掉的來回,麻煩收藏一下,再訂閱這個博客,我會接着真裝真跑這類給 agent 用的工具,跑通的和跑不通的都照實寫。