跳至主要內容
Daily Operations Management

SuperPortia 日常運維 — 一個人怎麼管 11 個 Repo

3 分

一人團隊管 11 個 repo,聽起來像是在自找麻煩。但如果你把規則寫進工具而不是留在腦子裡,實際上比管一個亂掉的 monorepo 還輕鬆。

這篇文章把 SuperPortia 目前的日常運維架構攤開來說清楚:為什麼要從 monorepo 拆分出去、session 的完整流程是什麼、Work Order 的角色、跨機器 config 怎麼不漂移、以及 hooks 怎麼把規則從「建議」變成「執行」。

日常運維依賴的治理框架詳見 EGS — 工程治理規範;多 agent 協作如何在這個框架下運作,參考 多代理 CLI 協作實錄


為什麼要拆成 11 個 Repo

SuperPortia 最初是一個 monorepo。所有東西在一起,方便開始,但隨著 agent 數量增加、部署目標分化(Cloudflare Workers、Pages、本地服務),問題開始出現:一個 frontend 的 commit 觸發全域 build、不同服務的依賴互相污染、CI 不知道哪段程式碼改了要重新部署哪個服務。

ADR-0010 確立了拆分原則:1 repo = 1 deployable。每個 repo 有自己的部署單元,可以獨立 commit、獨立部署、獨立管理依賴。用 git filter-repo 拆分,完整保留每個服務的 commit 歷史——不是 git subtree、不是新建空白 repo,是真正的歷史保留。

最終的 11 個 repo 按照用途分類:

類別Repos
基礎設施superportia-opssuperportia-sresuperportia-mcp-server
知識庫superportia-vault
產品服務superportia-bridgesuperportia-command-centersuperportia-docs-site
AI Pipelinesuperportia-ub-pipelinesuperportia-ub-worker
內容superportia-blogkol-narratives

拆完之後,一個 Cloudflare Worker 的改動只影響 superportia-ub-worker。Frontend 改了只跑 superportia-bridge 的 build。每個 deployable 的生命週期彼此獨立,不再互相干擾。


Session 的完整流程

SuperPortia 的工作單位是「session」——agent 開始工作到結束工作的一個完整週期。session 有明確的開始協議和結束協議,不是隨便開個終端機就開始改程式碼。

Session Start

每次 session 啟動,session-startup.sh hook 自動觸發。這個 hook 做兩件事:從 Cloud UB 拉取佈告欄(bulletin board)的最新內容,把它注入到 session context;然後列出開機自檢的待辦清單:

  1. 查看待辦工單
  2. 查看 agent 信箱
  3. agent 報到上線(heartbeat)
  4. 確認夏哥當前位置
  5. 回報「開機自檢完成」

這個流程確保 agent 在開始工作之前,先知道公司目前的目標和優先順序。不是靠記憶,是靠工具拉到最新資料。

agent-intelligence-protocol.md 定義了 session start 的具體行為規則:MEMORY.md 是 context,不要在啟動時大量讀 UB entries,只做 2 個呼叫(heartbeat + mailbox check),然後問夏哥要做什麼,按需讀資料。

工作中

工作進行中有幾個關鍵協議:

Pre-Decision 檢查:在做重要決定(選哪個 engine、用什麼架構)之前,先搜尋 UB 有沒有前例。找到就先回報前例再決定;找不到就繼續,備注「no UB precedent」。

Discovery 記錄:學到重要的新事實、模式、洞察時,立刻寫進去——個人知識進 Memory MCP,團隊知識進 UB ingest_fragment。不是「之後再說」,是當下就做。

Correction Capture:夏哥說「這個不對」時,dual ingest——Memory MCP 用 CORRECTION: 前綴,UB 用 ingest_fragmentcorrection tag。個人記憶和團隊記憶都更新。

Session End

session 結束只有一個觸發條件:夏哥明確說「收工」、「結束」、「下班」。Agent 不會自己說「要結束了嗎?」——這是規定,不是禮貌。

結束流程包含三件事:

  1. 確認所有 ingestion 完成
  2. 寫當日工作日誌到 vault(60-Daily/YYYY-MM/YYYY-MM-DD.md
  3. 寫 session handoff 到 UB(ingest_fragment,tag: session-handoff

session_end_daily_log.sh hook 在 session 結束時自動寫一個 stub 到 vault,確保即使 agent 忘記,也有最低保障的記錄。但 stub 只是保障,完整的 handoff 仍然需要 agent 親手寫。


Work Orders 是唯一的任務頻道

公司憲法(Company Constitution)§3 只有一句話:Tasks via WO system. No verbal promises.

不管任務是什麼——寫程式、做研究、部署服務——都必須走 Work Order。口頭說「等等做這個」不算數。沒有 WO,沒有任務。

這個規定解決了一個實際問題:一人帶多個 agent,各個 agent 都有自己的 session,如果任務散落在各種對話裡,很快就會出現「我以為你在做」和「我以為那個不急」的狀況。WO 是唯一的真相來源。

WO 的生命週期:建立(create_work_order)→ 開始工作 → 完成後提交審查(review_work_order)→ 夏哥批准或退回。每個 WO 都有 ID,可以追蹤,可以搜尋,可以跨 session 接手。

Company Constitution §8 補充了一條規則:在同一個 session 內開始或回報 WO,不說「下次再做」。 這防止了 WO 在系統裡堆積成未被處理的債務。


Cross-Ship Sync 與五鐵律

SuperPortia 跑在兩台機器上:SS1(Mac)和 SS2(Windows)。兩台機器都跑 Claude Code,都需要一致的 agent 行為——一樣的 rules、一樣的 skills、一樣的 hooks。

問題是:如果每台機器各自維護自己的 .claude/ config,遲早會漂移。2026-03-10 的事故就是這樣發生的:SS2 比 SS1 少了 11 個 hooks,EGS 落後兩個版本。Agent 在 SS2 上的行為和在 SS1 上不一樣,而沒有人注意到,直到出了問題。

解法是確立 superportia-ops 為唯一 SSoT(Single Source of Truth),然後用五鐵律防止漂移再發生。

五鐵律

鐵律一:SSoT 唯一性。 superportia-ops.claude/ 的唯一來源。想改 skill、rule、hook → 改 ops repo,不改本地。

鐵律二:單向流動。 Config 只從 ops 流向各台機器,永不逆流。SS2 上寫了新 skill?先 PR 到 ops,merge 後再 sync 下來。直接在 SS2 的 .claude/ 改然後「之後再同步」——這就是 drift 的根源。

鐵律三:Sync 覆蓋本地。 sync_from_ssot.sh 執行時,本地 .claude/ 被 ops 版本完全覆蓋。本地未提交的修改會被丟棄。這是設計,不是 bug。

鐵律四:新建必歸源。 在任何機器上新建 skill、rule、hook,必須在 ops repo 上建。流程:ops repo 建檔 → push → 各機器 git pull / sync 取得。

鐵律五:衝突時 ops 贏。 任何 .claude/ 內容衝突,ops repo 版本為準。沒有例外。

實務同步方式

# SS1(Mac)— 一次性設定 symlink
cd ~/Documents/superportia-bridge   # 任一 repo
ln -s ../superportia-ops/.claude .claude
# ops 一 push,所有 symlink repo 立刻生效

# SS2(Windows)— 每次 ops 有新 push 後執行
cd C:/Users/XYZ/superportia-ops && git pull
bash scripts/sync_from_ssot.sh   # 完全覆蓋本地 .claude/

# 確認 symlink 正確(SS1)
ls -la ~/Documents/superportia-bridge/.claude
# 應顯示 → ../superportia-ops/.claude
Symlink 模式的優勢

SS1 的 symlink 設計意味著:ops repo 一旦有新的 hook 或 rule 被推送,所有使用 symlink 的 repo 立刻反映,不需要手動同步。這消除了「我以為我在用最新版本」的模糊地帶。

五鐵律的核心:Sync 覆蓋本地

sync_from_ssot.sh 執行時,本地 .claude/ 被 ops 版本完全覆蓋,本地未提交的修改會被丟棄。這是設計,不是 bug。如果你在本地的 .claude/ 裡改了什麼但沒推回 ops,那份修改會消失。正確做法:先 PR 到 ops,merge 後再 sync。

SS1(Mac)用 symlink:每個 repo 的 .claude/ 是一個指向 superportia-ops/.claude/ 的符號連結。ops 一 push,所有 repo 的 agent config 立刻生效,不需要手動同步。

SS2(Windows)用複製覆蓋:git pull ops 之後執行 sync_from_ssot.sh,把本地 .claude/ 完全換成 ops 版本。


Hooks 是規則的執行層

規則寫在文件裡,但文件沒有人讀的時候什麼都不是。Hooks 是規則和現實之間的橋樑——它們在工具使用的節點自動觸發,不需要 agent 記住要做什麼。

superportia-ops/.claude/hooks/ 目前有 16 個 hooks。幾個關鍵的:

deploy-gate.sh(PreToolUse, DENY)

攔截所有 wrangler deploywrangler publish 指令。如果沒有 --dry-run flag,直接 deny,並要求先跑 dry-run 確認,再拿夏哥的 go-ahead。

這個 hook 的起源是一個教訓:agent 自以為在測試環境部署,結果直接推到 production。現在這個情境不可能再發生——工具層面就擋住了。

commit-format-check.sh(PreToolUse, ASK)

檢查 git commit message 是否有 [bracket] 前綴。格式:[Stage X] Verb + Content,例如 [EGS] Add deploy gate hook。格式不對就提問(ASK mode)——不是強制 deny,是給 agent 一個修正的機會。

protect-files.sh(PreToolUse, DENY)

保護敏感 config 不被 agent 直接修改。受保護的檔案清單:.env.env.local.env.productionsettings.jsonsettings.local.jsonwrangler.toml。任何嘗試 Edit 或 Write 這些檔案的操作都被 deny,並要求夏哥授權。

post-edit-lint.sh(PostToolUse, LOG)

在 Edit 或 Write 操作之後自動執行語法檢查。Python 檔案用 ast.parse;JSON 用 json.load;Shell 腳本用 bash -n。語法錯誤立刻回報,agent 在同一個 context window 內就能修正,不用等到執行時才發現。

pre-commit-build-check.sh(PreToolUse, DENY)

在 commit 之前,如果 staged 的變更包含 frontend 程式碼,先跑 npm run build。Build 失敗就 deny commit。這個 hook 的起源:frontend 壞掉的程式碼被 commit 進去,deploy 之後才發現,要花時間 rollback。現在這個情境在 commit 階段就截住了。

session-startup.sh(Session Start)

前面提到的開機 hook,拉取 bulletin board 並注入 pre-flight checklist。


規則沒有 Hooks 只是建議

回頭看這整套架構,核心原則其實很簡單:把決策留給人,把執行交給工具。

五鐵律防止 config 漂移,但沒有 symlink 和 sync script 的話,鐵律只是文字。WO system 確保任務可追蹤,但沒有 create_work_order 工具的話,還是得靠記憶。Hooks 把規則編碼進 agent 的工具呼叫鏈,讓「deploy 前先 dry-run」不再是一條需要背的規則,而是一個不可跳過的步驟。

一人管 11 個 repo,靠的不是超人的記憶力,而是讓基礎設施記住你該做的事。


SuperPortia 是一個以 AI agent 為中心建構的營運系統,目前由 Mac CLI 小克(Claude Code)在 SS1 執行日常工程工作。架構持續演進中,本文描述截至 2026-03-16 的現況。