922a57fe34
Self-hosted 開源:WASM 零件 + recipe + cypher-executor,跑在你自己的 Cloudflare。 此為重建的乾淨歷史起點(移除曾誤 commit 的 GCP SA 金鑰,舊歷史保留在 richblack/arcrun 與本地 backup 分支)。含: - acr init --self-hosted installer(建 KV/R2 + codeload 拉預編譯 wasm + wrangler deploy + seed recipe) - recipe push 把關(資料外流提醒 + 打通檢查) - 19 個正當零件預編譯 wasm(claude_api/km_writer/kbdb_upsert_block 排除:違反 DECISIONS §1) - CLI / cypher-executor / registry / 完整 SDD Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
193 lines
14 KiB
Markdown
193 lines
14 KiB
Markdown
# 交辦文件:完成 arcrun self-hosted harness(給接手的 CC)
|
||
|
||
> 建立:2026-06-01(由前一個 CC 調查後撰寫)
|
||
> 對象:接手的外部 CC
|
||
> 目的:把 arcrun 補到「任何 CC 在自己的 CF 帳號上 self-host 後就能順暢開發、且不可能重蹈 mira 的錯」的程度。
|
||
>
|
||
> **先讀**:`DECISIONS.md`(穩定決策)、`.claude/rules/06-mindset.md`(mindset)、`BACKLOG.md`(流動待辦)。
|
||
> 本文件不取代它們,只是把「今天要做的三件事」連同已查證的實況整理好,讓你不用重跑調查。
|
||
|
||
---
|
||
|
||
## 0. 戰法已轉變(最重要的背景)
|
||
|
||
richblack 2026-06-01 決定:**從 SaaS 改成 self-hosted 開源策略。**
|
||
|
||
這直接改變 harness 的成功定義:
|
||
|
||
- **舊定義**:在 richblack 的 prod 帳號(`cypher.arcrun.dev`)上能跑。
|
||
- **新定義**:**任何 CC 在自己的 CF 帳號上 `acr init --self-hosted` 後就能跑通一個含 recipe 的 workflow,而且寫錯時會被程式擋住。**
|
||
|
||
richblack 會用另一個 CF 帳號實測 self-host。所以「self-hosted 一鍵起得來」從「第一期重要但非阻擋項」**升為今日第一優先**。
|
||
|
||
### arcrun 現在的核心心智(richblack 2026-06-01 校準,比 DECISIONS §1 更硬)
|
||
|
||
- 核心**零件數量少、由 richblack 維護、不接受 CC 自製**(可投稿 PR,人 merge = 閘門)。
|
||
- 其他人做的一律是 **recipe**(= http_request + 一組 YAML 設定,不用 deploy)。
|
||
- arcrun 是**一套給 CC 的 harness**:事前提醒 CC 能用什麼 / 不能做什麼,事後用程式擋住讓它**無法犯錯**。
|
||
- **你不用管 mira。** mira 是錯誤做法的源頭(見 §1),它自己會修。你的目標是讓**任何** CC 都能用,且絕不會發生 mira 的錯。
|
||
|
||
---
|
||
|
||
## 1. mira 故障 = 症狀樣本(已定位,不用你修)
|
||
|
||
mira(`/Users/youlinhsieh/Documents/tech_projects/InkStoneCo/polaris/mira/arcrun/*.yaml`)的 workflow 寫 `component: kbdb_get` / `claude_api` / `telegram` 等。這些是 **mira 當初自己錯做的「假零件」**(DECISIONS §1 判準:打固定 endpoint 的東西是假零件,該是 recipe)。
|
||
|
||
本次整修(BACKLOG 步驟3)已把這些假零件**降級成 recipe + 刪掉零件目錄**(registry/components 從 33 → 22)。所以 mira 斷了。
|
||
|
||
**這證明的事**:mira 的錯,正是當時 harness 沒擋住的漏洞。零件刪了,但 harness 還缺「**事前告訴 CC 別這樣做 + 事後擋住 CC 這樣做**」的完整機制 → 下一個 CC 還會犯同樣的錯。**這就是你要補的(§3 task 2)。**
|
||
|
||
---
|
||
|
||
## 2. 已查證的實況(你不用重查,2026-06-01 實打 prod)
|
||
|
||
### 2.1 降級後的 recipe 鏈路是「活的」✅
|
||
|
||
實打 `https://cypher.arcrun.dev/recipes`(richblack prod)確認以下 recipe 都在 KV:
|
||
|
||
| canonical_id | hash | endpoint | auth_service |
|
||
|---|---|---|---|
|
||
| `kbdb_get` | rec_4c7dcf9b | `https://kbdb.finally.click{{_path}}` | kbdb |
|
||
| `gmail_send` | rec_cd426129 | gmail.googleapis.com/.../send | google_gmail_sa |
|
||
| `google_sheets_append` | rec_9fd1b662 | sheets.googleapis.com{{_path}} | google_sheets_sa |
|
||
|
||
→ **「對的用法」(`component: kbdb_get` 走解析鏈 step 6 查 `recipe:kbdb_get`)本身是通的。** 不需要重建 recipe。
|
||
|
||
> 注意:這是 richblack 的 prod KV。**self-host 的新帳號 KV 是空的**,需要 seed 這些 recipe(見 §3 task 1 的 seed 步驟)。
|
||
|
||
### 2.2 component-loader 解析鏈(`cypher-executor/src/lib/component-loader.ts`)
|
||
|
||
`resolveComponent` 依序嘗試 8 層(行號近似,以實際檔案為準):
|
||
|
||
```
|
||
0. 平台 orchestration 零件(trigger_workflow) line ~88
|
||
1. 內建零件(純 JS) line ~96
|
||
2. 外部 URL(http(s)://...) line ~100
|
||
3. cmp_hash → WEBHOOKS KV idx → 邏輯 Worker line ~105
|
||
4. rec_hash → RECIPES KV idx → recipe 執行 line ~115
|
||
5. 邏輯零件 canonical_id → Service Binding (SVC_*) line ~122
|
||
5.5 auth recipe (auth_recipe:{service}) line ~127
|
||
6. KV recipe canonical_id → RECIPES KV → fetch 外部 API line ~130 ← kbdb_get 等降級 recipe 命中這層
|
||
7. WASM HTTP runner(白名單 WASM_HTTP_RUNNER_IDS) line ~134
|
||
8. 找不到 → 報錯 line ~142
|
||
```
|
||
|
||
`WASM_HTTP_RUNNER_IDS` 白名單(line ~36)現只剩:`http_request` / `cron` / 4 個 `auth_*` primitive。
|
||
→ `claude_api`、`kbdb_upsert_block`(BACKLOG 標 deferred、源碼暫留)**不在白名單也沒 recipe** → 用到它們的 workflow 會落到 step 8 報錯。這是 mira 自己的問題,不在你範圍。
|
||
|
||
### 2.3 `acr init --self-hosted` 現況:純手動問答,差很遠
|
||
|
||
`cli/src/commands/init.ts` 的 `initSelfHosted()`(line 105-131)**只是問 6 個問題後寫進 config**:
|
||
要求 CC 自己**事先**部署好 Worker、建好 KV、再手填 Account ID / cypher URL / 兩個 KV namespace ID / WASM bucket / CF token。
|
||
|
||
BACKLOG 步驟7 要的是「**貼 CF token → 自動建 KV、部署 Worker、自動 workers.dev、寫回 config**」。**這是最大缺口,task 1 的主體。**
|
||
|
||
config 讀取端已支援 self-hosted(`cli/src/lib/config.ts:52` 已能用 `cypher_executor_url`),所以你只要把「自動部署」這段補上,config/執行端不用動。
|
||
|
||
### 2.4 CI/CD 已是通用掃描式(可重用於 self-host 部署)
|
||
|
||
`.github/workflows/deploy.yml` 掃所有含 `wrangler.toml` 的目錄自動部署(見 `.claude/rules/05-deploy-convention.md`)。
|
||
self-host 自動部署可以參考同一套掃描邏輯(`find . -name wrangler.toml`),對每個目錄跑 `wrangler deploy`。
|
||
|
||
---
|
||
|
||
## 3. 今天要做的三件事(按序,全在 harness 主線)
|
||
|
||
> richblack 指示:「全部要做」(含 `acr init --self-hosted`)。
|
||
> 三件都做完 = 今天可交付:外部 CC 能 self-host 起來、用對的方式開發、犯錯被擋。
|
||
|
||
### 🔴 Task 1:完成 `acr init --self-hosted` 一鍵自動化(第一優先)
|
||
|
||
> ✅ **實作狀態(2026-06-02,已大致完成)**:定稿形態為 **installer 模式**(richblack 拍板)——
|
||
> 用戶只做:申請 CF 帳號 → 裝 wrangler → 裝 acr → `acr init --self-hosted`(貼 token),其餘自動。
|
||
> 已實作(typecheck 過):`cli/src/lib/api-recipe-seeds.ts`(10 recipe 種子)、`cf-api.ts` 的
|
||
> `CfAccountClient`(建 KV/R2/查 subdomain/驗 token)、`deploy.ts`(常數 + downloadAndDeploy)、
|
||
> `initSelfHosted()` 改寫、`acr update`、`cypher-executor/scripts/seed-api-recipes.ts`。
|
||
> **唯一剩餘前置(13.6)**:repo 沒有含預編譯 wasm 的 GitHub release(.wasm 不 commit,rule 05)→
|
||
> `downloadAndDeploy()` 目前**誠實回 implemented:false 不假裝部署**(mindset §7)。建 KV/R2/seed/config
|
||
> 已可跑;release 產製管道補上後部署即自動化。定稿設計見 SDD `self-hosted-init.md`(含 §6 前置依賴)。
|
||
> **以下原始子步驟保留供對照**;KBDB recipe 採 Supabase 模式進 seed(richblack 2026-06-02)。
|
||
|
||
**目標**:CC 只需提供「CF Account ID + CF API Token」,CLI 自動完成其餘一切。
|
||
|
||
**SDD**:定稿 `.agents/specs/arcrun/sdk-and-website/self-hosted-init.md`(installer 模式,已與 richblack 對齊)。
|
||
|
||
**子步驟**:
|
||
1. 改 `cli/src/commands/init.ts` 的 `initSelfHosted()`:
|
||
- 收 CF Account ID + CF API Token(要 KV Edit + Workers Scripts Edit + R2 權限)。
|
||
- 用 CF API(或 shell out `wrangler`)**自動建 7 個 KV namespace**:WEBHOOKS / CREDENTIALS_KV / RECIPES / USERS_KV / SESSIONS_KV / ANALYTICS_KV / EXEC_CONTEXT(清單見 `.claude/rules/01-tech-stack.md` 資料儲存表)+ R2 WASM_BUCKET。
|
||
- **自動部署所有 Worker**:cypher-executor + registry + 22 個 `.component-builds/*`。可重用 §2.4 的 `wrangler.toml` 掃描。每個 worker 的 `wrangler.toml` 已含 `workers_dev = true`(BACKLOG 步驟 P1#2 已做),部署後 workers.dev URL 自動啟用。
|
||
- **把 cypher-executor 的 `[vars] WORKER_SUBDOMAIN` 改成 CC 自己的帳號 subdomain**(self-host 關鍵,見 P0 #9:cypher-executor 走 `arcrun-{name}.{subdomain}.workers.dev` 對內 URL)。
|
||
- **seed 降級 recipe + auth recipe 進 RECIPES KV**:新帳號 KV 是空的。把 §2.1 那些 recipe(kbdb_get/gmail_send/...)+ auth recipe seed 寫進去。auth recipe seed 已有 `cypher-executor/scripts/seed-auth-recipes.ts`,API recipe 需確認有對應 seed 機制(routes/recipes.ts 是動態 push,可能要寫一份 seed 腳本或用 `acr recipe push`)。
|
||
- 寫回 config(現有欄位已足夠)。
|
||
2. **runtime secret 不進 CLI 自動化**:`ENCRYPTION_KEY` 等由 CC 自己 `wrangler secret put`(rule 05 禁止 secret 進自動化流程)。CLI 應在最後**印出提示**告訴 CC 要手動 put 哪些 secret 到哪些 worker。
|
||
|
||
**驗收(客觀證據,不是口頭宣布 — mindset §7)**:
|
||
- richblack 用全新 CF 帳號跑 `acr init --self-hosted` → 全程無手動建 KV / 部署。
|
||
- 跑完後 `acr push` 一個含 `component: kbdb_get`(或 http_request + 自建 recipe)的 workflow → trigger → HTTP 2xx + execution trace 證明跑通。
|
||
|
||
### 🔴 Task 2(已重定義 2026-06-01):封鎖自製零件 + recipe 入庫把關
|
||
|
||
> ✅ **實作狀態(2026-06-02,第一期部分完成)**:(1) 封鎖自製零件 = 靠 GitHub PR 人 merge,無需新做
|
||
> (矛盾已釐清)。(2a) 資料外流提醒 = **既有實作已涵蓋**(recipe.ts `obtainExposureConsent` + exposure-warning.ts,
|
||
> 非 TTY 拒絕)。(2b) 打通檢查 = **新增** `probeRecipeEndpoint`(recipe.ts,typecheck 過):push 後實打
|
||
> endpoint,提醒級不硬擋,含 {{模板}} 誠實說明待 run 才知,401/403 標「多半缺 credential 非 bug」。
|
||
> 公共庫 relay 檢核(--public)= 第一期後。SDD `recipe-push-gatekeeping.md` + tasks.md W2。
|
||
|
||
> ⚠️ **方向修正(richblack 2026-06-01)**:原 Task 2「acr validate 擋假零件名」**作廢**。
|
||
> 理由:自製/修改零件的路已封鎖(CC 造不出零件)→「擋假零件」這件事不存在;workflow 引用
|
||
> recipe(`component: kbdb_get`)是合法且未來唯一的擴充方式,不該被當假零件擋。
|
||
> 把關點**從 workflow validate 移到 recipe 入庫(push)那一刻**。
|
||
> 已動的 yaml-parser.ts(LEGAL_PRIMITIVES / findSuspectComponents)**已回退**。
|
||
|
||
**新目標**:
|
||
1. **封鎖自製零件**:靠「零件投稿走 GitHub PR + 人 merge」天然閘門(DECISIONS §8)。零件數量少、
|
||
絕大多數是 recipe → 不為零件 PR 蓋自動化把關(量少,人工檢查即可;爆量才回頭想自動化)。
|
||
2. **recipe 入庫把關**(CC 唯一能擴充的是 recipe,一律用 push,自有庫/公共庫同一套指令):
|
||
- **自有庫(self-hosted)= 提醒級**:(a) 資料外流提醒——會讓資料/服務對外可見的動作需人類明示同意;
|
||
(b) 打通檢查——push 時實打 endpoint 回報 2xx 與否(誠實標原因,不假綠,不硬擋)。
|
||
- **公共庫 = 維護者 relay 檢核**(實際打通、真收到成功回傳)— 第一期後。
|
||
|
||
**SDD**:已寫 design 給 richblack review →
|
||
`.agents/specs/component-gatekeeping/recipe-push-gatekeeping.md`(+ tasks.md W2 節)。**review 通過才動 code。**
|
||
|
||
**動到的檔案(待 review)**:`cli/src/commands/recipe.ts`(push 加提醒 + 打通檢查)、確認 data-exfil hook 涵蓋 recipe push 路徑。
|
||
|
||
**驗收**:
|
||
- `acr recipe push` 會產對外 webhook 的東西 → 印資料外流警示 + 要人類同意;非 TTY → 拒絕。
|
||
- `acr recipe push` endpoint 可達的 recipe → 回報「✓ HTTP 2xx」。
|
||
- `acr recipe push` 缺 credential → 回報「⚠️ 未打通:缺 credential」(誠實),仍允許 push。
|
||
- workflow 引用 recipe(`component: kbdb_get`)**不被任何 validate 步驟當假零件擋**。
|
||
|
||
### 🔴 Task 3:README 重寫成單一路徑 — harness「事前提醒」
|
||
|
||
**目標**:self-hosted 開源後,README 是外界 CC 唯一入口。砍掉「玩法一/二/三」三選一,講清楚單一正確路徑。
|
||
|
||
**子步驟**(改根 `README.md`):
|
||
1. 砍三選一玩法,留**一條路**:`acr init --self-hosted` → 寫 workflow(primitive 串 + recipe)→ `acr push` → trigger。
|
||
2. 明示心智(呼應 mindset §1):「零件就這固定幾個由我們維護、不接受自製;要打外部 API 就寫 recipe;要編排就寫工作流。」
|
||
3. 連到 `.claude/rules/06-mindset.md` / arcrun-mindset Skill,讓 CC 一開始就有正確世界觀。
|
||
|
||
**驗收**:README 讀完,一個沒看過 arcrun 的 CC 知道:能用什麼、不能自製零件、打外部 API 要寫 recipe、怎麼 self-host 起來。
|
||
|
||
---
|
||
|
||
## 4. 今天「不要做」的(避免你走偏)
|
||
|
||
| 項目 | 為何不做 |
|
||
|---|---|
|
||
| 修 mira | richblack 明示不用管,mira 自己修 |
|
||
| 步驟2 `acr recipe test` / relay / credits | DECISIONS §3c 明確劃為服務側、非第一期 |
|
||
| 步驟6 搬家拆 matrix | 純 repo 整理,不影響 CC 能否用 |
|
||
| 砍 `injectCredentials` 舊路 / `BUILTIN_CREDENTIALS_MAP` | 獨立清理,不擋交付(DECISIONS §3b / BACKLOG「第一期之後」)|
|
||
| 新 primitive / Gherkin 真跑 / 入站認證 | richblack 已標「不要現在做」 |
|
||
|
||
---
|
||
|
||
## 5. 鐵律提醒(違反會被 hook block)
|
||
|
||
- 任何 code 變動前先讀對應 SDD + 在回覆開頭宣告(`.claude/rules/00-sdd-protocol.md`)。
|
||
- `registry/components/` 下禁止 TS;cypher-executor TS 禁止 credential/auth/JWT 業務邏輯(`.claude/rules/02-forbidden.md`,hook 強制)。
|
||
- 每完成一個 task 立刻更新對應 tasks.md / BACKLOG.md 的 `[x]`,不批次。
|
||
- 誠實限制(mindset §7):stub / 未完成就標 unimplemented,**不假綠**;完成 = 客觀證據(exit code / HTTP status + trace),不是口頭宣布。
|