一個以 Markdown skill 為主體的套件,2026 年 10 月 21 日(UTC)一天發了五個版本:v0.9.97、v0.9.98、v0.9.99、v0.9.100、v0.9.101。CHANGES.md 的五個條目讀下來,講的全是路徑。Windows 風格的反斜線,CLAUDE_CONFIG_DIR,transcript 寫在哪個資料夾,agent 走進 worktree 之後又該去哪找。

規則寫在文字檔裡,只要文字沒改,就不會自己壞。壞的是文字檔旁邊那幾行腳本,因為腳本得在每個人不同的機器上,自己把東西找出來。

這個套件叫 pstack-claude,是 Lauren Tan 為 Cursor 寫的 pstack 的移植版,目標包括 Claude Code、Codex、Pi、GitHub Copilot、Muse。README 開場把上游形容成 “an opinionated Cursor skill stack that improves agent outcomes”。以下數字都是 2026 年 10 月 23 日用 gh api 取得:3,326 顆星、311 個 fork、MIT 授權、最新版 v0.9.102(10 月 22 日 23:12 UTC 發布)。先講一件容易混的事:這個 repo 不是 GitHub fork(fork: false),文件裡說的「fork」是另一個意思,後面會拆開。

這套 skill 好不好用,我答不了:只讀了文件與原始碼,沒有裝過,也沒有跑過。我想追的是另一題。上游是 Cursor 的東西,搬到 Claude Code 這邊之後,兩邊的差異是怎麼長出來的?又是誰在管?

0.9.2 那次同步:三十多個 commit 一次追上

CHANGES.md 的 0.9.2 條目,對應 2026-06-23 的 commit「Sync to upstream pstack 0.9.2 (e46364b), re-apply Claude Code substitutions」。條目第一句是:”Upstream pstack jumped from 0.1.0 → 0.9.2 between syncs. 30+ commits, including 11 new files.” 兩次同步之間,上游自己往前跳了這麼多,port 一口氣追上,再把 Cursor 的 transcript 路徑改寫成 Claude Code 的路徑。

日期口徑要交代一下。這個 repo 的 GitHub Release 列表,最舊的一筆是 v0.9.27(2026-09-09),在那之前的版本沒有 release 日期。本文標在更早版本上的日期,是「改動該版 plugin.json 的 commit 日期」,兩種不能混著比。

換成書來比方比較快。上游是原作,port 是譯本。CONTRIBUTING.md 把分工寫成一句:”Upstream owns skill content. This port owns the Cursor-to-Claude-Code translation.” 照這句分工,譯者本來只管把原作裡「只有 Cursor 才有的東西」換成讀者手邊有的東西,後面會看到它其實也留了自己的主張。路徑是最典型的一種:原作寫「去 A 資料夾找」,譯本得改成「去 B 資料夾找」。

開頭那天為什麼全是路徑,我的讀法是:翻譯的工作多半就落在這裡。這是我的讀法,CHANGES 沒有下過這個結論。

pstack-claude 的版本線

2026-05-26 repo 建立

gh api 回報的 created_at。

2026-06-23 0.9.2(commit 日期)

同步上游,兩次同步之間上游跳了 30+ commits、11 個新檔案。

2026-07-01 0.9.3(commit 日期)

拿掉 plugin-dev 的 dependency 宣告,因為它讓 plugin 在桌面版靜默消失。

0.9.14(日期我沒查)

條目描述 generate.mjs 與 sync.mjs,同步時用 upstream.json 的 SHA pin。

2026-09-09 v0.9.27

GitHub Release 列表上最舊的一筆。

2026-10-15 v0.9.86

同步到上游 v0.15.25,15 個衝突逐一手解。

2026-10-16 v0.9.88

三個 skill 的模型從 fable 改回 opus,反轉 0.9.15 的選擇。

2026-10-21 v0.9.97 到 v0.9.101

一天五版,全部跟路徑有關。

譯註清單:47 筆偏離,每筆要說得出理由

譯本最麻煩的地方,是譯者忍不住想改幾句。pstack-claude 的做法是把每一處「我們跟上游不一樣」都登記進 tools/forks.json。CONTRIBUTING.md 定義了兩種:port-feature 是 “Claude Code, Codex, Pi, GitHub Copilot, or Muse mechanics upstream cannot carry”,policy 是 “a workflow change the port chose to keep”。前者是平台差異,後者是譯者的主張。

forks.json 的計數是取證時用 python 解析 main 當時的版本得到的:pstack 區塊 47 筆,其中 policy 39 筆、port-feature 8 筆;另外 thermos 區塊 1 筆,是 policy。47 筆的 upstream 欄全是 not-proposed。每筆都有一句話的 why,下面挑五筆,why 逐字複製。路徑省略了前面的 plugins/pstack/,since 是 port 的版本號,不是日期。

檔案 類型 since why(原文)
skills/tdd/SKILL.md policy 0.9.21 “Requires quoting the failure content, not the assertion line, as evidence that the new test fails for the intended reason.”
skills/blast-radius/SKILL.md policy 0.9.21 “Extends the trigger to run before design when a brief asserts something about existing code.”
skills/poteto-mode/playbooks/opening-a-pr.md policy 0.9.10 “Requires stopping every live agent that holds a worktree before committing, merging, or deploying from it.”
skills/create-verification-skill/SKILL.md port-feature 0.9.29 “Names the generated project skill verify so it replaces Claude Code’s bundled user-only /verify and the playbooks can invoke it.”
skills/poteto-mode/playbooks/orchestrate.md port-feature 0.9.29 “Runs workers as background subagents in per-writer worktrees under a ~/.claude/orchestrate store because Claude Code has no cloud worker environment, and keeps human rulings in their original wording.”

兩種的味道差很多。policy 那三列讀起來像譯者的偏好:測試失敗要貼失敗內容而不是斷言那一行,commit 前要先把握著 worktree 的 agent 停掉。port-feature 那兩列講的是平台:Claude Code 有一個內建的、只給使用者叫的 /verify,所以產生出來的 skill 要改名去取代它;Claude Code 沒有雲端 worker 環境,所以改成在各自的 worktree 裡跑背景 subagent。

還有一筆我想單獨拉出來,因為它最像「譯者改了原作的結論」。skills/poteto-mode/playbooks/autopilot-full.md,policy,since 0.9.39,why 的開頭是 “Owners stop at merge-ready and the operator clicks every merge”,後面一句把上游的做法反過來講了出來:”instead of each owner merging after a clean verdict”。上游的 owner 在審查乾淨之後自己合併,port 改成停在可合併的狀態,由人按下去。

偏離的帳單:每次同步都要重算一遍

登記是一回事,付帳是另一回事。CONTRIBUTING.md 對 policy 的代價寫得很坦白:

“The port keeps the change as a policy fork, and every later sync merges it three ways against upstream’s new text. Keep the edit small and in one place, because a wide rewrite conflicts each time upstream touches the same lines, and someone has to settle the change again under time pressure.”

另一段交代了為什麼不先去上游送 PR:”Upstream rarely merges pull requests from outside its own team, so this port does not ask you to land a change there first.” 47 筆的 upstream 欄全是 not-proposed,跟這句擺在一起看,沒有任何東西顯示兩者是因果,我只能說兩件事並排存在。

帳單長什麼樣,CHANGES.md 的 0.9.86(2026-10-15 發布)有一份實測。同一個指令 bun tools/sync.mjs pstack 跑了兩次:

“The step to c86f349 merged clean: 4 updated, 1 added, 1 merged. The step to 99743e9, over 106 files with 37 excluded, left 60 unchanged, updated 24, added 1, merged 6, and wrote 15 conflicts, each resolved by hand from upstream’s new text plus the lines its forks.json entry names.”

同一條條目也說了這次上游改了什麼:”Upstream rewrote the Autopilot-full, Autopilot-stack, and Shipping playbooks as rules with their reasons. The port takes the new text and keeps its own policy inside it.” Autopilot-full 正好就是上面表格外那一筆 0.9.39 的 policy。至於 15 個衝突各落在哪些檔案,條目沒有說,我也沒去對。

把它跟 0.9.2 擺在一起,差異很具體。0.9.2 是兩次同步之間一口氣追三十多個 commit;0.9.86 是分兩步走,第一步乾淨合併,第二步才碰到衝突,一個個手解,而且手解的依據是「上游的新文字,加上 forks.json 那筆記錄點名的那幾行」。偏離有了清單,解衝突才有東西可依。清單也會縮:同一次 0.9.86,另有一個 principle 直接採用上游的文字,CHANGES 寫 “its fork is gone”。

模型欄位:同一個選擇,後來被改回去

偏離不只長在文字上,也長在設定上。CHANGES.md 的 0.9.88(2026-10-16 發布)有這一句:

“bug-fix, perf-issue, and hillclimb move from fable to opus, reversing the 0.9.15 choice, since upstream runs them on its worker model rather than its strongest.”

0.9.15 當時為這三個 skill 選了 claude-fable-5,0.9.88 退回 opus,理由是上游把它們放在 worker 模型上跑,不是最強的那個。0.9.15 的發布日期我沒查,所以不知道隔了多久。同一條還提到另一個差異:”The four-model panel stays: upstream’s two-model panel crosses vendors, and a Claude-only panel gets its diversity from more Claude models.” 這是兩邊結構上的不同:上游審查用兩個模型,跨廠商;port 只用 Claude 家的,靠多放幾個 Claude 模型來湊出差異。

panel 的組成自己也來回過。0.9.15 同條把 haiku 移出 panel(”claude-haiku-4-5 leaves the four panels … so each runs the three-model panel”),0.9.77(2026-10-08 發布)又寫 “The default panel is opus, fable, sonnet, haiku.” 三個模型,再回到四個。這條線沒有一路往同一個方向走,中間有來回。

靜默失效:翻譯錯了,不會有人跟你說

版本發得多快先放一邊,這條演進線上有件事更讓我在意:壞掉的方式。

0.9.3 的 CHANGES 條目寫得很細:plugin.json 原本宣告了一個跨 marketplace 的 dependency(plugin-dev)。Claude Code 桌面版會把每個啟用的 plugin 當成 session-only 的 --plugin-dir 傳給 CLI,這樣一傳,marketplace 的身分就被剝掉(pstack@inline),跨 marketplace 的 dependency 永遠解不開,載入器直接把整個 plugin 以 dependency-unsatisfied 停用。條目的原文結果是 “pstack loaded in the CLI and the VS Code extension but silently vanished from desktop-app sessions.”

作者先試過什麼?在 dependency 上標 optional: true。條目寫:”optional: true on a dependency entry passes claude plugin validate but is not honored by the loader (tested on 2.1.197).” 驗證指令放行,載入器不認。最後改成文件上寫「手動安裝」。這條死路的重點在於:claude plugin validate 綠燈,只證明格式合法,不證明在每個殼裡都載得起來。

0.9.84(2026-10-13 發布)是同一類。前一版 0.9.83 在 plugins/pstack/ 放了一份 Agent Plugins 1.0.0 格式的根 plugin.json。條目說,Codex 會先讀這份 manifest 再讀 .codex-plugin/plugin.json,而且對這種格式不載入 plugin hooks,所以在 Codex 上 SessionStart hook 停止執行,session 少了 pstack 的路由指示。0.9.83 發布到 0.9.84 修好,相隔 17 小時 47 分鐘。把格式換成比較新的那種,反而把功能弄沒了。

0.9.3 的條目自己就用了 silently 這個字;0.9.84 的條目沒說有沒有錯誤訊息,但結果相同:session 少了東西,plugin 不見了,hook 沒跑。

一天五版:路徑是被推出來的,推錯了就換一種推法

回到開頭那一天。五個版本的發布時間(UTC)是 08:46、12:22、12:52、15:45、19:00,從第一版到最後一版 10 小時 14 分。

v0.9.97 先出,修的是一個很不起眼的洞。awk 的 -v 參數會展開反斜線跳脫,所以 plugin 根目錄只要含 \t 或 \\,Windows 風格的路徑就是這樣,awk 就會被指到一個不存在的目錄。條目的結尾是:”The hooks then exited 0 with the mandate missing”. hook 以 0 結束,指令卻沒進去,一樣是靜默。改成用環境變數 PSTACK_HOOKS 傳。

接下來四版,都在處理 Claude Code 把檔案放在哪。其中 0.9.98、0.9.100、0.9.101 三版,回答的是同一個問題:腳本怎麼知道這個 session 的 transcript 在哪?

版本 腳本怎麼找 transcript 目錄 壞在哪/備註(條目原文或其意)
0.9.98 之前 skills 直接寫死固定路徑 ~/.claude/projects/ 設了 CLAUDE_CONFIG_DIR 時,Claude Code 寫在 $CLAUDE_CONFIG_DIR/projects/,”writes nothing to ~/.claude/projects/“
0.9.98 跟著 $CLAUDE_CONFIG_DIR/projects/ 條目載明由貢獻者 @Poggen 找到並修好(#298)
0.9.100 用系統提示裡的 primary working directory 推出來 那個標籤 “follows the shell rather than the directory the session started in”,agent 進了 worktree 就拿到 exit 1
0.9.101 用 CLAUDE_CODE_SESSION_ID 條目的 Verified 段:新測試在 0.9.100 失敗、在這版通過

夾在中間的 0.9.99(12:52,比 0.9.98 晚 30 分鐘)修的是同一族的另一半:Claude Code 把 plugins 與個人 skill 也放在設定目錄底下,變數一設,poteto-agent 就去一個空的 ~/.claude/plugins/ 找 poteto-mode,automate-me 也漏掉個人的 mode skill。條目有一句:”Both tests fail on 14 lines at 0.9.98 and pass here”,同時承認了一個限制:”A separate run with the variable set did not happen, because a new configuration directory starts logged out.”

最有戲的是 0.9.100 到 0.9.101,間隔 3 小時 15 分。0.9.100 改成用系統提示裡的 primary working directory 去推 transcript 目錄,三個多小時後就被推翻。0.9.101 的原文是這樣說它為什麼壞:”In 0.9.100 the skills passed the system prompt’s primary working directory, and that label follows the shell rather than the directory the session started in. After the agent moved into a worktree, recall, automate-me, reflect, show-me-your-work, and the Eval and Session pickup playbooks got exit 1.”

同一個動作換了四種推法,含最初寫死的那一種:寫死一個位置、跟著環境變數、從系統提示的標籤推、直接用 session 自己的 ID。前三種都在「猜 transcript 放在哪」,最後一種改成「問 session 自己是誰」。這是我從表格那四列歸納出來的,條目沒有用這種說法。

作者寫條目的習慣也值得看。我讀到的這幾條(至少 0.9.99 與 0.9.101),會講哪個測試在舊版失敗、新版通過,連「沒做到的那次實測」都寫出來,不躲。這個習慣的價值,在於你不需要信任作者的口氣,只要看證據的涵蓋範圍。

要不要裝:先看你手上有沒有一套在跑的路由

我的立場:如果你已經有一套自己在跑的路由與審查流程,不要把 pstack 整包裝進去;你還沒有的話,先讀 tools/forks.json 與 CHANGES.md,再決定裝不裝,因為這兩份是整個專案裡資訊密度最高的地方。

理由有四個,都出自文件,沒有一個是我跑出來的。

第一,它自己就預期小任務不該走這套。session-start 的路由文字寫:”For smaller tasks, such as a contained change to one file with an obvious test, a question, or a one-line edit, work directly and verify on the real artifact.” 觸發它的是三種情況:改多個檔案或簽章、做設計與架構選擇、原因未明的 bug 或效能問題。

第二,它預期自己會跟別的 session-start 指令共存。同一份文字結尾:”User instructions (CLAUDE.md, AGENTS.md, direct requests) take precedence. Other session-start mandates, such as superpowers, still apply.” 兩套都開時,觸發條件會不會重疊、結果怎麼樣,文件沒有量化。我推測可能會重疊,但沒有取證。想關掉 session hook,文件的說法是跑 /pstack:setup-pstack,或在 sheet 寫 session hook: off,這句出自 reference.md,我沒有重核過原文,裝之前自己對一次。

第三,成本沒有數字。arena、swarm、interrogate 這類 skill 的設計是派多個 subagent,panel 預設四個模型,所以我推測它比單線工作貴;這是從流程設計推出來的猜測,repo 裡沒有任何成本資料,我也沒有量過。

第四,執行品質取決於模型守不守規矩。它是 Markdown skill 加少量腳本,我讀到的範圍沒有看到強制執行的機制。作者把審查閘寫成規則:”A review gate stays closed when no independent reviewer can run.” 規則寫得清楚,不等於每次都會被遵守。README 與我讀過的文件裡,我沒找到成效評測,但我沒有逐檔搜過 benchmark 或 eval 這些字,所以只能說「沒找到」,不能說「沒有」。另外 reference.md 自己寫 “Delegation remains unverified on Prime Agent and Gemini CLI, and multi-model workflows on all three.”,README 也記了 Copilot 在 1.0.92 上的限制。驗證範圍就這麼大。

還有一個很實際的數字:10 月 21 日那一天五版,到 10 月 22 日已經是 v0.9.102。每次更新都可能動到行為,要不要追,要自己去看 CHANGES。

會讓我改變想法的條件,我列三個。第一,有人拿同一批任務,公開有裝與沒裝 pstack 的對照結果,而且不是作者自己跑的,那我對第四點的保留就得收回。第二,作者文件寫明兩套 session-start 指令並存時誰先、衝突時怎麼辦,而不是只寫一句 “still apply”,那我對第二點的推測就得刪掉。第三,路徑這類修補連續幾週沒有再出現同型的 hotfix,那「版本變動快」這個理由就弱了。這三個至少要有一個成立,我才會把「有自己流程就不要裝」改成「可以試試」。

背後是兩條線:上游擁有內容,port 擁有翻譯。兩條線重疊的地方,就是 forks.json 那 47 筆登記的東西,其中 policy 那些,每次同步都得重新談一次。我會先帶走的,是「偏離要登記,而且每一筆要說得出理由」這個做法。