查官方文件(code.claude.com/docs/en/cloud-environments 的「What carries over」表)發現:今天裝好的 --scope user 機制很可能不會被雲端 session 讀到 (user-scope enabledPlugins 明文寫「不會帶到雲端」);先前引用的 「Pre-populate plugins for containers」是另一個機制(CLAUDE_CODE_PLUGIN_ SEED_DIR,給自架容器用),不是 claude.ai Cloud environments 產品。 新增 docs/cloud-environment-audit-20260820.md: - Plan A 風險(本機隔離環境重跑一次,貼新鮮輸出佐證腳本本身沒問題) - Plan B(官方文件證實可行:把 ISEP 宣告進連線 repo 自己的 settings.json) - Plan C(今天新查到:claude --cloud 直接從本機 checkout 打包,完全不經 過 GitHub 薄殼,官方文件證實可行) - 舊雲端環境變數逐一比對 credentials-map.md:八個名字(CLOUDFLARE_ACCOUNT_ID 等)確認來自 polaris/mira/.env(leo21c 現役),與 cloud 總管工作無關, 建議排除 - 薄殼/ISEP 共存風險分析(不會打架,除非 bootstrap.sh 重新把 InkStoneCo/ clone 進薄殼workspace) scripts/make-cloud-env.sh:NEEDED 從 1 個擴到 8 個,排除 leo21c 來源的 憑證,加註每個變數的出處依據。 docs/TESTING.md、docs/cloud-setup-script.sh、docs/cloud-session-bootstrap.md: 補上指向審計文件的警示與 Plan B/C 的 fallback 指引。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
19 KiB
雲端環境盤點與修正(2026-08-20,InkStoneCo#14 收尾)
leo 今天最高優先:「我明天可以在雲端總管用到完整的環境嗎?」 本檔回答三件事:①
docs/cloud-setup-script.sh目前的機制官方文件核實後有沒有問題 ② 舊雲端環境的變數/網域哪些該留、哪些該丟 ③ 舊薄殼(GitHubyoulinhsieh/inkstoneco) 會不會跟新機制打架。每一格都標實測過還是查文件得出,沒有的明講。
1. 🔴 官方文件核實後發現:今天裝好的機制(Plan A)可能不會生效
docs/cloud-setup-script.sh 目前做的是 claude plugin marketplace add ... --scope user
+ claude plugin install isep@inkstone --scope user。這個機制本機驗證過(見
cloud-session-bootstrap.md「已驗」段),但沒有在真正的雲端 session 跑過。
今天查官方文件(code.claude.com/docs/en/cloud-environments,2026-08-20 抓取)
的「What carries over from your setup」表格,白紙黑字寫:
| 項目 | 雲端 session 帶不帶得到 |
|---|---|
你 repo 的 .claude/settings.json hooks |
Yes(clone 的一部分) |
.claude/settings.json 裡宣告的 enabledPlugins+extraKnownMarketplaces |
Yes(session 啟動時直接從你宣告的 marketplace 裝) |
只在使用者層級啟用的 plugin(~/.claude/settings.json 的 enabledPlugins) |
No——原文:「User-scoped enabledPlugins lives in ~/.claude/settings.json. Declare them in the repo's .claude/settings.json instead」 |
而本機實測(隔離 $HOME,見下方 §4)證實:claude plugin install isep@inkstone --scope user
寫入的正是 ~/.claude/settings.json 的 enabledPlugins/extraKnownMarketplaces——
跟官方文件說「雲端不會帶到」的是同一個檔案、同一個欄位。
⇒ docs/cloud-setup-script.sh 目前的寫法,很可能在真正的雲端 session 裡裝了等於白裝
(磁碟上有檔案,但 Claude Code 啟動時不會去讀它)。這與今天稍早在 #14/#57 留言裡
「A7 plugin 裝得起來」「A8 新 session 閘會觸發」的驗證都是在本機隔離環境跑的,
不是真雲端——所以沒有人真的撞過這一格。
🔴 這格我沒有辦法在本機驗到底(沒有真正的雲端 session 可以跑)。
明天 B2(docs/TESTING.md)就是驗這件事的關卡:如果 claude plugin list 沒看到
isep@inkstone,這就是原因,直接跳到下面 Plan B。
2. Plan B(官方文件證實可行的正解):把 ISEP 宣告在「連進雲端 session 那個 repo」自己的 .claude/settings.json
同一份官方文件的 schema(code.claude.com/docs/en/settings §Plugin configuration):
{
"extraKnownMarketplaces": {
"inkstone": {
"source": { "source": "git", "url": "https://git.uncle6.me/inkstone/ISEP.git" }
}
},
"enabledPlugins": {
"isep@inkstone": true
}
}
這段要放進雲端 session 實際連進去的那個 repo(目前是 GitHub 薄殼
youlinhsieh/inkstoneco)自己的 .claude/settings.json,不是任何 user-scope 檔案。
docs/cloud-setup-script.sh 的 git URL 重寫(url.insteadOf)繼續需要,
因為 git 來源要用同一把 GITEA_TOKEN_CLAUDE_CODE 才 clone 得到 ISEP(private repo)。
🔴 這格我沒有推:改薄殼=GitHub 寫入=D20,要 leo 親手(見 §5)。
3. Plan C(不必碰 GitHub 薄殼的替代路——今天新查到,建議優先試)
官方文件另有一條路(claude-code-on-the-web.md §"Send local repositories without GitHub"):
「When you run
claude --cloudfrom a repository that isn't connected to GitHub, Claude Code bundles your local repository and uploads it directly to the cloud session... This fallback activates automatically when GitHub access isn't available.」
InkStoneCo 與 ISEP 兩個 repo 本機的 git remote 只有 gitea,沒有連 GitHub
(實測:git remote -v 只列出 gitea)——這正好符合「repository that isn't
connected to GitHub」的條件,這個 bundle 模式會自動觸發,不需要任何設定。
⇒ leo 明天可以直接在終端機、在 ~/Documents/tech_projects/ISEP(或 InkStoneCo)
底下跑:
claude --cloud "跑一下 claude plugin list 給我看,再故意打 git tag -a v9.9.9 -m test 給我看"
這會把**本機當下這份 ISEP/InkStoneCo(含未 commit 的變更)**直接包上傳,
雲端 session 用的就是這份 repo 自己的 .claude/settings.json/hooks/——
完全不經過 GitHub 薄殼,不需要今天的 Plan A/Plan B 任何一個機制,
且天生不會漂移(因為就是同一份)。
限制(同一份官方文件):
- bundle 只含已 track 的檔案(
git add過的),未 add 的新檔不會被帶上去 - bundle 出來的 session 若要
git push回 Gitea,要嘛靠docs/cloud-setup-script.sh的 URL 重寫(Setup script 仍然獨立於連的是哪個 repo,照樣會跑),要嘛另外設定 - 目錄要在 100MB 以內(ISEP/InkStoneCo 都遠小於這個量級,
git count-objects沒驗但兩者都是純文字 repo,不像會超)
🔴 這格我沒有跑過真正的 claude --cloud(那是要在 leo 自己的終端機、
用他登入的帳號跑的動作,這台機器上跑不會是同一個帳號脈絡)。但機制本身
是官方文件白紙黑字寫的,不是我的推測。
4. Plan A 到底裝出什麼——本機隔離環境重跑一次(今天,新鮮輸出)
隔離 $HOME=/private/tmp/claude-501/isep-test-home3(全新,未接觸過真正的
~/.claude/),照 docs/cloud-setup-script.sh 逐行跑:
$ git config --global url."https://x-access-token:***@git.uncle6.me/".insteadOf "https://git.uncle6.me/"
$ claude plugin marketplace add https://git.uncle6.me/inkstone/ISEP.git --scope user
Adding marketplace…Refreshing marketplace cache (timeout: 120s)…
Cloning repository (timeout: 120s): https://git.uncle6.me/inkstone/ISEP.git
Clone complete, validating marketplace…
Cleaning up old marketplace cache…
✔ Successfully added marketplace: inkstone (declared in user settings)
$ claude plugin install isep@inkstone --scope user
Installing plugin "isep@inkstone"...✔ Successfully installed plugin: isep@inkstone (scope: user)
$ claude plugin list
Installed plugins:
❯ isep@inkstone
Version: 0.0.0
Scope: user
Status: ✔ enabled
$ cat ~/.claude/settings.json
{
"extraKnownMarketplaces": { "inkstone": { "source": { "source": "git", "url": "https://git.uncle6.me/inkstone/ISEP.git" } } },
"enabledPlugins": { "isep@inkstone": true }
}
這證實兩件事:① 今天的 Setup script 內容本身沒有語法或連線問題,本機隔離環境
跑一次成功、乾淨(跟 08-14/08-20 之前的驗證一致)。② 它寫的檔案就是
~/.claude/settings.json——跟官方文件說「雲端不帶」的是同一個檔案。
⇒ 腳本能跑完 ≠ 雲端會生效,這是本檔 §1 那個發現的直接證據。
5. 舊薄殼(youlinhsieh/inkstoneco)會不會跟新機制打架
結論:不會「打架」,但有一個要注意的重新啟動路徑。
-
新機制(Plan A/B)都不會去改動或需要薄殼本身;
docs/cloud-setup-script.sh不 clone InkStoneCo、不跑bootstrap.sh。 -
薄殼裡舊的
.claude/settings.json(InkStoneCo#1408-14 那輪查證的「51 條 hook 指標」, 指向$CLAUDE_PROJECT_DIR/InkStoneCo/.claude/hooks/<name>.sh)現在還在薄殼裡 (這格沒有重新讀薄殼確認——薄殼是私有 GitHub repo,讀取按 D20 視同寫入, 這台機器沒有 leo 開閘不去碰;以下推論全部基於 08-14 那輪已查證、寫進#14留言裡的事實,那是既有紀錄不是我新查的)。 這些指標本身有「檔案不在就安靜放行」的安全閥([ -f "$h" ] || exit 0)。 -
只要
InkStoneCo/這個子目錄不會被 clone 進薄殼的 workspace,這 51 條指標就是 死的、不會觸發、也不會跟 ISEP 衝突。 新機制完全沒有任何步驟會去 clone InkStoneCo。 -
唯一會重新炸開的路徑:如果雲端 session 裡的 AI 因為薄殼自己委
CLAUDE.md裡還留著舊指示(叫它跑bootstrap.sh)而照做,InkStoneCo/子目錄會被生出來, 51 條指標會重新指到真檔案——那時兩份閘會各觸發一次(薄殼那 51 條 + ISEP plugin 的等價閘),跟本機今天已經在跑的「兩份都在,閘各響兩次(吵,但安全)」 是同一個形狀,不安全的方向是漏擋,這個方向是誤攔/吵,不是漏。🔴 這一段我沒有讀到薄殼當下的
CLAUDE.md是否還留著那個指示(同上, 私有 repo 讀取要開閘),所以無法斷言會不會發生,只能給出「如果發生會怎樣」 跟「安全方向」。 -
建議:如果明天走 Plan B(把 ISEP 宣告寫進薄殼
.claude/settings.json), 同一次 D20 開閘可以順手清掉薄殼裡舊的hooks區塊(51 條指標)與bootstrap.sh對InkStoneCo/的 clone 邏輯——這正好是這次要解的問題本身,一次做完。 如果走 Plan C(claude --cloudbundle),薄殼整個變成不需要的舊東西, 這個顧慮直接消失。
6. claude plugin install 裝完會不會被雲端快照保留——查官方文件,不是猜
code.claude.com/docs/en/cloud-environments §Environment caching 原文:
「The setup script runs the first time you start a session in an environment. After it completes, Anthropic snapshots the filesystem and reuses that snapshot as the starting point for later sessions... The cache is a filesystem snapshot, so it keeps what the setup script writes to disk... The setup script runs again to rebuild the cache when you change the environment's setup script or allowed network hosts, and when the cache reaches its expiry after roughly seven days. Resuming an existing session never re-runs the setup script.」
⇒ 檔案本身會被保留(快照機制對「寫到磁碟的東西」沒有爭議,~/.claude/plugins/
與 ~/.claude/settings.json 都會在)。問題不是「保不保留」,是「雲端 session
啟動時要不要去讀那個檔案」——這正是 §1 查到的分歧點:磁碟上有 ≠ 啟動時會讀。
新鮮度的另一半(次要,明天不急):改 Setup script 內容或 allowed network hosts 會逼快照重建;否則卡在快取裡最長約 7 天。跟本題(會不會生效)是兩件事,不要混。
7. 舊雲端環境變數盤點——哪些留、哪些丟
依據:~/.claude/cloud-env/leo-貼上來的雲端現況-20260820.txt(leo 貼的舊環境,
值已被他自己刪除只剩結構)+ InkStoneCo/system-dev/wiki/credentials-map.md
2026-08-13 逐檔實抽索引(權威、有名字有出處,不是我新查的)。
關鍵發現:舊雲端環境的變數清單,逐一比對後,幾乎是 polaris/mira/.env
(🔴 leo21c 現役)整包搬過去的——CLOUDFLARE_API_TOKEN/CLOUDFLARE_ACCOUNT_ID/
PRIVATE_KEY/CLIENT_EMAIL/NAMESPACE/NOTION_INTEGRATION_TOKEN/
TELEGRAM_CHAT_ID/TELEGRAM_BOT_TOKEN 這八個名字,credentials-map 索引裡
全部列在 polaris/mira/.env 那一行。這解釋了 2026-08-14 那輪審查為什麼會抓到
「沒有名字的 CLOUDFLARE_API_TOKEN 讀得到 leo21c 的 6 顆正式 worker」——
因為它本來就是 mira 的正式帳號憑證,不是為雲端 CC session 特別開的。
| 舊變數 | 建議 | 為什麼(有出處) |
|---|---|---|
CLOUDFLARE_ACCOUNT_ID(=leo21c) |
🔴 丟 | credentials-map.md 確認來自 polaris/mira/.env(leo21c 現役)。InkStoneCo 頂層 CLAUDE.md 對薄殼白紙黑字寫「絕不設 CLOUDFLARE_ACCOUNT_ID」,2026-08-14 審查已列為「最危險的發現」 |
CLOUDFLARE_API_TOKEN(無名字,同上帳號) |
🔴 丟 | 同上,實測讀得到 leo21c 6 顆正式 worker,會被所有工具當預設 token |
PRIVATE_KEY / CLIENT_EMAIL(Google 服務帳號) |
🔴 丟 | credentials-map.md 第 183 行:這是 mira 用的 Google 服務帳號,cloud 總管的工作(管 InkStoneCo/ISEP/arcrun 相關 repo)不需要它。2026-08-14 審查已標「用途不明的私鑰放雲端本身是風險」 |
NAMESPACE=leo |
🔴 丟 | 同來源(mira 的環境變數),cloud 總管的任務不吃這個變數 |
GITEA_TOKEN(mira 自己那把)/GITEA_BASE_URL |
🔴 丟 | mira 自己的 Gitea 身分,跟 GITEA_TOKEN_CLAUDE_CODE(claude-code 機器帳號)是兩回事,留著只會製造「兩把 token 混用」的漂移風險(正是本票 §setup script 那個舊 bug 的同款病) |
MCP_OWNER_SECRET / MCP_STATIC_TOKEN |
🔴 丟 | mira 自己 MCP server 的認證密鑰(服務端用),cloud CC session 是呼叫端不是服務端,用不到 |
CLAUDE_CODE_OAUTH_TOKEN |
🔴 丟 | leo 自己在舊快照裡就註記「這個已經不需要了」 |
GITEA_TOKEN_CLAUDE_CODE |
✅ 留 | 新機制的唯一必要憑證(docs/cloud-setup-script.sh 靠它) |
TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID |
✅ 留(次要路徑) | 規則五要求的 notify_leo 通道。今天查證:notify_leo 現在優先走 arcrun workflow(MCP 呼叫,免密碼),這兩個變數是「手寫 curl」那條備援路——留著成本低、故障時有備援 |
GEMINI_API_KEY |
✅ 留 | matrix/arcrun/.env/products/arcrun-rag/.env 都列為 arcrun 工作流用的變數,非 mira 專屬 |
NOTION_INTEGRATION_TOKEN |
✅ 留 | leo 自己在舊快照裡註記「給 arcrun 用的」——雖然 credentials-map 索引目前只在 mira 那行看到它,但既有明確用途註記,維持留著(成本低,不是 leo21c 寫入類憑證) |
UNCLE6_CF_API_KEY |
✅ 留 | products/arcrun-rag/.env 索引確認是 uncle6 帳號(非 leo21c),對 uncle6 CF 資源的操作 |
N8N_UNCLE6_API_KEY |
✅ 留(低風險) | leo 自己註記「n8n MCP 用」;沒有查到它對應到 leo21c 寫入路徑,留著备用 |
CLOUDFLARE_API_TOKEN_YOULIN_CC_USE |
✅ 留 | InkStoneCo/.env 頂層索引確認,D37 測試帳號,非 leo21c,本來就設計給 CC 用 |
CLOUDFLARE_API_TOKEN_leo21c(明確具名的) |
⚠️ 留但要 leo 先確認權限 | 這把不在任何 .env 索引裡出現,很可能是 08-14 審查建議「真要診斷,給唯讀的」之後臨時開的一把。只有 leo 自己在 CF 控制台看得到這把 token 的權限範圍——留著前請確認它是唯讀(Zone Read / Account Read 之類),不是 Edit。就算不小心留著寫入權限,ISEP 現有的 leo21c-write-guard.sh(今天已驗證上線)會再擋一層,但憑證本身沒有寫入權限才是根本的防線 |
新增建議(不是「丟」,是「舊環境漏掉的」,2026-08-14 審查早就列過、但當時沒有加進去):
| 建議新增 | 為什麼 |
|---|---|
CLOUDFLARE_API_TOKEN_CC_SHIPPING_CORE |
InkStoneCo/.env 頂層索引確認存在。credentials-map 註記「總管唯一可以直接動的實例」——geek6688 出貨機。沒有它,雲端連 D82 出貨三步都做不了 |
CLOUDFLARE_ACCOUNT_ID_GEEK6688 |
同上,成對變數 |
🔴 這兩條是否要開,屬於「要不要讓雲端有出貨能力」——leo 的品味/風險判斷, 不是我能替他決定的格子,這裡只負責把選項與依據列清楚。
8. Allowed domains 盤點
| 網域 | 建議 | 為什麼 |
|---|---|---|
git.uncle6.me |
✅ 留 | Gitea+ISEP marketplace,新機制必要 |
api.cloudflare.com |
✅ 留 | CF API(youlin/uncle6/geek6688 帳號的操作都要打這個網域,帳號區分靠 token 不是靠網域) |
api.telegram.org |
✅ 留 | notify_leo 備援路徑 |
n8n.uncle6.me |
✅ 留 | notify_leo workflow/n8n MCP 現在掛在這裡 |
*.uncle6-me.workers.dev |
✅ 留 | uncle6 帳號的 CF Workers |
*.arcrun.dev |
✅ 留 | arcrun CLI/服務網域 |
*.youlin-hsieh-dev.workers.dev |
✅ 留 | D37 測試帳號的 Workers |
*.leo21c.workers.dev |
⚠️ 建議丟,或至少確認用途 | 這是 leo21c(mira/arcrun 正式帳號)自己的 Workers 網域。§7 的邏輯是「雲端不該預設碰得到 leo21c」——網域可達不等於一定會寫入(GET 不擋),但既然 §7 已經把 leo21c 的憑證都拿掉了,留著這個網域也打不出什麼(沒有 leo21c token 可用),是否留純粹看 leo 要不要保留「唯讀診斷 leo21c」的能力,不影響安全性(憑證才是關鍵,網域只是能不能連上) |
| 預設套件管理器清單 | ✅ 留 | Setup script 需要(npm/pip 等),且舊的 npm i -g arcrun 若保留也要它 |
9. 舊 Setup script 那支已知 bug——不會延續到新版
舊的(目前真的在雲端跑的那份,~/.claude/cloud-env/leo-貼上來的雲端現況-20260820.txt
裡的原文):
printf 'https://Leo:%s@git.uncle6.me\n' "$GITEA_TOKEN" > ~/.git-credentials
$GITEA_TOKEN 從沒被設過(環境變數清單裡只有 GITEA_TOKEN_CLAUDE_CODE)
⇒ 印出空密碼、且用 Leo 帳號不是 claude-code。這支腳本本身就是今天要被
整段取代掉的東西(明天貼 docs/cloud-setup-script.sh 進 Setup script 欄位,
這行連同整支舊腳本一起消失,不是修,是換掉)。docs/cloud-setup-script.sh
用的是 git config --global url.insteadOf 重寫(本檔 §4 已重新驗證),
沒有這個 bug。
~/.arcrun/config.yaml(acr CLI 設定,含 api_key/cf_api_token):
舊 Setup script 有寫這段,新版沒有。今天稍早在 #14 已經驗證:MCP 呼叫
arcrun(arcrun_whoami/arcrun_list_workflows 等)走的是 portal-login 綁定,
不吃 api_key 參數,也不需要這份 config.yaml。這段是否還要保留純粹取決於
leo 是否還會在雲端 session 裡直接打 acr CLI 指令(而不是透過 MCP 工具)——
🔴 這格我沒有驗證雲端 session 有沒有機會用到裸 acr CLI,保守建議:
先不加回去,若明天發現某個工作流程需要裸 CLI,再補(成本低、可逆,符合「不確定
就先做最小假設,錯了再修」)。
10. 一句話總結
- 今天裝好的機制(Plan A)有沒有效,明天 B2 才見真章——官方文件顯示它很可能無效, 這是本檔最重要的發現,優先級高於環境變數細節。
- Plan C(
claude --cloudbundle 本機 repo)是今天新查到、完全不碰 GitHub 薄殼、 官方文件證實可行的路,建議明天優先試,最省事、天生不會漂移。 - 舊環境變數有八個名字其實是 mira(leo21c 現役)的憑證被誤搬過來,建議這次一併清掉, 不只是修 Setup script 那一行 bug。