在 GitHub 閒逛時發現了 Innei 的 SKILL 倉庫,裡面有個 session-to-skill-and-blog技能,核心概念很妙:把一次折騰的工程對話,沉澱成兩個產出——一個可重複使用的 AI skill,一篇帶連結的部落格。鐵律是先寫 skill 再寫 blog,因為 blog 需要 skill 的 URL,而且 SKILL.md 的格式強迫先把操作性內容理清楚。想法很好,但它是為 Innei 自己的基礎建設量身打造的——skill 存在他的 GitHub 倉庫,blog 透過 mxs CLI 發到他的 mx-space 部落格。我也有 mx-space(pinw.ca),所以決定把它改成適合自己環境的版本。這篇文章記錄改造過程中踩到的坑和學到的教訓。第一坑:伺服器不在本機安裝完 skill 後第一件事就是跑 mxs auth login。結果:TEXT → probing http://localhost:2333… ✘ connection refused 我的 mx-space 跑在遠端伺服器上,API 位址是 https://api.pinw.ca,不是本機。嘗試加 --api-url 參數:BASH mxs --api-url https://api.pinw.ca auth login 沒用,它還是去連 localhost。翻原始碼發現 mxs auth login 的 --api-url 傳遞鏈有問題——global flag 在 auth 子命令裡沒有正確接管。改用環境變數:BASH MXS_API_URL=https://api.pinw.ca pnpm mxs auth login 這次成功了。認證後 config 寫入了 ~/.config/mxs/profiles/default/config.json。Note教訓:mx-space CLI 的 global flag 與子命令之間的 override 優先級在不同版本中行為不一致。環境變數 MXS_API_URL 是最可靠的跨版本配置方式。第二坑:profile 不會自動啟用認證成功後,我以為萬事大吉。直接跑:BASH pnpm mxs auth whoami # 結果顯示未認證 但 auth status 卻正常:BASH pnpm mxs auth status # 已登入為 pintaste · pintaste@outlook.com 接著來看 mxs category list的內容:TEXT ✘ connection refused 它又在連 localhost。明明 config.json 裡 api_url 已經是 https://api.pinw.ca,current 指標也指向 default。但 pnpm mxs 在 monorepo 環境下沒有正確讀取 profile。明確指定 profile 解決:BASH pnpm mxs --執行了 profile default category list --output llm # 成功回傳 9 個分類 於是我在 resolve-mxs.sh 裡加上了 --profile default,所有腳本呼叫 mxs 時自動帶上。Note教訓:在 monorepo 裡透過 pnpm mxs 呼叫時,profile 解析路徑可能不同於全域安裝。明確指定 --profile 比依賴 current 指標更可靠。第三坑:snippet API 版本差異原版 skill 的 push-skill.sh原版 skill 的 t_69 用法如下:BASH mxs snippet create --指令為 name "skill-name" --type skill --file SKILL.md mxs snippet get "skill/skill-name" --json 但我的 mxs 版本(0.13.2)的 snippet 子命令完全不同——它是 VFS 風格的:BASH mxs snippet put --對應的語法為:type skill --file SKILL.md "skills/name/SKILL.md" 而且路徑必須以 /SKILL.md 結尾:TEXT ✘ skill snippet path must end with /SKILL.md 這個限制在文件裡沒有任何提示,只能從錯誤訊息反推。改造後的 push-skill.sh 從 60 行精簡到 30 行,因為 VFS API 本身就是冪等的——同一個 path 重複 put 就是更新。第四坑:過早抽象化第一版改造我犯了一個經典錯誤:看到使用者的部落格目錄下有 hugo.pinw.ca/,就假設部落格是 Hugo,把整個 skill 改成了 Hugo 工作流(hugo new、git push → Netlify)。使用者糾正說「我現在的網站也是 mx-space」——原來 pinw.ca/core/ 和 pinw.ca/Yohaku/ 才是主站。這個錯誤的根本原因是:在沒確認當前架構的情況下,根據目錄名稱做了推論。 hugo.pinw.ca 是舊部落格的遺留目錄,真正在跑的 mx-space 後端就在旁邊的 pinw.ca/core/。Warning教訓:不要根據目錄名稱推論技術棧。先問使用者,或者檢查實際執行的服務。一個目錄叫 hugo.xxx 不代表 Hugo 是主站。最終的改造方案以下是改造前後的對照:元件Innei 原版pinw.ca 版本Skill 存放位置~/git/innei-repo/skill/~/.pi/agent/skills/mxs 呼叫方式全域 mxspnpm mxs --profile default腳手架含 README/symlink/git stage只建立目錄 + stubSnippet APIcreate --type skillput --type skill(VFS)設定檔~/.config/innei-skills/config.json無需設定檔全部 7 個腳本中,5 個需要改寫(resolve-skill-repo.sh、scaffold-skill.sh、push-skill.sh、publish-post.sh、get-post.sh、update-post.sh),1 個新增(resolve-mxs.sh),1 個保持不變(load-litexml.sh)。可帶走的判斷這次改造暴露了三個通用原則,不只 mx-space 適用:確認執行狀態,不要推論。目錄名稱叫 hugo.xxx 不代表主站是 Hugo。先問 ps、docker ps、curl,再動手。CLI 工具的 global flag 不可靠時,改用環境變數。--api-url 在子命令中的傳遞行為因版本而異,MXS_API_URL 在原始碼裡是第一優先級。Monorepo 裡的 CLI 呼叫需要明確指定 profile。pnpm mxs 的環境解析不同於全域 mxs,--profile 是唯一可靠的定位方式。改造完成的 skill 已經在 ~/.pi/agent/skills/session-to-skill-and-blog/ 就位,本文正是用它發布的——吃自己的狗糧。Skill 網址:Innei/SKILL — session-to-skill-and-blog(原版,本文的靈感來源)
在 GitHub 閒逛時發現了 Innei 的 SKILL 倉庫,裡面有個 session-to-skill-and-blog技能,核心概念很妙:把一次折騰的工程對話,沉澱成兩個產出——一個可重複使用的 AI skill,一篇帶連結的部落格。鐵律是先寫 skill 再寫 blog,因為 blog 需要 skill 的 URL,而且 SKILL.md 的格式強迫先把操作性內容理清楚。
想法很好,但它是為 Innei 自己的基礎建設量身打造的——skill 存在他的 GitHub 倉庫,blog 透過 mxs CLI 發到他的 mx-space 部落格。我也有 mx-space(pinw.ca),所以決定把它改成適合自己環境的版本。這篇文章記錄改造過程中踩到的坑和學到的教訓。
第一坑:伺服器不在本機
安裝完 skill 後第一件事就是跑 mxs auth login。結果:
我的 mx-space 跑在遠端伺服器上,API 位址是 https://api.pinw.ca,不是本機。嘗試加 --api-url 參數:
沒用,它還是去連 localhost。翻原始碼發現 mxs auth login 的 --api-url 傳遞鏈有問題——global flag 在 auth 子命令裡沒有正確接管。改用環境變數:
這次成功了。認證後 config 寫入了 ~/.config/mxs/profiles/default/config.json。
教訓:mx-space CLI 的 global flag 與子命令之間的 override 優先級在不同版本中行為不一致。環境變數 MXS_API_URL 是最可靠的跨版本配置方式。
第二坑:profile 不會自動啟用
認證成功後,我以為萬事大吉。直接跑:
但 auth status 卻正常:
接著來看 mxs category list的內容:
它又在連 localhost。明明 config.json 裡 api_url 已經是 https://api.pinw.ca,current 指標也指向 default。但 pnpm mxs 在 monorepo 環境下沒有正確讀取 profile。
明確指定 profile 解決:
於是我在 resolve-mxs.sh 裡加上了 --profile default,所有腳本呼叫 mxs 時自動帶上。
教訓:在 monorepo 裡透過 pnpm mxs 呼叫時,profile 解析路徑可能不同於全域安裝。明確指定 --profile 比依賴 current 指標更可靠。
第三坑:snippet API 版本差異
原版 skill 的 push-skill.sh原版 skill 的 t_69 用法如下:
但我的 mxs 版本(0.13.2)的 snippet 子命令完全不同——它是 VFS 風格的:
而且路徑必須以 /SKILL.md 結尾:
這個限制在文件裡沒有任何提示,只能從錯誤訊息反推。改造後的 push-skill.sh 從 60 行精簡到 30 行,因為 VFS API 本身就是冪等的——同一個 path 重複 put 就是更新。
第四坑:過早抽象化
第一版改造我犯了一個經典錯誤:看到使用者的部落格目錄下有 hugo.pinw.ca/,就假設部落格是 Hugo,把整個 skill 改成了 Hugo 工作流(hugo new、git push → Netlify)。使用者糾正說「我現在的網站也是 mx-space」——原來 pinw.ca/core/ 和 pinw.ca/Yohaku/ 才是主站。
這個錯誤的根本原因是:在沒確認當前架構的情況下,根據目錄名稱做了推論。 hugo.pinw.ca 是舊部落格的遺留目錄,真正在跑的 mx-space 後端就在旁邊的 pinw.ca/core/。
教訓:不要根據目錄名稱推論技術棧。先問使用者,或者檢查實際執行的服務。一個目錄叫 hugo.xxx 不代表 Hugo 是主站。
最終的改造方案
以下是改造前後的對照:
全部 7 個腳本中,5 個需要改寫(resolve-skill-repo.sh、scaffold-skill.sh、push-skill.sh、publish-post.sh、get-post.sh、update-post.sh),1 個新增(resolve-mxs.sh),1 個保持不變(load-litexml.sh)。
可帶走的判斷
這次改造暴露了三個通用原則,不只 mx-space 適用:
改造完成的 skill 已經在 ~/.pi/agent/skills/session-to-skill-and-blog/ 就位,本文正是用它發布的——吃自己的狗糧。
Skill 網址:Innei/SKILL — session-to-skill-and-blog(原版,本文的靈感來源)