航海日誌:我和副官 Claude Code,怎麼讓一座 AI 新聞站每天早上自己醒過來

一座每天早上九點自己醒來、自己抓新聞、自己叫 AI 分類的策展站,是怎麼一句一句對話蓋出來的?這篇把船長與副官 Claude Code 的交班全程原話留下來——什麼時候我下令,什麼時候它停下來請我出手。

分享
航海日誌:我和副官 Claude Code,怎麼讓一座 AI 新聞站每天早上自己醒過來
開發航海日誌(二)| 船長 Balung · 副官:Claude Code · 航行日期:2026-05-13 → 06-10

上一艘船,我把四座漂在不同海域的統計小島連成了一塊大陸。那篇〈航海日誌:從零到上線〉裡,副官(Claude Code)多半在划槳,我這個船長偶爾出手。很多人讀完問我同一句話:「你們之間到底是怎麼講話的?什麼時候你下令,什麼時候它停下來等你?」

這一篇,我換一艘更難開的船來回答這個問題。

這次要蓋的,不是一個「打開來給你玩」的靜態網站,而是一座每天早上九點會自己醒過來的新聞站——AI Daily Brief。它得在天還沒亮的時候,自己去十幾個來源把昨天的 AI 新聞撈回來,自己判斷哪些重要、該歸到哪一類,自己寫進資料庫,趕在我起床喝第一口咖啡之前,把當天的日報擺上網站。每週一,還要多生一份週報。

靜態網站翻船頂多是畫面壞掉;這艘船底下有一具會燒錢的引擎——每天叫醒一次 AI、一座永遠在線的資料庫、一個對全世界開著的網址。所以這趟航行,對話比上次更密、分界更清楚。我會盡量把當時我們一來一往的原話留下來,讓你看見 Vibe Coding 真正運轉時,人跟 AI 是怎麼交班的。

先把兩個角色講白:船長,是我這個人類——定方向、做決策、把關品味、在關鍵時刻拍板,還有按下所有「收不回來」的鈕。副官,就是 Claude Code——能讀懂整包專案文件、自己寫程式、跑測試、開瀏覽器驗證的 AI。下文凡寫「副官做了什麼」,就是「Claude Code 自己把那段做出來、跑出來」。

這篇很長。我們從第一句話開始。

全程流程海圖:對齊航向→空船下水→裝引擎→每天九點自動上線→調校改版
第一章字卡:先對齊航向

第一章:開工前的第一句話——「先讀文件,先別寫程式」

航行日期:2026-05-13

我把整個專案資料夾用 Claude Code 打開。左邊檔案樹一攤開,05-app/ 還空著,但旁邊已經躺著一套寫好的文件。我下的第一道指令,不是「幫我做網站」。我打的是這句:

請你先讀這個資料夾裡的 harness 文件,特別是 CLAUDE.mdSPEC.mdARCHITECTURE.mdROADMAP.md。讀完告訴我你打算怎麼進行。先不要動手寫程式。
名詞解釋:harness 文件是什麼

為什麼這樣下?因為「先寫文件」的回報,就在這一刻兌現:我要先確認副官讀過海圖、站回同一條航線,再讓它碰程式碼。它讀完,回我的不是程式,而是一段複述——把這艘船的鐵律一條條唸回來給我聽:

收到。我把這個專案的航向複述一遍,您確認對得上再開工:

一、部署優先。先打通「本機 → GitHub → Vercel」的管線,第一次只推一個極簡測試頁,看到上線、確認每次 push 都會自動部署,再回頭長功能。
二、去重以原始連結 URL 為唯一鍵,而且去重要在呼叫 LLM 之前——重複的新聞不能重複花錢叫醒 AI。
三、不存新聞全文,只留標題、連結、來源、分類、重要性分數、摘要。
四、所有時間以台灣時間顯示,資料庫一律存 UTC。
五、排程的 endpoint 要用 CRON_SECRET 擋住,不讓外人亂打。
六、API key 絕不寫死在程式裡、絕不進 git;MVP 不做使用者系統。

它複述的航向,跟我海圖上畫的對得起來。對得上,才開工。這就是我心目中 Vibe Coding 的第一步——不是對著 AI 喊一句就生出網站,而是先讓它跟你站在同一張海圖前,把你信什麼、怕什麼,先講清楚。

誰掌舵、誰划槳:白紙黑字的三條界線

分工不能只靠精神喊話,它寫死在 ROADMAP.md 的「人機協作規範」裡,把界線切成三種——這也是這整篇日誌的骨架:

  • 副官自己做、不必問我:讀寫程式碼、跑測試、在本機起伺服器預覽、打包、開瀏覽器自己截圖比對、本機 commit。這些可逆、可自動,丟回來問我反而是浪費。
  • 副官一定要停下來、當場點名請我做:安裝新套件、把程式 push 上雲端、部署上線、用我的真實金鑰去呼叫付費 AI。這些要嘛花錢、要嘛對外、要嘛收不回來。
  • 只有我能親手做的(副官根本沒權限碰):到 GitHub 開 repo、到 Vercel Dashboard 設環境變數、到 Supabase 貼 SQL 建表、把真實 API key 放進 .env,以及最後——親手按下這篇部落格的 publish。

所以接下來你會一直看到一個畫面:副官划得飛快,但每撞到一條「對外、花錢、收不回來」的界線,它就停下來,具體地點名請我出手。一隻腳踩在岸上、一隻腳踩在船上——Vibe Coding 的分工,就是這個樣子。

第二章字卡:先讓空船下水

第二章:先讓空船下水——只是這次,船底有一具引擎

航行日期:2026-05-13

第一章講完規矩,副官沒有急著去寫抓新聞、叫 AI 那些「酷」的東西。它照著「部署優先」的鐵律,先做一件看起來什麼都沒做的事:讓一個空殼先成功上線。

它用 create-next-app 搭好骨架,把首頁改成一張極簡的測試頁——深色背景、置中、一行大字:「⚓ 這是 Captain Balung AI 日報 · Coming Soon」。然後它在本機跑起來,自己開瀏覽器確認畫面正常,接著就走到了那道它跨不過去的界線。它停下來,點名請我:

船長,空殼我準備好了,本機也驗過了。但接下來這步我沒有權限,得請您親手到 GitHub 處理:
請到 github.com/new 開一個 repo,設成 Private,三個初始化選項(README / .gitignore / license)都不要勾
開好之後,把 repo 的 URL 貼回來給我,我就把程式碼推上去。

那三個選項為什麼都不能勾?因為我本機已經把檔案和版本準備好了,如果讓 GitHub 再幫忙塞 README 進去,兩邊就會打架。空船塢,就讓它空著。

我照做,開好,把網址貼回去。副官接手,把 remote 接上、推送:

收到 URL。我執行 git remote add origin …git branch -M maingit push -u origin main
推之前我先 git add . 再跑一次 git status 給您看清單——確認 .env 不在裡面,才 push。這是紅線,每次都要當著您的面確認。

這是我特別欣賞的一個小動作:每次 git add 之後主動 git status、當場跟我確認金鑰沒被夾帶上去。不是我盯著它,是它把這條紅線內建成習慣。

「請你直接用 CLI 幫我把 Vercel 接起來」

程式碼上了 GitHub,下一關是 Vercel。這裡有一段對話我印象很深。我本來想偷懶,丟了一句:

船長:接下來 Vercel 的部分,你直接用 CLI 幫我處理掉。

副官沒有照單全收,反而幫我把界線劃清楚——哪些它能用指令代勞,哪些非得我本人點不可:

可以,但有一段我代不了,先跟您講清楚分工:

我能用 CLI 做的:之後 vercel 指令打包、vercel env pull 把雲端的環境變數拉回本機對帳、vercel logs 撈線上日誌來除錯——這些我自己來。
非得您本人做的:第一次把這個 GitHub repo 授權給 Vercel、以及把真實的 API key 貼進 Vercel 的環境變數。金鑰要經過您的手,不能從我這邊流過去。

所以請您先到 Vercel Dashboard:Add New → Project,import 這個 repo,按下 Deploy。先別管環境變數,讓這個空殼上線就好。網址出來後貼給我。
名詞解釋:Vercel 是什麼

看到沒有——同樣一句「你幫我處理」,副官沒有衝過界線去碰我的金鑰,而是把能自動的攬下來、該我做的明確退回給我。該人類動手的,AI 會點名請你做,而不是自己亂闖。

幾十秒後,Vercel 的網址活了過來,上面就是那張樸素的「Coming Soon」。我們三個檢查點全亮綠燈:本機看得到、GitHub 看得到、Vercel 線上看得到。為了確認「每次 push 都會自動部署」真的成立,副官還故意改了首頁一行小字、推上去,叫我等兩分鐘重整——果然自己更新了。水管通了,接下來才輪到水龍頭。

第三章字卡:裝進引擎

第三章:把引擎裝進船艙——抓取、去重,然後才敢叫醒 AI

航行日期:2026-05-13 → 05-21

空船能自動上線之後,才開始裝真正的引擎。這座引擎的工序是一條鏈:並行抓取 → 去重 → 叫 AI 分類評分 → 寫進資料庫

抓取這段副官完全自理:它寫好一個共用的 RSS/API 抓取層,接上第一批來源——OpenAI、DeepMind、Google Research、Hugging Face 四個官方部落格,加上 Hacker News 和 arXiv。寫完它自己跑了一個 test-fetch 腳本,確認每個來源都撈得到東西,才回報給我。這一段我沒插手,因為它可逆、可自動、出錯也只是本機跑不動,丟回來問我是浪費。

但鏈條中間那一步,副官特地停下來跟我確認了一件事——這也是這艘船跟上一艘最不一樣的地方:

船長,這裡有個順序我想跟您敲定:去重一定要排在叫 AI 之前。
官方部落格的同一篇文章,明天、後天我還是會在 RSS 裡再抓到它。如果不先用 URL 把重複的擋掉就送進 LLM,等於每天替同一篇新聞重複付一次 AI 的錢。所以我用原始連結 URL 當唯一鍵,先跟資料庫比對、把看過的丟掉,剩下的「真的新」的,才送進 AI。
這也讓後面一個決定變得很安全——抓取的時間窗就算開很大,重複抓到的也不會多花一毛錢。這點第六章會用到。

我拍板。對一個「每天都會自己花錢」的系統,省錢的紀律不是上線後才補,是設計第一天就釘進鏈條裡。

停下來請我建資料庫

引擎要有地方存東西。副官從 ARCHITECTURE.md 生出完整的建表 SQL,存成 supabase/migrations/0001_init.sql——這一步它自己做。但真正去資料庫建表,又是一道它沒權限的界線,它停下來:

名詞解釋:Supabase 是什麼
SQL 我寫好了、放進 migration 檔了。但執行得靠您:
請到 Supabase Dashboard → SQL Editor,把這段貼上去、按 Run。跑完到 Table Editor 確認 newsweekly_reportsfetch_logs 三張表都在。
建好回我一聲,我接著把讀寫資料庫的程式接上去。

我貼、我跑、我確認三張表都在、回報。副官接手,把資料層的 CRUD、把那條「URL 去重」的邏輯寫成程式。引擎的心臟,裝好了。

第四章字卡:每天九點的鬧鐘

第四章:時區暗礁,與那道每天九點自己響的鬧鐘

航行日期:2026-05-21

引擎能轉,還得有人每天早上去點火。這就是排程(cron)。但點火時間藏著一道暗礁,副官先把它挑明:

排程時間我想設在台灣時間早上 08:45 開跑,留 15 分鐘給抓取和 AI,趕在九點前讓日報上架。
但這裡有個很多人會踩的雷:Vercel 的排程吃的是 UTC。台灣早上 08:45,換算成 UTC 是前一天的 00:45。所以 vercel.json 裡我寫的是 00:45,不是 08:45
同一條鐵律也貫穿整個資料庫:所有時間一律存 UTC,只在畫面上才換算成台灣時間顯示。存的時候就混台灣時間,遲早會在某個跨日的半夜算錯「這是哪一天的日報」。
名詞解釋:Vercel Cron 排程是什麼

這是「安靜地算錯」在新聞站的版本——不是當機,是某天的新聞被默默歸到錯的日期,沒人發現。存 UTC、顯示台灣時間,一刀切乾淨。

那顆不能對全世界開著的鈕

排程的另一面是安全。這個會叫醒付費 AI 的 endpoint,一旦裸著放在網路上,任何人對它連打十下,我的 AI 帳單就被連刷十次。副官在這裡又停了一次,這次是請我設金鑰:

船長,/api/cron/daily 這個網址會觸發抓取 + 叫 AI,不能讓任何人打得動。我已經在程式裡加了驗證:沒帶對 CRON_SECRET 的請求一律擋掉。
但真正的密鑰得由您的手放進去。請到 Vercel → Settings → Environment Variables,設好這四個:
CRON_SECRET(隨機字串,我這邊驗證用)、ANTHROPIC_API_KEYSUPABASE_SERVICE_ROLE_KEYADMIN_EMAIL
設好告訴我,我就讓排程正式接管。萬一哪天 cron 整串失敗,它會自動重試三次、還是不行就寄信到 ADMIN_EMAIL 通知您。

我把四個變數一個個貼進 Vercel,回報。副官把排程掛上。然後我們做了一件很安靜、卻是整趟航行裡我最有感的事——什麼都不做,去睡覺。

隔天早上,我還沒碰電腦,網站上已經擺著當天的 AI 日報。沒有人去點火,是那道排程在台灣時間天還沒亮時自己醒來,把整條鏈跑完了一遍。空船下水那天我只是看著它浮起來;這天,我看著它自己開始航行

圖:台灣時間每天早上九點前,那道排程自己跑完整條鏈—
圖:台灣時間每天早上九點前,那道排程自己跑完整條鏈——抓取、去重、AI 分類與排序——把當天日報擺上桌。每張卡片的星星是重要度。沒有人點火。
第五章字卡:副官獨自航行

第五章:船長上岸,副官獨自把船開完

航行日期:2026-05-21

引擎會自己轉之後,剩下的是「把船的內裝做完」——首頁日報、週報、歷史檔案、關於頁。這些大多是純執行、品味我已經寫在 SPEC.md 裡的活。所以這一章有個轉折:我上岸了。我給副官下了一道明確的命令,然後去忙別的:

船長:把日報首頁、/daily/[date]、週報、/archive 歷史月曆、/about 全部做完。自己測、自己開三種螢幕尺寸截圖比對、能判斷的別來問我。我回來時,要看到一艘完整的船。

接下來的航程,是副官獨自完成的。我回來時,六大分類的卡片版面、日期前後切換、週報專屬版型、歷史月曆——都已經在線上跑著了。它甚至自己跑了手機/平板/桌機三種尺寸的截圖,擺在那裡等我驗收。

圖:副官獨自完成的歷史月曆。底線標記的日期可點進當天
圖:副官獨自完成的歷史月曆。底線標記的日期可點進當天日報;頁尾那行「每天 09:00(台北)自動策展」,就是這艘船的引擎時刻表。
圖:週報有自己專屬的版型,開頭一段「本週重點」是 A
圖:週報有自己專屬的版型,開頭一段「本週重點」是 AI 撈過去七天資料寫出來的看點。
圖:同一份日報的手機版。副官自己跑了手機/平板/桌機
圖:同一份日報的手機版。副官自己跑了手機/平板/桌機三種尺寸截圖擺著等我驗收——響應式,它自己顧好了。

後面幾天,我陸續又交辦了幾件「品味活」:把英文標題和摘要翻成中文、每天首頁開頭加一段 AI 寫的「編輯短評」、補上深淺色主題切換。節奏都一樣——我講清楚「要長成什麼樣、底線在哪」,副官划槳、自測,做完只在一個時刻回來找我:下令把成果 push 上線。程式是副官划的槳,我只負責在對的時機喊一聲「推」。

到這裡,2026-05-25,我親口在日誌裡記下一句話:線上每天都有更新、週報也有產出。MVP,真的活著了。

第六章字卡:海上的兩道暗礁

第六章:海上撞到的兩道暗礁

暗礁一:被 Hacker News 壟斷的首頁

航行日期:2026-05-27

船自己跑了幾天,我每天打開看。然後我注意到一件不對勁的事,丟給副官:

船長:首頁怎麼幾乎全是 Hacker News?OpenAI、Google 那些官方部落格的新聞,我好幾天沒在上面看到了。

副官查了一輪,把病根挖出來給我看——這是個很漂亮的 bug:

找到了。問題出在「抓取時間窗」是所有來源共用一個 24 小時
但官方部落格一週才發 1–2 篇,落在任何一天的 24 小時內,常常是 0 篇;而 Hacker News 每天有上百篇。結果就是官方一手消息天天被社群熱度洗版、擠不上首頁。不是它們不重要,是它們根本沒被抓進來。

它開的藥方,正好用上了第三章那個埋好的設計:

修法:讓每個來源自己宣告抓多久的窗。官方部落格拉到 336 小時(14 天),Hacker News 和 arXiv 維持 24 小時。
窗開這麼大會不會重複抓爆?不會——還記得第三章我們把去重排在叫 AI 之前嗎?同一篇官方文章被重複抓到,會在進 LLM 前就被 URL 擋掉,一毛錢都不會多花。14 天的窗,連 Google Research 那種發文間隔可以到 8 天的低頻來源都接得住,甚至撐得過一整個週末 cron 全壞的意外。

我拍板。看著首頁第二天重新長出官方一手消息,那種感覺很踏實——回頭看第四章那張首頁截圖,「巨頭動向」那一區裡 OpenAI Blog、Hugging Face 和 Hacker News 並排站著,就是這道暗礁修好之後的樣子:官方一手消息,回來了。當初那個「去重要在 AI 之前」的小決定,也在兩週後變成了一個我們敢放手開大時間窗的底氣。好的設計,回報常常遲到,但會到。

暗礁二:寧可多花一點,也不要首頁出現一篇假新聞

航行日期:2026-05-29

第二道暗礁是品質。負責判斷「這篇重不重要、該歸哪一類、是不是其實跟 AI 無關」的,是一顆比較輕便、便宜的模型。它大部分時候很稱職,但偶爾會把一篇邊緣的、其實跟 AI 沾不太上邊的新聞,放行到首頁。對一個「幫你篩掉雜訊」的策展站來說,這比漏掉一篇還傷——讀者信的就是「上面這些都值得看」。

這是一個純品味、純取捨的決定,所以由我拍板:

船長:把分類那顆模型換成更強的(Opus)。每天就那幾十篇,貴一點點無所謂。我寧可多花那一點錢,也不要首頁出現一篇讓人皺眉、覺得「這也算 AI 新聞?」的東西。乾淨,比便宜重要。

副官換好模型、重跑驗證、回報判斷品質的差異。順手也把一個之前因為沒有公開 RSS 而被迫拿掉的來源——Anthropic 官方新聞——用別的方式補了回來。品味與底線的決定是人的,執行交給副官;這條分界,從第一章到這裡,一次都沒變過。

第七章字卡:換一身衣服

第七章:換一身衣服,與「只有船長能按的那顆鈕」

航行日期:2026-05-31 → 06-10

船能穩穩自己航行之後,我想幫它換一身更好看的衣服——一個雜誌拼貼風的新版面。但這是一次大改版,動到的是每天都在線上跑、有真實讀者在看的頁面。我們之間早有一條默契,副官主動把它講了出來:

大改版我不直接動現有的頁面。我先在 /preview/collage 底下蓋一個平行版本,跟正式站共用同一份真實資料,但完全隔離。您看順眼了、覺得可以扶正,我們再一次切換過去。
這樣萬一新版有問題,正式站一秒都不會受影響——讀者每天早上要看的日報,永遠是穩的那一版。

於是新版的「DAILY BRIEF」大標、編輯短評、深淺交錯的卡片,全長在 /preview 這個安全的乾塢裡。正式站照常每天九點上架,毫髮無傷。改版這件事本身,就是「先讓水管通水、別把風險堆到使用者面前」這條鐵律,又一次的具體實踐。

圖:改版後的 /preview/collage——雜
圖:改版後的 /preview/collage——雜誌拼貼風的「DAILY BRIEF」報頭。它跟正式站共用同一份真實資料,但完全隔離;看順眼了才扶正,正式站一秒都不受影響。

最後一句話,副官交還給了我

說個你可能已經猜到的事:你現在讀的這篇航海日誌,是副官寫的初稿。

我請它回頭翻整個專案的文件、git 歷史、那些踩過的雷,把我們這一路怎麼一來一往交班,重新講成一個故事。它做完了,然後在最後停下來——停在那道從第一章就立好、它永遠跨不過去的界線上:

船長,稿子我寫好了。但最後這一步我做不了,也不該做:按下 publish。
這篇要對外、收不回來、而且是您的名字、您的部落格。發文這顆鈕,從頭到尾,只有您能按。

於是這篇文章自己,就成了整艘船分工的最後一個註腳:AI 可以把船開得又快又穩,可以在我上岸時獨自航行,甚至可以替我寫下這趟航行的故事——但那顆「對外、收不回來」的鈕,永遠留在船長手裡。

尾聲:人定方向,AI 划槳

上一艘船教我的事,是「對話會散,文件不會」。這一艘教我的,是另一半——當文件把方向釘住之後,人跟 AI 之間真正值錢的,是那條清清楚楚的交班線。

哪些副官自己做、哪些它停下來點名請我、哪些只有我能親手碰。這條線畫得夠清楚,AI 就能在這座每天自己醒來、自己花錢、對全世界開著的引擎旁,跑得又快又穩,而我只要守在三個位置:開工前確認航向、撞到暗礁時拍板取捨、以及——按下每一顆收不回來的鈕。

現在,台灣時間每天早上九點之前,這艘船會自己把當天的 AI 新聞擺上桌。沒有人點火。

圖:關於頁——這艘船的來歷、如何運作,與一整排新聞來
圖:關於頁——這艘船的來歷、如何運作,與一整排新聞來源清單。

人定方向,AI 划槳。這就是我心目中的 Vibe Coding。

下一段航程,換你了——去 打開它,告訴我哪裡還能更好。


📦 想對照原件的:這趟航行的完整程式碼,連同那套讓副官站回航線的 harness 文件(CLAUDE.mdSPEC.mdARCHITECTURE.mdROADMAP.md),都放在 GitHub repo 裡,照這條動線就翻得到 👉 github.com/captain-balung/ai-daily-brief