Files
Arcrun/.agents/specs/arcrun/sdk-and-website/self-hosted-init.md
T
uncle6me-web 922a57fe34 arcrun — AI workflow execution engine (clean history)
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>
2026-06-03 15:52:38 +08:00

14 KiB
Raw Blame History

Design 補充:acr init --self-hosted 一鍵自動化(installer 模式)

2026-06-01 初稿 → 2026-06-02 定案改寫(richblack 拍板 installer 形態)。 本檔是 sdk-and-website/design.md 的單檔補充(規則 02 §4.3 允許)。 狀態:design 已與 richblack 對齊;實作前讀 §6 前置依賴。 背景:戰法從 SaaS 轉 self-hosted 開源(docs/HANDOFF-self-host-harness.md §0)。


1. 定案形態(richblack 2026-06-02

arcrun CLI = installer / orchestrator(類似 rustup / nvm:工具本身小,按需從遠端拉真正內容)。

用戶只做 4 件事,中間什麼都不用懂:

  1. 申請 CF 帳號
  2. 安裝 CF CLIwrangler
  3. 安裝 arcrun CLInpm i -g arcrun
  4. acr init --self-hosted(貼 CF Account ID + API Token)→ 完成,其餘看機器跑

CLI 自動做(用戶無感):

  • 驗 CF token 權限
  • 建 7 個 KV namespace + 1 個 R2 bucket(冪等)
  • 從 GitHub release 下載預編譯部署物(含 24 個 .wasm + 各 Worker 的 wrangler.toml + cypher-executor/registry
  • 把建好的 KV namespace id 注入各 wrangler.toml + cypher-executor 的 WORKER_SUBDOMAIN
  • wrangler deploy 部署全部 Worker(用戶已裝 wrangler
  • seed auth recipe + API recipe 進 RECIPES KV
  • 寫回 ~/.arcrun/config.yaml
  • 印出「手動 wrangler secret put ENCRYPTION_KEY ×3」提示(secret 不自動化,rule 05

關鍵技術決策(richblack 2026-06-02

決策 選擇 理由
零件部署物 預編譯 .wasm(不在用戶端 build 用戶不懂 tinygo、也不該懂。下載即用。
部署工具 wranglershell out 用戶已裝 CF CLI;self-host 本來就有上傳能力。CLI 不自己重寫 CF Script Upload API。
源碼來源 GitHub release tarball(含預編譯 wasm 版本明確、不需用戶有 git、acr update 拉新 release 同一條路。
為何不是 git clone repo 沒 commit .wasmrule 05 build 產物不 commit)→ clone 拿不到 wasm 必須走含 wasm 的 release artifact。

2. 為什麼是 installer 而非「repo 內掃 wrangler.toml」(推翻初稿)

初稿假設「用戶在 repo 內跑、CLI 掃 wrangler.toml」。推翻,因為:

  • npm 全域裝的 acr 手上沒有 24 個 Worker 源碼。
  • repo 沒 commit .wasm(已查證 git ls-files .component-builds | grep .wasm = 0)→ 連 clone 都拿不到可部署的 wasm。
  • 用戶不該需要懂 git / tinygo / repo 結構。

→ 正解:CLI 當 installer,從 GitHub release(含預編譯 wasm 拉部署物到暫存目錄,在暫存目錄注入 KV id 後 wrangler deploy


3. 流程設計(initSelfHosted 改寫)

acr init --self-hosted
  │
  ├─ 1. 問 2 輸入:CF Account ID + CF API Token
  │     wrangler 是否已裝?which wrangler;沒裝 → 提示先裝 CF CLI 再來)
  │     驗 tokenCF API GET /accounts/{id}/tokens/verify + GET /accounts/{id}
  │     缺權限(Workers Scripts Edit / KV Edit / R2 Edit)→ exit 1 指出缺哪個 scope
  │
  ├─ 2. 建資源(冪等:先 list 已存在就重用)
  │     7 KVWEBHOOKS / CREDENTIALS_KV / RECIPES / USERS_KV /
  │            SESSIONS_KV / ANALYTICS_KV / EXEC_CONTEXTrule 01 資料儲存表)
  │     1 R2WASM_BUCKET
  │
  ├─ 3. 下載部署物:GitHub release tarball → 解壓到暫存目錄 (~/.arcrun/.deploy-<ver>/)
  │     內含:cypher-executor/ + registry/ + .component-builds/*(每個含預編譯 component.wasm + wrangler.toml
  │
  ├─ 4. 注入設定到暫存目錄的 wrangler.toml(不改用戶 repo,改暫存副本)
  │     - 各 Worker 的 KV binding id ← step 2 建立的
  │     - cypher-executor [vars] WORKER_SUBDOMAIN ← CF API GET /accounts/{id}/workers/subdomain
  │
  ├─ 5. 部署:對暫存目錄每個含 wrangler.toml 的 dirshell out
  │     `wrangler deploy`env CLOUDFLARE_API_TOKEN=<token>, CLOUDFLARE_ACCOUNT_ID=<id>
  │     分兩層:tier1 = .component-builds/*(先)→ tier2 = cypher-executor / registry(後)
  │     每個 wrangler.toml 已含 workers_dev = true → workers.dev URL 自動啟用
  │
  ├─ 6. seed recipe 進 RECIPES KV(部署後打新 cypher URL,或直接 CF KV API 寫)
  │     - auth recipe:重用 AUTH_RECIPE_SEEDScypher-executor/src/lib/auth-recipe-seeds.ts
  │     - API recipe:新增 seed-api-recipes.ts(見 §5
  │
  ├─ 7. 寫回 configmode: self-hosted + 所有 id + cypher_executor_url = 部署後 workers.dev URL
  │
  └─ 8. 印手動 secret 提示:
        wrangler secret put ENCRYPTION_KEY --name arcrun-cypher-executor
        wrangler secret put ENCRYPTION_KEY --name arcrun-auth-static-key
        wrangler secret put ENCRYPTION_KEY --name arcrun-auth-service-account
        (三 Worker 共用同一把 key,見 memory: encryption-key-drift-trap

acr update(同一條路,未來新零件)

  • 拉新 GitHub release → 解壓 → 注入既有 config 的 KV id → wrangler deploy 變動的 Worker。
  • 第一期至少做到「重跑等效 init 的部署步驟」;diff-only 部署可後續優化。

4. 動到的檔案

檔案 動作
cli/src/commands/init.ts 改寫 initSelfHosted()line 105-131)為 installer 流程
cli/src/lib/cf-api.ts 擴充:KV namespace 建立/list、R2 bucket 建立、subdomain 查詢、token verify
新增 cli/src/lib/deploy.ts(暫定) 下載 release tarball + 解壓 + 注入 wrangler.toml + shell out wrangler deploy
新增 cli/src/commands/update.ts(暫定) acr update:拉新 release 重部署
新增 cli/src/lib/api-recipe-seeds.ts API recipe 種子資料installer 用;放 CLI 端,不放 cypher-executor/src——rule 02 §2.2 hook 擋 cypher-executor TS hard-code endpoint,且 seed 資料本就屬 installer 職責)
新增 cypher-executor/scripts/seed-api-recipes.ts seed 腳本(給 prod 補灌用,import CLI 的種子資料;scripts/ 不受 §2.2 hook 管)
cli/src/index.ts 註冊 acr update 指令

不動cypher-executor 執行路徑、既有零件 wasm 源碼、config 讀取端(config.ts:52 已支援 self-hosted)。


5. API recipe seed(新增 seed-api-recipes.tsrichblack 2026-06-02 定)

codebase 只有 auth recipe seed。新增 seed-api-recipes.ts,把現役 API recipe hard-code 成種子。

現役 API recipe(從 prod KV 查得,2026-06-01

  • kbdb_get+ create_block / patch_block / delete / ingest)→ auth_service: kbdb
  • gmail_send → google_gmail_sa
  • google_sheets_append / google_sheets_read → google_sheets_sa
  • telegram_send → telegram
  • line_notify_send → line_notify

KBDB recipe 採 Supabase 模式(richblack 2026-06-02

  • KBDB 是 richblack 提供的服務(跟 arcrun 一樣),採「基礎免費、大量收費」。
  • KBDB recipe 進 seed(展示能力 = 引子,Supabase 模式)。使用者要用 → 去 arcrun 取統一 API Key(已有 /register 入口),把 key 設成 credential。
  • ⚠️ FOLLOW-UP(交 KBDB 端):現役 endpoint 是 kbdb.finally.click{{_path}}。richblack:這是 KBDB 端要改的問題——KBDB 該用統一對外網址提供大家用,不是 finally.click。seed 先照現況進;KBDB 端改網址後同步更新 seed。 此事不擋 init 實作。

6. 部署物產製:commit wasm 進 repo + codeload tarballrichblack 2026-06-02 定案)

此節取代初稿的「GitHub release artifact」構想。richblack 拍板更輕的做法: 直接把預編譯 wasm commit 進 repoCLI 從 GitHub codeload tarball 拿。不需 release.yml 機制。

6.1 策略

  • repo 自帶可部署的 wasm:刪 .gitignore*.wasm 排除,commit 預編譯 wasm 進 repo。 → repo 本身就是部署來源,CLI 直接拿、用戶用自己的 CF token deploy。
  • CLI 走 codeload tarballhttps://codeload.github.com/richblack/arcrun/tar.gz/{ref} ref = main 或 tag)。用戶不需 git、版本可控(tag)。acr update 拉新 ref。
  • 理由richblack):「我在我的 CF 能用 = 我已擁有 wasm;用戶指向我的 GitHub 取得 wasm 用他自己的 CF credential deploy。開源,看不看源碼不重要,體驗好最重要。」

6.2 ⚠️ 推翻既有鐵律(rule 05)— 需同步改規則

.claude/rules/05-deploy-convention.md 明文「.component-builds/{name}/component.wasm 不 commit 進 repo build 產物)」「Phase 1-3 暫時 commit 過,之後會加 .gitignore 清理」。 本決策反向commit wasm 進 repoself-host 需 repo 自帶可部署 wasm)。 → 實作時必須同步改 rule 05 + .gitignore,否則 pre-write hook / 規則與實作打架。 → deploy.yml 的 CI rebuild 步驟仍保留(CI 部署 prod 時用最新 source rebuild,與 commit 的 wasm 不衝突; commit 的 wasm 是給「self-host 用戶 + acr init」用的部署來源)。

6.3 只 commit 部署所需的 wasm(省空間)

  • 實況(2026-06-02 查):registry/components/*.wasm 23 個(build 中間產物)+ .component-builds/*/component.wasm 22 個(部署物),共 ~50MB
  • 部署只需 .component-builds/*/component.wasmwrangler deploy 認這個)。 → 只 commit .component-builds/*/component.wasm22 個),不必 commit registry 那 23 個(省一半)。 .gitignore 改成:保留排除 registry/components/**/*.wasm(中間產物),只放行 .component-builds/**/component.wasm
  • ⚠️ 誠實 trade-offmindset §7):commit wasm 進 repo → 每次 wasm rebuild 都在 git 歷史累積二進位, repo 長期會膨脹。可接受(self-host 體驗優先),但記錄此代價;未來若膨脹過劇,再考慮 release artifact / git-lfs。

6.3.1 「錯做成零件」的 3 個不 commitrichblack 2026-06-02

實際 commit 的是 19 個正當零件,不是 22。排除的 3 個:claude_api / km_writer / kbdb_upsert_block

  • 原因(richblack 修正「待刪」說法):它們不是 endpoint 薄殼,是把工作流硬塞進零件(違反 DECISIONS §1)。 例:kbdb_upsert_block 的 upsert 邏輯應在 KBDB API 那邊(API 提供 upsert endpoint),零件只該驅動它; 現在卻把「GET 找→有則 PATCH 無則 POST」整段工作流塞進零件。本質是工作流/recipe,被錯做成零件。
  • 為何「現在就不 commit」而非「先 commit 之後刪」commit 二進位進 git 歷史後,即使日後 git rm, 歷史裡仍永久殘留(repo 體積已被佔),除非 rewrite history(很麻煩)。錯誤的東西不灌進永久歷史。
  • 落地.gitignore 放行 22 個後再排除這 3 個(後出現規則勝出);deploy.ts discoverWorkerDirs 只部署「同時有 wrangler.toml + component.wasm」的目錄 → self-host 用戶 codeload 拿到的目錄缺這 3 個 wasm → 自然跳過。
  • 後續:這 3 個的降級(變回工作流/recipe)是 BACKLOG 既有待辦,本次不處理,但確保它們不進 self-host 部署來源。

6.4 CLI deploy 流程(deploy.ts downloadAndDeploy 補實作)

1. 下載 codeload tarballref 預設 mainacr update 可帶 tag)→ 解壓 ~/.arcrun/.deploy-<ref>/
2. 讀解壓出的 .component-builds/* + cypher-executor/ + registry/
3. 各 wrangler.toml 注入 ctx.kvNamespaceIds + cypher-executor WORKER_SUBDOMAIN
4. tier1=.component-builds/*(先)→ tier2=cypher-executor/registry(後)
   每個 dirpnpm install(若有 lock)→ CLOUDFLARE_API_TOKEN=<用戶> wrangler deploy
5. 回 cypherExecutorUrl = https://arcrun-cypher-executor.<subdomain>.workers.dev

注意:tier2cypher-executor/registry)是 TSwrangler deploy 會在用戶端用內建 esbuild bundle (不需額外工具,richblack 確認源碼可見不重要、體驗優先 → artifact 含 TS 源碼即可)。

6.5 實作順序

  1. .gitignore(放行 .component-builds/**/component.wasm+ commit 22 個 wasm。
  2. 同步改 rule 05(記錄此決策推翻原慣例)。
  3. 補實 deploy.ts downloadAndDeploycodeload 下載 + 注入 + wrangler deploy)。
  4. 在 1-2 完成前,downloadAndDeploy 維持誠實 unimplemented,不假裝(mindset §7)。

6.6 未來方向:零件按需安裝(richblack 2026-06-02,現在不做)

  • 現在 acr init --self-hosted 全裝基礎零件22 個一次部署)。簡單、夠用。
  • 未來若零件數量真的變很多,再思考「按需安裝」(只裝 workflow 實際用到的零件 / 用戶選裝)。
  • 現在不做的理由(DECISIONS 附錄「會不會累積成債」):零件目前少且未來絕大多數是 recipe (不需 deploy)→ 為「零件爆量」做按需安裝基建 = 為不存在的規模做自動化 = 過度工程。 零件真的爆量再回頭做,屆時是「未來一次性處理的設計點」,現在不必焦慮。

7. 驗收標準(客觀證據,mindset §7)

  1. richblack 用全新 CF 帳號 + wrangler 已裝 + 一個 CF API Token 跑 acr init --self-hosted → 全程無手動建 KV / 無手動 clone / 無 tinygo / 無手動填 namespace id。
  2. 跑完印 secret 提示,richblack 手動 wrangler secret put ENCRYPTION_KEY ×3。
  3. acr push 一個含 http_request + 自建 recipe 的 workflow → trigger → HTTP 2xx + execution trace
  4. 冪等:重跑 init 不重建已存在 KV / 不報錯。
  5. acr update 拉新 codeload tarballtag)→ 重部署成功。

8. 為何不違反鐵律

  • 只動 cli/ + 新增 cypher-executor/scripts/(seed 腳本,非執行路徑業務邏輯)。
  • 不在 registry/components/ 寫 TS;不在 cypher-executor TS 實作 credential/auth/JWT。
  • 不新增 Service Binding。
  • secret 不進自動化(§3 step 8 手動)。
  • 不重寫部署輪子(用 wrangler,不自寫 CF Script Upload)。