[CODE]

一個指令接好一個新客戶——再用 CI 守門員把這套劇本擋在 main 之外

以前接一個新民宿進分析 agent,要手動重跑十幾個容易出錯的步驟。我把整段流程包成一個 Claude skill,一個 session 跑完;然後加了一道 CI 守門員,確保這個塞滿內部路徑和 secret 配置的 skill 永遠不會進到公開分支。

1 min read AI 生成
claude-code ci-cd automation google-ads ga4

以前接一個新客戶進分析 agent,是我每個月最容易出錯的一件事。不是哪一步特別難——是步驟有十幾個,一個接一個,漏掉任何一步,就會做出一個看起來設定好、實際上什麼都沒回報的站台。

這篇講的是一起出貨的兩件事:一個能在單一 session 內完成整套客戶上線的 Claude skill,加上一道把這個 skill 擋在公開分支外的 CI 守門員。這個 skill 塞滿了內部路徑和 secret 的擺放位置。兩件事會綁在一起,是因為背後是同一個張力:劇本越強,外洩越危險。

手動做就守不住的工

分析 agent 會幫恆春幾家民宿跑每週的營運週報。每個站台都需要同一套骨架:一個 config 檔、一份給分析 AI 讀的 business-context(避免它誤判流量)、一份 ads-health context、一份營運 runbook、一份收件人清單,還有一個 operator-events.yaml 事件記錄。這些都不是難的部分。

難的部分是,這套骨架必須反映真實的站台,而且要在系統的兩端都把追蹤接好。網站的 analytics.ts 需要 GA4 和 Google Ads 標籤。Google Ads 帳號需要建立轉換動作——而這些動作會回傳真實的 AW- 標籤和轉換 label,這些 label 又得貼 analytics.ts。只要出貨時 label 還是 placeholder,網站上的聯絡按鍵點擊——電話、聯絡按鈕、立即訂房——就永遠不會被算成轉換,整條 pipeline 的意義就這樣悄悄失效了。

這趟來回,就是沒有人第一次手動做能做對的地方。你建好轉換動作、忘了把 label 抓回來、出貨時帶了個 placeholder,三週後轉換欄位讀到零,你才回頭重建你漏掉了什麼。

這種工,是因為有了 AI 才划得來才會存在。一家小民宿沒辦法養一個工程師花一整天細心接 analytics、再養一個廣告專員建轉換動作、再找人驗證來回有沒有接上。把這些綁在一起,從來就不在小業者的預算內。這個 skill 把它壓進一個 session。

skill 先讀網站,再動筆

我認定的設計原則是:**絕不寫 placeholder。**所有產出檔案裡的 ID、label、email、URL,在寫檔之前都必須是真的。值還不知道,skill 就先把它收集起來。

所以 skill 一開始會去讀網站的原始碼——本機路徑或一份新 clone 的 GitHub repo——抽出真正的業務資料:聯絡管道、頁面、房型與商品資訊、CTA。產出的 business-context.md 反映的是這個特定站台,不是一個通用樣板。這在後段很重要:每週的分析 AI 會讀這份文件,才知道這家民宿的旺季和在地脈絡,不會把一個正常的淡季下滑誤判成問題。

接著它從模板生出 sites/<slug>/ 底下七個檔案,模板就放在 skill prompt 旁邊。模板是起點,依讀到的程式碼調整——不是最終產出。

撐起整件事的是最後一個階段。skill 更新網站的 analytics.ts,接著用 Google Ads API 建立轉換動作,把真實的標籤和 label 讀回來,再插進去。這趟來回在同一個 session 內、由同一個建立兩端的角色完成。這正是人會斷線的那一步;skill 不會,因為它在拿到真值之前不會跳到下一個檔案。

這個 skill 太好用,不能公開

第二件事要解的問題在這裡。這個 skill 真的有價值——而它的價值,來自它引用了專案內部:sites/scripts/ 的結構、ads client 的路徑、secret 目錄的擺放、它依賴的已安裝套件。讓它能跑的那份具體性,外洩出去就成了負債。一個指名 secret 放哪、ads client 怎麼接的 skill,是一張我不想放上公開分支的地圖。

工作記錄和決策筆記也一樣——HANDOFF.mdWORKLOG.mdDECISIONS.md。這些天生就只屬於 dev。它們誠實地描述系統,包括那些你永遠不會放進 README 的東西。

直覺的做法是:合併前記得刪掉。第一次累的時候就破功了。所以我改成做了一道 CI 守門員。

守門員讀的是一份清單,不是 workflow

值得點名的設計決定是:dev-only 路徑的清單,放在一個 CI 守門員會去讀的純文字檔,不是寫死在 workflow 的 YAML 裡。一行一個路徑。結尾有斜線代表目錄——裡面任何檔案都算違規。沒有斜線就是精確比對單一檔案。井字號開頭是註解。

只要清單上的任一路徑出現在非 dev 分支,守門員就讓 build 失敗。要保護一個新的 dev-only 路徑,你在那個檔案後面加一行。守門員下一次 push 就會吃到——不用改 workflow,不用維護第二個地方。

最後這點,就是它得是獨立檔案的全部理由。安全守門員的失敗模式不是它不在——是它要保護的東西,跟「要保護什麼」的清單漸漸對不上。把清單放進 workflow,下一個加 dev-only 文件的人就得知道 workflow 存在、還要改對。把清單放進一個 workflow 會去讀的檔案,加保護就是在你本來就在動的同一個目錄裡補一行。守門員之所以一直正確,是因為維持它正確不花任何成本。

為什麼這是一個故事,不是兩個

skill 和守門員看起來不相干——一個接客戶,一個管分支。它們其實是同一個決定的兩面。skill 的威力來自它的具體性:它知道每樣東西確切在哪。而那份具體性,正是不能公開的東西。把能力和圍堵放在同一次合併裡做完,不然前者就是一顆等著外洩的地雷。

以前讓我很怕的上線流程,現在是一個指令——而讓它能跑的那個東西,逃不出它該待的那條分支。