我用 Claude 當 DM 跑 MyGM 遊戲,費城拿了十冠

你有沒有過那種,本來只是想偷懶、結果做出一個比正職還認真的東西的經驗?

我本來只是想玩 NBA 2K 的 MyGM 模式啦——就那個你當總經理、選秀、交易、被老闆罵的模式。但我電腦上沒裝 2K,手癢之下就想:欸,乾脆叫 Claude 當我的總經理遊戲 DM 好了。一個禮拜後,我手上有一個 repo,裡面 Claude 同時扮演裁判(骰 d20)+ 書記(寫存檔)+ 聯盟總裁(拋老闆難題),而我已經當了三次總經理,其中一次還在費城拿了十座冠軍。

先講這個 repo 在幹嘛。

一個沒有程式碼的「遊戲引擎」

這個專案最怪的地方是——它幾乎沒有程式。整包 repo 翻車的核心其實是 Markdown:CLAUDE.md 是給 Claude 看的 DM 守則,templates/ 放著從 1979 到 2026 每一年的選秀名單跟薪資帽(對,我真的整坨建了快五十個 draft class 檔),saves/ 則是每一局存檔。

規則本身是 DnD 那套搬過來的:任何重大決策——簽自由球員、跟別隊喬交易、賭老闆會不會批預算——都骰一顆 d20 + 屬性修正 vs DC。屬性有四個:老闆信任、外交手腕、專業智略、更衣室氣場,開局發 60 點。骰出自然 20 是狗屎運大成功,自然 1 是毀滅性翻車。每一年強制四個停頓點:休賽季選秀、交易大限、季後賽、年度結算。年度任務沒達標就 GAME OVER,被老闆開除。

換句話說,Claude 不是在「聊天」,是在跑一個有狀態機的遊戲。而狀態全部落在檔案裡——這就是後面要講的雷的來源。

一個禮拜,三次人生

saves/ 底下現在躺著三局,剛好是我這禮拜當的三次經理:

第一局接的是 Brooklyn Nets,從 2010 跑到 2022-23,GM 屬性被我練到全項 20 滿,吃了八座冠軍。這局算是我摸熟規則的練習局,骰運好到有點假。

第二局更扯,接 Philadelphia 76ers,從九零年代一路打,最後十冠封王、GM 功成身退請辭。這局我還順手叫 Claude 寫了一份 memory/gm-ai-relationship.md,記錄 GM 跟 Allen Iverson「十二年鐵哥們」的設定——以後 AI 相關的談判 DC 自動下修五點以上。對,我幫一個文字遊戲建了人際關係資料庫,我也不知道我在認真什麼。

第三局回到 Golden State Warriors,2010 年代從零開始。這局還在跑。

三局攤開來看才發現一件事:**我不是在玩遊戲,我是在反覆壓力測試一個我自己設計的系統。**每開一局,就是一次 cold start,逼我檢查 Claude 到底有沒有照規則讀檔、寫檔、骰點。然後我就踩到雷了。

翻車現場:那個我以為一直在保護我的 hook

事情是這樣。我很怕 Claude 跑一跑「忘記寫檔」——它劇情演得很開心,結果 STATE.md 沒更新,下一局 cold start 整個狀態對不上。所以我在 6/7 那天加了一個 Stop hookscripts/validate-turn.sh),設計是:每回合結束,檢查存檔的狀態檔超過 480 秒沒更新就噴一句提醒——

STATE="$SAVES_DIR/$LATEST/current/STATE.md"
DASHBOARD="$SAVES_DIR/$LATEST/DASHBOARD.md"

我那時候超滿意,覺得這下書記再也不會偷懶了吧。

問題是,同一天稍晚,我做了一次重構(commit 7c4dd6f),把原本散落的七個狀態檔——my-teamcap-situationscouts 那些——全部 merge 成一個 STATE.md,順手把 current/ 這層資料夾整個拿掉,DASHBOARD.md 也改名沒了。理由很正當:cold start 要讀的檔越少越好,少讀一點 token。

你看出來了吧。

我那個寶貝 hook,守的是 $LATEST/current/STATE.mdDASHBOARD.md——**兩個檔在我重構後一秒都不存在了。**腳本裡有一行 [ ! -f "$FILE" ] && return,檔案不在就安靜跳過。所以 hook 每回合都乖乖執行、乖乖 return、乖乖什麼都不做。它沒噴錯、沒掛、沒跳紅字,就只是……一個盡責地保護著空氣的守衛。

誤診與真相

最初我完全沒發現。我以為書記變勤勞了——每局狀態都對得上,我還暗爽「果然加 hook 有用」。

直到這禮拜回頭整理 repo,我才對照時間軸:hook 寫於 6/7,重構也在 6/7,hook 守的路徑在它出生幾小時後就被我親手拆了。那段期間狀態之所以沒出包,根本不是 hook 的功勞,是因為我每次都盯著看、自己手動確認。換句話說,真正在做驗證的人是我,hook 只是個吉祥物。

這就是那種最陰險的 bug:**它不會讓你的東西壞掉,它只會讓你以為某個東西在保護你。**比起噴一個 stack trace,這種「沉默的安全感」危險多了——因為你不會去查一個從來不抱怨的元件。

教訓我覺得滿可遷移的:**任何「改了資料結構」的 commit,都要回頭掃一遍有誰在引用舊路徑。**hook、腳本、CI 設定、寫死的相對路徑——這些東西不在你的 import graph 裡,編譯器不會幫你抓,測試也未必涵蓋。它們是靠「約定」連著的,而約定最會在重構時被你自己毀約。理想上,那個 hook 的開頭就該有一句「路徑不存在 = 設定壞了,給我噴出來」,而不是默默 return。fail loud,不要 fail silent 啊。

所以我這禮拜的戰績是:當了三次總經理、拿了十八座冠軍、寫了一個忠心耿耿守著虛無的 bash 守衛。先不說了啦,我得去把那個 hook 的路徑修一修,然後可能順便再開第四局——這次我想試試看能不能在自然 1 的詛咒下還守住飯碗。

這段 code 寫於 2026 年 6 月 7 到 9 日,文章整理於 6 月 10 日。