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>
This commit is contained in:
Executable
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
# .claude/hooks/post-edit-remind-tasks.sh
|
||||
# arcrun PostToolUse hook for Write / Edit / MultiEdit
|
||||
#
|
||||
# 職責:改完 code 後立刻提醒 CC 更新對應 tasks.md,避免批次更新
|
||||
# 退出 code:不 block,只提醒(exit 0)
|
||||
|
||||
set -o pipefail
|
||||
|
||||
INPUT=$(cat)
|
||||
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
|
||||
|
||||
# 只針對程式碼檔案提醒(不含 tasks.md / CLAUDE.md / rules/*.md 本身)
|
||||
if [[ "$FILE_PATH" =~ \.(go|ts|tsx|js|jsx|py|rs|wasm)$ ]] && [[ "$FILE_PATH" != *"tasks.md"* ]]; then
|
||||
cat >&2 <<EOF
|
||||
|
||||
📌 PostEdit 提醒(by arcrun hook)
|
||||
剛修改了:${FILE_PATH}
|
||||
|
||||
下一步動作:
|
||||
1. 找到對應的 .agents/specs/*/tasks.md
|
||||
2. 如果這個 task 已完成 → 立刻把 [ ] 改成 [x](或把進行中的 [🔄] 改成 [x])
|
||||
3. 如果發現新的 sub-task → 立刻加入 tasks.md
|
||||
4. 不要等到 session 結束才批次更新
|
||||
|
||||
違反 SDD 協議會在 Stop hook 被提醒,建議現在就處理。
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Executable
+106
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
# .claude/hooks/pre-bash-guard.sh
|
||||
# arcrun PreToolUse guard for Bash
|
||||
#
|
||||
# 職責:擋下會違反 CLAUDE rules 的 shell 指令
|
||||
# 退出 code:
|
||||
# 0 = 允許
|
||||
# 2 = 擋下(stderr 訊息會回傳給 CC)
|
||||
|
||||
set -o pipefail
|
||||
|
||||
INPUT=$(cat)
|
||||
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
|
||||
|
||||
block() {
|
||||
local rule="$1"
|
||||
local reason="$2"
|
||||
local fix="$3"
|
||||
cat >&2 <<EOF
|
||||
❌ BLOCKED by arcrun CLAUDE rules
|
||||
違反項:${rule}
|
||||
指令:${CMD}
|
||||
原因:${reason}
|
||||
正確做法:${fix}
|
||||
參考:.claude/rules/02-forbidden.md
|
||||
EOF
|
||||
exit 2
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 1.2 / 3.3:禁止用 mkdir 建立違規的 auth/credential worker 目錄
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
if echo "$CMD" | grep -qE "mkdir.*((auth|credential|jwt|oauth)[-_]worker|new[-_](auth|credential|jwt|oauth))"; then
|
||||
block "1.2/3.3" \
|
||||
"偵測到嘗試建立新的 auth/credential/jwt/oauth Worker 目錄" \
|
||||
"auth primitive 放在 registry/components/auth_*/;不需要另建 worker 目錄"
|
||||
fi
|
||||
|
||||
# 禁止建立同名零件的平行目錄
|
||||
if echo "$CMD" | grep -qE "mkdir.*/(gmail|telegram|google[-_]sheets|line[-_]notify|http[-_]request)[-_](v2|v3|new|worker|backup)"; then
|
||||
block "3.3" \
|
||||
"禁止為既有零件建立平行目錄(v2/new/worker/backup)" \
|
||||
"直接改 registry/components/<n>/main.go"
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 1.3:禁止 wrangler init / generate auth-* credential-* jwt-*
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
if echo "$CMD" | grep -qE "wrangler[[:space:]]+(init|generate).*[[:space:]](auth|credential|jwt|oauth)[-_]"; then
|
||||
block "1.3" \
|
||||
"禁止用 wrangler init/generate 建立 auth/credential/jwt Worker" \
|
||||
"auth primitive 透過 component-worker-template/ 搭配 WASM binary 部署,不要 wrangler init"
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 3.1:Service Binding 新增警示
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 偵測在 wrangler.toml 新增 [[services]] 的 echo/cat/sed 操作(非 100% 準確,但夠用)
|
||||
if echo "$CMD" | grep -qE "echo.*\[\[services\]\].*>>"; then
|
||||
block "3.1" \
|
||||
"偵測到要在 wrangler.toml 新增 [[services]] binding" \
|
||||
"零件串接一律走 HTTP URL(cypher binding),不新增 service binding。若有特殊需求,先與 richblack 確認"
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 一般性危險指令
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
if echo "$CMD" | grep -qE "rm[[:space:]]+-rf[[:space:]]+(/|/\*|~|\\\$HOME|\.)"; then
|
||||
block "general" \
|
||||
"偵測到危險的 rm -rf 指令" \
|
||||
"明確指定要刪的目錄,不要對根目錄 / home / 當前目錄遞迴刪除"
|
||||
fi
|
||||
|
||||
# 禁止 force push 到 main
|
||||
if echo "$CMD" | grep -qE "git[[:space:]]+push.*--force.*(main|master)"; then
|
||||
block "general" \
|
||||
"禁止 force push 到 main/master" \
|
||||
"用 feature branch,或和 richblack 確認後手動操作"
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 資料外流警示(data-exfil-warning SDD R2):AI 動手把資料變成可被外部呼叫前先擋
|
||||
# `acr push`(部署 webhook)/ `acr recipe push`(定義資料去向)= 暴露面動作。
|
||||
# 不含 `acr creds push`(上傳加密 credential 是保護,非暴露)。
|
||||
#
|
||||
# 信任修正(2026-05-30):無「旗標放行」捷徑——AI 自己能加的旗標 = 自己批准自己。
|
||||
# 這類動作一律擋,必須由人類在終端機親自執行(CLI 會跳互動、要人類輸入資源名確認)。
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 只在「指令本身就是執行 acr push / acr recipe push」時擋(錨定到指令開頭,
|
||||
# 允許前置 cd .. && 或環境變數)。避免誤判 git commit -m "...acr push..." 這類
|
||||
# 「字串裡剛好提到 acr push」的情況(commit message / echo / grep 不該被擋)。
|
||||
if echo "$CMD" | grep -qE "(^|&&|;|\|)[[:space:]]*(cd[[:space:]][^&;|]*(&&|;)[[:space:]]*)?([A-Za-z_]+=[^[:space:]]*[[:space:]]+)*acr[[:space:]]+(recipe[[:space:]]+)?push\b" \
|
||||
&& ! echo "$CMD" | grep -qE "acr[[:space:]]+creds[[:space:]]+push\b"; then
|
||||
cat >&2 <<'EOF'
|
||||
❌ BLOCKED:資料外流警示(arcrun data-exfil-warning)
|
||||
原因:acr push / acr recipe push 會把資料/workflow 變成「可被外部呼叫」(暴露面)。
|
||||
這種動作你(AI)不能自行執行,也沒有旗標捷徑——需人類明示知情同意(法律憑證)。
|
||||
正確做法:
|
||||
- 把這件事交給人類:請人類在終端機親自執行(CLI 會跳互動、要人類輸入資源名確認)
|
||||
- 人類第一次確認後 server 會記住,之後同資源不用再確認
|
||||
參考:.agents/specs/data-exfil-warning/
|
||||
EOF
|
||||
exit 2
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Executable
+193
@@ -0,0 +1,193 @@
|
||||
#!/bin/bash
|
||||
# .claude/hooks/pre-write-guard.sh
|
||||
# arcrun PreToolUse guard for Write / Edit / MultiEdit
|
||||
#
|
||||
# 職責:擋下會違反 CLAUDE rules 的檔案寫入操作
|
||||
# 退出 code:
|
||||
# 0 = 允許
|
||||
# 2 = 擋下(stderr 訊息會回傳給 CC)
|
||||
#
|
||||
# 依賴:jq
|
||||
|
||||
set -o pipefail
|
||||
|
||||
INPUT=$(cat)
|
||||
|
||||
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
|
||||
# 取得將要寫入的內容(Write: content;Edit: new_string;MultiEdit: edits[].new_string 全部串起來)
|
||||
CONTENT=$(echo "$INPUT" | jq -r '
|
||||
.tool_input.content
|
||||
// .tool_input.new_string
|
||||
// (.tool_input.edits // [] | map(.new_string // "") | join("\n"))
|
||||
// ""
|
||||
')
|
||||
|
||||
block() {
|
||||
local rule="$1"
|
||||
local reason="$2"
|
||||
local fix="$3"
|
||||
cat >&2 <<EOF
|
||||
❌ BLOCKED by arcrun CLAUDE rules
|
||||
違反項:${rule}
|
||||
檔案:${FILE_PATH}
|
||||
原因:${reason}
|
||||
正確做法:${fix}
|
||||
參考:.claude/rules/02-forbidden.md
|
||||
EOF
|
||||
exit 2
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 1.1:registry/components/ 下不准 TS(除非是 AssemblyScript)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
if [[ "$FILE_PATH" == *"registry/components/"* && "$FILE_PATH" == *.ts ]]; then
|
||||
# 允許 asconfig.json 同目錄的 AssemblyScript
|
||||
COMP_DIR=$(dirname "$FILE_PATH")
|
||||
if [[ ! -f "$COMP_DIR/asconfig.json" ]]; then
|
||||
block "1.1" \
|
||||
"registry/components/ 下禁止 TypeScript(除非是 AssemblyScript 且同目錄有 asconfig.json)" \
|
||||
"零件必須用 TinyGo (main.go) 或 AssemblyScript 實作並編譯成 .wasm"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 1.2:禁止在非法位置新增 auth/credential 實作
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 合法位置:registry/components/auth_static_key | auth_oauth2 | auth_service_account | auth_mtls
|
||||
if [[ "$FILE_PATH" =~ auth[-_](static[-_]key|oauth2|service[-_]account|mtls) ]]; then
|
||||
if [[ "$FILE_PATH" != *"registry/components/auth_"* ]]; then
|
||||
block "1.2" \
|
||||
"auth primitive 實作只能放在 registry/components/auth_<type>/" \
|
||||
"改去 registry/components/auth_static_key/ 等目錄,用 TinyGo 實作 main.go"
|
||||
fi
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 2.1:禁止新增含特定關鍵字的 TS 檔案(credential-injector / jwt-signer 等)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
if [[ "$FILE_PATH" == *.ts ]]; then
|
||||
BASE=$(basename "$FILE_PATH")
|
||||
# 既有的 credential-injector.ts / jwt-signer.ts 允許修改(為了刪除),但不准新增同名
|
||||
if [[ "$BASE" =~ ^(credential[-_]injector|jwt[-_]signer)\.ts$ ]]; then
|
||||
if [[ ! -f "$FILE_PATH" ]]; then
|
||||
block "2.1" \
|
||||
"禁止新增 ${BASE}(Phase 1-3 的目標是刪除此類檔案,不是重建)" \
|
||||
"credential 注入 / JWT signing 屬於 WASM 零件職責,改去 registry/components/auth_*/"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 2.2:cypher-executor TS 裡不准實作業務邏輯(只准 wasi-shim.ts 做 crypto)
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
if [[ "$FILE_PATH" == *"cypher-executor/src/"* && "$FILE_PATH" == *.ts ]]; then
|
||||
BASE=$(basename "$FILE_PATH")
|
||||
|
||||
# crypto.subtle.decrypt:只准在 wasi-shim.ts
|
||||
if echo "$CONTENT" | grep -qE "crypto\.subtle\.decrypt"; then
|
||||
if [[ "$BASE" != "wasi-shim.ts" ]]; then
|
||||
block "2.2" \
|
||||
"AES-GCM 解密(crypto.subtle.decrypt)只准出現在 wasi-shim.ts 的 crypto_decrypt host function" \
|
||||
"把解密邏輯移到 wasi-shim.ts 的 host function;或讓 WASM 零件透過 u6u.crypto_decrypt 呼叫"
|
||||
fi
|
||||
fi
|
||||
|
||||
# crypto.subtle.sign with RSASSA:只准在 wasi-shim.ts
|
||||
if echo "$CONTENT" | grep -qE "crypto\.subtle\.sign.*RSASSA"; then
|
||||
if [[ "$BASE" != "wasi-shim.ts" ]]; then
|
||||
block "2.2" \
|
||||
"RS256 簽章只准出現在 wasi-shim.ts 的 crypto_sign_rs256 host function" \
|
||||
"把簽章移到 wasi-shim.ts;或讓 auth_service_account WASM 透過 u6u.crypto_sign_rs256 呼叫"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Template 展開:{{secret.X}} 或 {{runtime.X}} 屬於 WASM 職責
|
||||
# 例外:auth-recipe-seeds.ts 是 recipe 資料定義(會被序列化寫進 RECIPES KV),
|
||||
# 其中的 {{secret.X}} / {{runtime.X}} 是「資料字面值」而非 TS 展開邏輯,
|
||||
# 真正的展開仍在 WASM auth primitive 內完成。
|
||||
if [[ "$BASE" != "auth-recipe-seeds.ts" ]] && echo "$CONTENT" | grep -qE "\{\{(secret|runtime)\." ; then
|
||||
block "2.2" \
|
||||
"Template 展開({{secret.X}} / {{runtime.X}})屬於 WASM auth primitive 職責" \
|
||||
"把這段邏輯改寫到 registry/components/auth_static_key/main.go(TinyGo)"
|
||||
fi
|
||||
|
||||
# Hard-code 的 BUILTIN_API_RECIPES / BUILTIN_CREDENTIALS_MAP 新增
|
||||
if echo "$CONTENT" | grep -qE "(BUILTIN_API_RECIPES|BUILTIN_CREDENTIALS_MAP)\s*[:=]"; then
|
||||
# 允許「把它設成空物件」或「刪除」,但不准新增實作
|
||||
if echo "$CONTENT" | grep -qE "BUILTIN_API_RECIPES.*=.*\{\s*[a-zA-Z]"; then
|
||||
block "2.2" \
|
||||
"禁止在 TS 裡新增 BUILTIN_API_RECIPES / BUILTIN_CREDENTIALS_MAP 實作" \
|
||||
"API 呼叫邏輯屬於各自的 WASM 零件(gmail.wasm / telegram.wasm 等),cypher-executor 只做 routing"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Hard-code API endpoint 實作
|
||||
HARDCODED_APIS=(
|
||||
"gmail\.googleapis\.com/gmail/v1/users/me/messages/send"
|
||||
"api\.telegram\.org/bot.*sendMessage"
|
||||
"sheets\.googleapis\.com/v4/spreadsheets"
|
||||
"notify-api\.line\.me/api/notify"
|
||||
)
|
||||
for PATTERN in "${HARDCODED_APIS[@]}"; do
|
||||
if echo "$CONTENT" | grep -qE "$PATTERN"; then
|
||||
# 允許 wasi-shim.ts 裡的 http_request host function(它只是 proxy)
|
||||
if [[ "$BASE" != "wasi-shim.ts" ]]; then
|
||||
block "2.2" \
|
||||
"禁止在 cypher-executor TS 裡 hard-code API endpoint(偵測到: $PATTERN)" \
|
||||
"把 API 呼叫移到對應的 WASM 零件(registry/components/gmail/main.go 等)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# exchangeGoogleJwt / 類似 token exchange function
|
||||
if echo "$CONTENT" | grep -qE "(exchangeGoogleJwt|exchangeServiceAccountJwt|signGoogleJwt)"; then
|
||||
if [[ "$BASE" != "wasi-shim.ts" ]]; then
|
||||
block "2.2" \
|
||||
"Token exchange 邏輯屬於 auth_service_account WASM 零件" \
|
||||
"改到 registry/components/auth_service_account/main.go"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 3.3:禁止建立 *-v2 / new-* / *-worker 類複製貼上目錄
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
if [[ "$FILE_PATH" =~ /(auth|credential|jwt|oauth|gmail|telegram|google-sheets|line-notify|http-request)[-_](v2|v3|new|worker|backup|temp)/ ]]; then
|
||||
block "3.3" \
|
||||
"禁止為同一零件建立平行目錄(v2/new/worker/backup 等)" \
|
||||
"直接修改 registry/components/<name>/main.go 即可;需要版本管理請用 git branch"
|
||||
fi
|
||||
if [[ "$FILE_PATH" =~ /new-(auth|credential|jwt|oauth|gmail|telegram)/ ]]; then
|
||||
block "3.3" \
|
||||
"禁止為同一零件建立 new-<name>/ 平行目錄" \
|
||||
"直接修改 registry/components/<name>/main.go"
|
||||
fi
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 規則 4.3:禁止自行在 .agents/specs/ 下建新 SDD 目錄
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
if [[ "$FILE_PATH" == *".agents/specs/"* ]]; then
|
||||
# 檢查是否在已知 SDD 目錄內
|
||||
KNOWN_SDDS=(
|
||||
".agents/specs/arcrun"
|
||||
".agents/specs/u6u-core-mvp"
|
||||
".agents/specs/u6u-platform-evolution"
|
||||
".agents/specs/component-registry-canon"
|
||||
".agents/specs/component-gatekeeping" # 2026-05-29 richblack 確認新建(Phase 3 把關)
|
||||
".agents/specs/data-exfil-warning" # 2026-05-30 richblack 確認新建(資料外流警示)
|
||||
)
|
||||
IN_KNOWN=false
|
||||
for K in "${KNOWN_SDDS[@]}"; do
|
||||
if [[ "$FILE_PATH" == *"$K/"* ]]; then
|
||||
IN_KNOWN=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ "$IN_KNOWN" == "false" ]]; then
|
||||
block "4.3" \
|
||||
"禁止自行在 .agents/specs/ 下建立新的頂層 SDD 目錄" \
|
||||
"先與 richblack 確認 SDD 範圍。若是現有 SDD 的補充檔案,請放到已知 SDD 目錄下"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Executable
+73
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
# .claude/hooks/session-start-load-sdd.sh
|
||||
# arcrun SessionStart hook
|
||||
#
|
||||
# 職責:session 啟動時注入當前進度、絕對禁令、SDD 位置,避免 CC 靠記憶猜測
|
||||
# 輸出走 stdout,會注入到 CC 的 context
|
||||
|
||||
set -o pipefail
|
||||
|
||||
cat <<'EOF'
|
||||
============================================================
|
||||
🚨 arcrun 工作規範(SessionStart 注入)
|
||||
============================================================
|
||||
|
||||
📌 絕對禁令(違反會被 pre-write / pre-bash hook 直接 block):
|
||||
|
||||
1. registry/components/ 下禁止 TypeScript 實作零件
|
||||
→ 只能 TinyGo (main.go) 或 AssemblyScript,編譯成 .wasm
|
||||
|
||||
2. cypher-executor TS 裡禁止實作 credential/auth/JWT 業務邏輯
|
||||
→ crypto.subtle.decrypt / sign 只准出現在 wasi-shim.ts 的 host function
|
||||
→ {{secret.X}} template 展開屬於 WASM 零件職責
|
||||
→ 禁止 hard-code gmail/telegram/sheets API endpoint
|
||||
|
||||
3. 禁止新增 Service Binding 綁零件
|
||||
→ 零件串接走 HTTP URL(cypher binding = YAML 裡的 URL 清單)
|
||||
→ Cypher binding 不是 Cloudflare 的 binding 機制
|
||||
|
||||
4. 每個 WASM 零件 = 獨立 Worker = 公開 URL
|
||||
→ 不是從 R2 動態讀(平台零件已 bundle 進各自 Worker)
|
||||
→ R2 只用於 Phase 5 的用戶自製零件(未啟用)
|
||||
|
||||
📋 任何 code 變動前,必須:
|
||||
|
||||
1. 讀 .agents/specs/arcrun/arcrun.md(總進度)
|
||||
2. 讀對應 task 的 SDD(design.md + tasks.md)
|
||||
3. 在回覆開頭宣告(格式見 .claude/rules/00-sdd-protocol.md):
|
||||
📋 已讀 SDD:<檔案清單>
|
||||
🎯 本次對應 task:<task 編號>
|
||||
📐 本次 task 的 SDD 規範摘要:<重點>
|
||||
🚧 執行範圍:修改/建立/刪除 <檔案>
|
||||
4. 每完成一個 task,立刻更新 tasks.md 的 [x],不批次
|
||||
|
||||
🔥 當前進行中 Phase:Credential Primitives TS → WASM
|
||||
|
||||
SDD:.agents/specs/arcrun/credential-primitives-wasm/
|
||||
已完成:Phase 0.1-0.5(核心合併 + u6u-core 刪除)
|
||||
未完成硬前置:
|
||||
- Phase 0.6 wasi-shim 加 host functions(kv_get / crypto_decrypt / crypto_sign_rs256)
|
||||
- Phase 0.7 component-loader WASM runner 路徑
|
||||
未完成主要任務:
|
||||
- Phase 1 auth_static_key WASM 零件(TinyGo)
|
||||
- Phase 2 auth_service_account WASM 零件
|
||||
- Phase 3 刪除 cypher-executor 的三套違規 TS:
|
||||
* src/actions/credential-injector.ts(整檔刪)
|
||||
* src/lib/jwt-signer.ts(整檔刪)
|
||||
* src/lib/component-loader.ts 的 BUILTIN_API_RECIPES + BUILTIN_CREDENTIALS_MAP(整段刪)
|
||||
|
||||
⛔ 封測狀態:推遲(richblack 2026-04-19 決定)
|
||||
原因:違規 TS 未清,不封測。
|
||||
|
||||
📚 詳細規範:
|
||||
.claude/rules/00-sdd-protocol.md — SDD 協議
|
||||
.claude/rules/01-tech-stack.md — 技術棧硬限制
|
||||
.claude/rules/02-forbidden.md — 禁止清單(hook 強制)
|
||||
.claude/rules/03-component-architecture.md — 零件架構(R2/cypher binding/service binding 的正確定義)
|
||||
.claude/rules/04-current-progress.md — 當前進度 + SDD 索引
|
||||
.claude/rules/06-mindset.md — mindset(為什麼層):工作流是default/零件稀有/AI→工具/誠實不假綠
|
||||
|
||||
============================================================
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
# .claude/hooks/stop-check-sync.sh
|
||||
# arcrun Stop hook
|
||||
#
|
||||
# 職責:session 結束前檢查 code 變動是否有對應的 SDD / tasks.md 更新
|
||||
# 退出 code:不 block,只警告
|
||||
|
||||
set -o pipefail
|
||||
|
||||
# 檢查 .agents/specs 下本次 session 是否有變動
|
||||
SPECS_DIFF=$(git -C "$(pwd)" status --porcelain -- '.agents/specs/' 2>/dev/null | head -20)
|
||||
CODE_DIFF=$(git -C "$(pwd)" status --porcelain -- '*.go' '*.ts' '*.tsx' '*.py' 'cypher-executor/' 'registry/' 'cli/' 2>/dev/null | head -20)
|
||||
|
||||
if [[ -n "$CODE_DIFF" && -z "$SPECS_DIFF" ]]; then
|
||||
cat >&2 <<EOF
|
||||
|
||||
⚠️ Stop hook 警告(by arcrun hook)
|
||||
|
||||
偵測到本 session 有程式碼變動,但 .agents/specs/ 下的 SDD 文件沒有任何變動。
|
||||
|
||||
未 commit 的程式碼變動:
|
||||
$(echo "$CODE_DIFF" | head -10)
|
||||
|
||||
請在結束前確認:
|
||||
1. 對應的 tasks.md 是否已更新 [x]?
|
||||
2. 是否有架構變動需要更新 design.md?
|
||||
3. 是否有 SDD 範圍外的 change 未標記?
|
||||
|
||||
SDD 協議要求:code 和 SDD 必須同步更新。
|
||||
參考:.claude/rules/00-sdd-protocol.md
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
# 若有暫存的 tasks.md 變動,提醒 commit
|
||||
TASKS_DIFF=$(git -C "$(pwd)" status --porcelain -- '.agents/specs/**/tasks.md' 2>/dev/null | head -5)
|
||||
if [[ -n "$TASKS_DIFF" ]]; then
|
||||
cat >&2 <<EOF
|
||||
|
||||
📝 提醒:tasks.md 有未 commit 的變動
|
||||
$(echo "$TASKS_DIFF")
|
||||
記得在結束前 commit。
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,79 @@
|
||||
# SDD 協議(每次啟動必讀)
|
||||
|
||||
## 第零原則:沒讀 SDD 不准動 code
|
||||
|
||||
任何 `.go` / `.ts` / `.tsx` / `.wasm` 相關變動,**必須**按以下順序執行。**不得簡化,不得跳過**。
|
||||
|
||||
### 步驟 1:讀總進度
|
||||
|
||||
先讀 `.agents/specs/arcrun/arcrun.md`,了解當前 Phase。
|
||||
|
||||
### 步驟 2:定位對應 SDD
|
||||
|
||||
根據任務性質找對應 SDD:
|
||||
|
||||
| 任務類型 | 對應 SDD |
|
||||
|---------|---------|
|
||||
| Auth primitive WASM 零件(static_key/oauth2/service_account/mtls) | `.agents/specs/arcrun/credential-primitives-wasm/` |
|
||||
| 清除 cypher-executor 裡的 TS 業務邏輯 | `.agents/specs/arcrun/credential-primitives-wasm/` |
|
||||
| WASI shim host functions(kv_get / crypto_decrypt / crypto_sign_rs256) | `.agents/specs/arcrun/credential-primitives-wasm/` |
|
||||
| Auth Recipe 系統(recipe schema、KV 格式) | `.agents/specs/arcrun/auth-recipe.md` |
|
||||
| Landing Page | `.agents/specs/arcrun/landing-page.md` |
|
||||
| CLI / SDK(Python/JS) | `.agents/specs/arcrun/sdk-and-website/` |
|
||||
| arcrun-core-mvp 整體架構 | `.agents/specs/arcrun-core-mvp/` |
|
||||
| Platform Evolution | `.agents/specs/arcrun-platform-evolution/` |
|
||||
| Credential 長期規格(需求源) | `docs/user_requirements/credential_parts.md` |
|
||||
|
||||
讀 `design.md` 和 `tasks.md` 兩份。
|
||||
|
||||
### 步驟 3:宣告(強制格式)
|
||||
|
||||
開始動手前,在回覆開頭**逐字**貼出以下宣告:
|
||||
|
||||
```
|
||||
📋 已讀 SDD:
|
||||
- .agents/specs/arcrun/arcrun.md(當前 Phase:<phase 名稱>)
|
||||
- <對應 SDD 的 design.md 路徑>
|
||||
- <對應 SDD 的 tasks.md 路徑>
|
||||
|
||||
🎯 本次對應 task:<task 編號,例如 "Phase 1.3 實作 auth_static_key main.go">
|
||||
|
||||
📐 本次 task 的 SDD 規範摘要:
|
||||
- <重點 1>
|
||||
- <重點 2>
|
||||
- <重點 3>
|
||||
|
||||
🚧 執行範圍:
|
||||
- 會修改:<檔案清單>
|
||||
- 會建立:<檔案清單>
|
||||
- 會刪除:<檔案清單>
|
||||
```
|
||||
|
||||
**不做這個宣告 = 違反 SDD 協議 = 停手等 richblack**。
|
||||
|
||||
### 步驟 4:check tasks.md 狀態
|
||||
|
||||
動手前:在 tasks.md 把對應 task 的 `- [ ]` 改成 `- [🔄]`(進行中標記)。
|
||||
完成後:改成 `- [x]`,不批次更新,每完成一個就立刻改。
|
||||
|
||||
## 什麼算「任務超出 SDD 範圍」?
|
||||
|
||||
以下情況屬於 **change**,不是 **modify**,**必須停手並與 richblack 確認**:
|
||||
|
||||
- SDD 沒寫到的新功能
|
||||
- 新增頂層目錄
|
||||
- 新增新的 Worker(不管是 cypher-executor / registry / 零件 worker)
|
||||
- 修改架構決策(例如「改用 xxx 取代 yyy」)
|
||||
- 跨多個子系統的連鎖修改
|
||||
|
||||
**停手不是怯懦,是專業**。猜錯方向比慢一小時更糟。
|
||||
|
||||
## 發現 SDD 本身有問題怎麼辦?
|
||||
|
||||
- SDD 和實作不一致 → 停手,列出矛盾點,與 richblack 確認哪一邊是對的
|
||||
- SDD 規範之間互相矛盾(例如禁令 A 和設計 B 衝突)→ 停手,引用矛盾原文,與 richblack 確認
|
||||
- **不可以自行猜哪個是對的**。CC 之前兩天就是這樣走錯的。
|
||||
|
||||
## 為什麼這個協議存在
|
||||
|
||||
arcrun 規範已經足夠細緻,CC 之前出錯不是因為不懂,而是因為**沒讀**或**讀了覺得「大概是這個意思」就動手**。SDD 協議強制把「先讀 → 定位 → 宣告 → 執行 → 更新」做成一條死規矩,沒有繞過去的路徑。
|
||||
@@ -0,0 +1,76 @@
|
||||
# 技術棧硬限制
|
||||
|
||||
## 三層語言對應(絕對不可混用)
|
||||
|
||||
| 層級 | 語言 | 位置 | 職責 |
|
||||
|-----|------|------|------|
|
||||
| 零件(Component) | **TinyGo 或 AssemblyScript → WASM** | `registry/components/{name}/` | 所有業務邏輯 |
|
||||
| 零件 Worker 包裝 | TypeScript(固定模板,不寫業務邏輯) | `.component-builds/{name}/` | WASI shim,stdin/stdout JSON |
|
||||
| Orchestration Worker | TypeScript + Hono | `cypher-executor/` | HTTP routing、workflow 執行排程、host functions |
|
||||
| CLI | TypeScript + Node.js | `cli/` | `acr` 指令 |
|
||||
| Python SDK | Python | `python-sdk/` | HTTP thin wrapper + client 端加密 |
|
||||
| JS SDK | TypeScript + Web Crypto | `js-sdk/` | HTTP thin wrapper + client 端加密 |
|
||||
| Frontend | React 19 + Vite + Tailwind v4 | `landing/` | Cloudflare Pages |
|
||||
|
||||
## 零件實作規範
|
||||
|
||||
### 只有兩種合法語言
|
||||
- **TinyGo**:`tinygo build -target=wasi -o {name}.wasm main.go`
|
||||
- **AssemblyScript**:`asc main.ts --target release -o {name}.wasm`
|
||||
|
||||
### I/O 模型
|
||||
- **stdin**:JSON input
|
||||
- **stdout**:JSON output
|
||||
- 不用 HTTP server,不監聽 socket(WASI preview1 沒 socket)
|
||||
|
||||
### Host Functions(零件呼叫外部能力的唯一管道)
|
||||
在 `u6u` namespace 下:
|
||||
|
||||
| Host Function | 用途 |
|
||||
|---|---|
|
||||
| `u6u.http_request` | 發 HTTP 請求 |
|
||||
| `u6u.kv_get` | 讀 Cloudflare KV(Worker 側依 key 前綴路由到正確 KV) |
|
||||
| `u6u.crypto_decrypt` | AES-GCM 解密(encryption key 永不暴露給 WASM) |
|
||||
| `u6u.crypto_sign_rs256` | RSA-SHA256 簽章(PKCS8 bytes 傳入) |
|
||||
|
||||
**所有 host function 在 `cypher-executor/src/lib/wasi-shim.ts` 實作**。零件透過 WASI import 使用。
|
||||
|
||||
## 資料儲存
|
||||
|
||||
| 儲存 | 用途 | Key 格式 |
|
||||
|-----|------|---------|
|
||||
| Cloudflare KV `WEBHOOKS` | workflow 定義(cypher binding YAML) | `webhook:{api_key}:{name}` |
|
||||
| Cloudflare KV `CREDENTIALS_KV` | 加密 credential | `{api_key}:cred:{name}` |
|
||||
| Cloudflare KV `RECIPES` | auth recipe / 動態 API recipe | `auth_recipe:{service}`, `rec_{hash}` |
|
||||
| Cloudflare KV `USERS_KV` | 用戶資料 | `user:{api_key}` |
|
||||
| Cloudflare KV `SESSIONS_KV` | session | `session:{token}` |
|
||||
| Cloudflare KV `ANALYTICS_KV` | 執行分析 | `execution:{timestamp}:{id}` |
|
||||
| Cloudflare KV `EXEC_CONTEXT` | workflow 執行中的 context | `ctx:{execution_id}:{node_id}` |
|
||||
| Cloudflare R2 `WASM_BUCKET` | **只用於用戶自製零件**(Phase 5 以後啟用) | `{api_key}:cmp:{hash}` |
|
||||
|
||||
**警告:R2 不存平台內建零件的 WASM**。平台零件已 bundle 進各自的 Worker binary(`[[wasm_modules]]` 或 `import ... assert { type: 'webassembly' }`)。
|
||||
|
||||
## 加解密規範
|
||||
|
||||
- **演算法**:AES-GCM 256-bit
|
||||
- **加密位置**:Client 端(CLI / Python SDK / JS SDK)
|
||||
- Python:`cryptography` 套件
|
||||
- JS:Web Crypto API(`crypto.subtle`)
|
||||
- **解密位置**:Server 端 **WASM primitive**(透過 host function `crypto_decrypt`)
|
||||
- cypher-executor TS **不解密**,只提供 host function
|
||||
- `ENCRYPTION_KEY` 只在 Worker host function 內部讀取,**永不經 stdin / 回傳值傳給 WASM**
|
||||
- **傳輸格式**:`{ name, encrypted, iv }`(iv base64、encrypted base64)
|
||||
|
||||
## 網路部署
|
||||
|
||||
- **平台 API(對外)**:`cypher.arcrun.dev`(cypher-executor)
|
||||
- **Landing**:`arcrun.dev`
|
||||
- **每個零件 Worker**:
|
||||
- **對內(cypher-executor 用來 fetch component,避開同 zone 死鎖)**:`arcrun-{kebab}.{WORKER_SUBDOMAIN}.workers.dev`
|
||||
- 例:`arcrun-kbdb-get.uncle6-me.workers.dev`
|
||||
- cypher-executor 從 `wrangler.toml [vars] WORKER_SUBDOMAIN` 組出此 URL
|
||||
- **對外(可選,零件對全網開放被 curl 用)**:`{kebab}.arcrun.dev`
|
||||
- 例:`gmail.arcrun.dev`、`kbdb-get.arcrun.dev`
|
||||
- 仍允許保留,但**禁止 cypher-executor 透過此 URL fetch**(會撞同 zone 自循環,見 [docs/incidents/2026-05-13-cypher-outbound-522.md](../../docs/incidents/2026-05-13-cypher-outbound-522.md))
|
||||
- **新增 component worker 部署清單**:`name = "arcrun-{kebab}"` + `[[routes]]` 對外(可選)+ dashboard 啟用 workers.dev(必須)
|
||||
- **部署工具**:Wrangler
|
||||
@@ -0,0 +1,132 @@
|
||||
# 禁止行為清單(零容忍)
|
||||
|
||||
**這份清單由 `.claude/hooks/*.sh` 強制執行。違反會 block 工具呼叫(exit 2)**。
|
||||
|
||||
---
|
||||
|
||||
## 第一類:零件實作層級的禁令
|
||||
|
||||
### 1.1 禁止在 `registry/components/` 下建立 TypeScript 檔案
|
||||
零件**只能**用 TinyGo(`.go`)或 AssemblyScript(`.ts` 但需 `asconfig.json`)實作,並編譯成 `.wasm`。
|
||||
cypher-executor/registry Worker 或 `.component-builds/` 內的 TS 不算零件邏輯,那是 WASI shim。
|
||||
|
||||
**Hook 會擋**:新增 `registry/components/*/{檔案}.ts`(除非目錄內有 `asconfig.json` 明確標記為 AssemblyScript)。
|
||||
|
||||
### 1.2 禁止建立新的 `auth_*` 目錄以外的 auth 實作
|
||||
所有 auth 邏輯只能在:
|
||||
- `registry/components/auth_static_key/`
|
||||
- `registry/components/auth_oauth2/`
|
||||
- `registry/components/auth_service_account/`
|
||||
- `registry/components/auth_mtls/`
|
||||
|
||||
**不可以**出現 `cypher-executor/src/auth-primitive/`、`cypher-executor/src/lib/auth-*.ts`、`auth-worker/`、`credential-worker/` 等目錄。
|
||||
|
||||
**Hook 會擋**:`mkdir` 或 `Write` 到上述違規路徑。
|
||||
|
||||
### 1.3 禁止用 `wrangler init/generate` 建立 auth/credential/jwt 相關的 TS Worker
|
||||
Auth primitive 必須透過 `component-worker-template/` 搭配 WASM binary 部署。
|
||||
|
||||
**Hook 會擋**:bash 指令含 `wrangler (init|generate) ... auth_`、`... credential_`、`... jwt_` 的 pattern。
|
||||
|
||||
---
|
||||
|
||||
## 第二類:cypher-executor TS 的禁令
|
||||
|
||||
### 2.1 禁止新增任何 credential / auth / jwt 相關的 TS 檔案
|
||||
**已存在但要刪**(Phase 1-3 範圍):
|
||||
- `cypher-executor/src/actions/credential-injector.ts` → 刪除(走 WASM auth primitive)
|
||||
- `cypher-executor/src/lib/jwt-signer.ts` → 刪除(RS256 移入 auth_service_account WASM)
|
||||
- `cypher-executor/src/lib/component-loader.ts` 的 `BUILTIN_API_RECIPES` 和 `BUILTIN_CREDENTIALS_MAP` → 整段刪除
|
||||
|
||||
**Hook 會擋**:新增任何路徑含以下關鍵字的 `.ts` 檔案:
|
||||
- `credential-injector`、`credential_injector`
|
||||
- `jwt-signer`、`jwt_signer`
|
||||
- `auth-dispatcher` 的 TS 若嘗試在裡面實作 credential 解密 / template 展開 / JWT signing,block
|
||||
|
||||
### 2.2 禁止在 cypher-executor 任何 TS 裡實作以下邏輯
|
||||
這些邏輯全部屬於 WASM 零件職責:
|
||||
|
||||
- AES-GCM 解密(`crypto.subtle.decrypt`)— 只准出現在 `wasi-shim.ts` 的 `crypto_decrypt` host function
|
||||
- RSA-SHA256 簽章(`crypto.subtle.sign` with RSASSA-PKCS1-v1_5)— 只准出現在 `wasi-shim.ts` 的 `crypto_sign_rs256` host function
|
||||
- Template 展開(`{{secret.X}}` / `{{runtime.X}}` 替換)— 只能在 WASM 零件內
|
||||
- PEM → PKCS8 解析
|
||||
- JWT header/payload/signature 組裝
|
||||
- Token exchange(拿 service account JWT 換 access_token)
|
||||
- 具體 API call 實作(例如 gmail send / telegram sendMessage / google sheets append)
|
||||
|
||||
**Hook 會擋**:
|
||||
- Write/Edit 到 `cypher-executor/src/` 下的 `.ts` 時,內容含:
|
||||
- `crypto\.subtle\.decrypt` 且檔名不是 `wasi-shim.ts`
|
||||
- `crypto\.subtle\.sign.*RSASSA` 且檔名不是 `wasi-shim.ts`
|
||||
- `interpolateTemplate`、`\{\{secret\.` 的模板邏輯
|
||||
- `BUILTIN_API_RECIPES`、`BUILTIN_CREDENTIALS_MAP`(新增用)
|
||||
- `gmail.googleapis.com/gmail/v1/users/me/messages/send` 類 hard-code API URL
|
||||
- `api.telegram.org/bot.*sendMessage`
|
||||
- `sheets.googleapis.com/v4/spreadsheets`
|
||||
- `notify-api.line.me/api/notify`
|
||||
|
||||
### 2.3 cypher-executor TS 的合法職責(允許)
|
||||
- HTTP routing(Hono routes)
|
||||
- workflow 執行排程(`graph-executor.ts`)
|
||||
- 呼叫 WASM 零件(透過 HTTP fetch 到對應 Worker URL,或 Service Binding fallback)
|
||||
- 提供 host function(`wasi-shim.ts` 的 `kv_get` / `crypto_decrypt` / `crypto_sign_rs256`)
|
||||
- KV/R2/Service Binding 存取封裝
|
||||
|
||||
---
|
||||
|
||||
## 第三類:架構層級的禁令
|
||||
|
||||
### 3.1 禁止新增 Service Binding
|
||||
**Cypher binding 不是 Cloudflare service binding**。它是 YAML/KV 裡的 URL 清單。
|
||||
|
||||
零件串接(workflow 層)一律走 HTTP URL,不走 `[[services]]`。
|
||||
|
||||
15 個現有的 `SVC_*` 綁定(`cypher-executor/wrangler.toml`)是歷史遺產(邏輯零件效能優化),**保留但不新增**。
|
||||
|
||||
**Hook 會擋**:bash 指令含 `wrangler tail` 以外、涉及 `[[services]]` 新增的 pattern;Edit wrangler.toml 新增 `[[services]]` 區塊時警告確認。
|
||||
|
||||
### 3.2 禁止以「從 R2 取 WASM」為設計
|
||||
平台內建零件已 bundle 進各自 Worker,不從 R2 取。
|
||||
R2 只在 Phase 5(用戶自製零件)啟用。
|
||||
|
||||
**Hook 會警告**:TS 中出現 `env.WASM_BUCKET.get(` 的新增 code(除非在明確標註的 Phase 5 user-submit 路徑中)。
|
||||
|
||||
### 3.3 禁止複製貼上 Worker 程式碼到新目錄
|
||||
要改 `gmail` 零件 → 改 `registry/components/gmail/main.go`,重新編譯、部署。
|
||||
**不准**新建 `gmail-v2/`、`new-gmail/`、`gmail-worker/` 等目錄。
|
||||
|
||||
**Hook 會擋**:`mkdir` 或 `Write` 到 `{component-name}-v2/`、`new-{component-name}/`、`{component-name}-worker/` 類路徑。
|
||||
|
||||
### 3.4 禁止在 SDK 內做 server 職責
|
||||
- **禁止**:SDK 裡做 server 端解密、credential-injector 重實作、workflow executor、auth recipe 解析
|
||||
- **允許**:SDK 做 HTTP thin wrapper + client 端加密(AES-GCM)
|
||||
|
||||
---
|
||||
|
||||
## 第四類:流程層級的禁令
|
||||
|
||||
### 4.1 禁止沒讀 SDD 就動 code
|
||||
見 `00-sdd-protocol.md`。
|
||||
|
||||
### 4.2 禁止批次更新 tasks.md
|
||||
每完成一個 task 就立刻 mark `- [x]`。不准「先全部做完再一次更新」。
|
||||
|
||||
### 4.3 禁止新建 SDD 而不事先與 richblack 確認
|
||||
SDD 屬於架構決策,必須人確認。CC 不可以自行在 `.agents/specs/` 底下建新目錄。
|
||||
例外:在現有 SDD 目錄內新增 `requirements.md` / `design.md` / `tasks.md` 的單檔補充(需在 CLAUDE.md 已註記的 SDD 範圍內)。
|
||||
|
||||
---
|
||||
|
||||
## Hook Block 訊息格式
|
||||
|
||||
當 hook 擋住一個操作時,訊息格式統一為:
|
||||
|
||||
```
|
||||
❌ BLOCKED by arcrun CLAUDE rules
|
||||
違反項:<禁令編號,例如 2.2>
|
||||
原因:<簡短說明>
|
||||
正確做法:<該改去哪裡、該用什麼方式>
|
||||
參考:.claude/rules/<對應檔案>
|
||||
```
|
||||
|
||||
這樣 CC 拿到錯誤訊息後有機會自行導正,不是被擋死就愣住。
|
||||
@@ -0,0 +1,161 @@
|
||||
# 零件架構與部署模式(必讀,CC 最常搞錯的地方)
|
||||
|
||||
## 第一核心概念:每個 WASM 零件 = 一個獨立 Worker = **兩個** URL
|
||||
|
||||
**不是**從 R2 即時載入 WASM 執行。
|
||||
**不是**用 service binding 串零件。
|
||||
**不是**一個 Worker 裡跑多個零件。
|
||||
|
||||
**是**:每個零件都是獨立部署的 Worker,每個都有**兩個 URL**:
|
||||
|
||||
| URL 類型 | Pattern | 用途 |
|
||||
|---|---|---|
|
||||
| 對內(cypher-executor 用)| `arcrun-{kebab}.{WORKER_SUBDOMAIN}.workers.dev` | cypher-executor fetch component 走這個,避開同 zone 自循環死鎖(P0 #9)|
|
||||
| 對外(直接 curl 用,可選)| `{kebab}.arcrun.dev` | 用戶單獨打 component 測試或 self-hosted 用法 |
|
||||
|
||||
例:`kbdb_get` 零件:
|
||||
- 對內:`arcrun-kbdb-get.uncle6-me.workers.dev`(cypher-executor 走這個)
|
||||
- 對外:`kbdb-get.arcrun.dev`(用戶 / 直 curl)
|
||||
|
||||
**為什麼這樣設計**:CF Workers 「同 zone 自循環防護」會讓綁 `cypher.arcrun.dev/*` 的 cypher-executor fetch 同 zone `*.arcrun.dev` 撞 522。完整事件報告:[docs/incidents/2026-05-13-cypher-outbound-522.md](../../docs/incidents/2026-05-13-cypher-outbound-522.md)。改走 workers.dev 子域繞過。
|
||||
|
||||
### 零件 Worker 的結構
|
||||
|
||||
```
|
||||
registry/components/{name}/
|
||||
├── main.go ← TinyGo 原始碼(實際零件邏輯)
|
||||
├── component.contract.yaml ← 輸入/輸出規格
|
||||
└── {name}.wasm ← TinyGo 編譯產物
|
||||
```
|
||||
|
||||
部署時,透過 `component-worker-template/` 把 WASM 包進一個 Hono Worker:
|
||||
```
|
||||
.component-builds/{name}/
|
||||
├── package.json
|
||||
├── wrangler.toml ← name = "arcrun-{name}",route = "{name}.arcrun.dev"
|
||||
├── component.wasm ← 從 registry/components/{name}/ 複製過來
|
||||
└── src/index.ts ← 固定的 WASI shim(POST / → stdin → WASM → stdout → JSON)
|
||||
```
|
||||
|
||||
**src/index.ts 是通用模板**,所有零件都用同一份。這個 TS 只做 WASI runtime,不是業務邏輯。
|
||||
|
||||
---
|
||||
|
||||
## R2(WASM_BUCKET)的真正用途
|
||||
|
||||
R2 存 WASM 只是**用戶自製零件上傳**用的。
|
||||
|
||||
**平台內建零件不從 R2 讀取**——它們在部署時就已 bundle 進 Worker 的 binary(透過 `[[wasm_modules]]` 或 `import` with `assert { type: 'webassembly' }`)。
|
||||
|
||||
Phase 5(封測後)才會啟用「用戶 push 自製零件 → 存 R2 → 動態執行」這條路徑。
|
||||
|
||||
**結論:當 CC 問「怎麼從 R2 取出 WASM」時,幾乎都是走錯路徑**。平台零件是獨立 Worker,走 HTTP 呼叫,不是 R2 動態載入。
|
||||
|
||||
---
|
||||
|
||||
## Cypher binding 的正確定義
|
||||
|
||||
**Cypher binding 不是 Cloudflare 的任何 binding 機制。**
|
||||
|
||||
Cypher binding 是一張 YAML 清單,內容是「一個 workflow 要呼叫哪些零件 URL」。存放在:
|
||||
- 本地:`workflow.yaml`(用戶寫的 workflow)
|
||||
- KV:`WEBHOOKS` KV(用戶 `acr push` 後存入)
|
||||
|
||||
Cypher executor 執行 workflow 時:
|
||||
1. 從 KV 讀出 workflow YAML
|
||||
2. 按 graph 順序解析每個節點的 `component`
|
||||
3. 用 HTTP fetch 打對應的零件 URL
|
||||
4. 把 output 當作下個節點的 input
|
||||
|
||||
**這就是 Cypher binding——用 HTTP URL 把零件串起來,存在 YAML/KV 裡**。
|
||||
|
||||
### 為什麼不能用 Service Binding?
|
||||
|
||||
Service binding 需要 `wrangler.toml` 裡寫死 `[[services]]`,且要 redeploy 才生效。arcrun 是類 n8n 服務,用戶建立新 workflow 時**絕對不可能**要他 redeploy。所以 workflow 層一定要 HTTP。
|
||||
|
||||
### Service Binding 的僅存合法用途
|
||||
|
||||
只在 `cypher-executor` 和**平台內建邏輯零件之間**保留(效能優化,避免公網往返)。看 `cypher-executor/wrangler.toml` 裡的 15 個 `[[services]]` 綁定就是這個用途。
|
||||
|
||||
**禁止新增任何 Service Binding**。所有新零件(特別是 auth primitive)都走 HTTP URL 路徑。
|
||||
|
||||
---
|
||||
|
||||
## 零件之間怎麼串:實際流程
|
||||
|
||||
假設 workflow 是:webhook → gmail(要 auth)→ google_sheets(要 auth)
|
||||
|
||||
```
|
||||
用戶 POST https://cypher.arcrun.dev/webhooks/named/xxx/trigger
|
||||
│
|
||||
▼
|
||||
cypher-executor(Worker)讀 workflow YAML
|
||||
│
|
||||
├─ 節點 1: component = gmail
|
||||
│ a. 查 auth_recipe:gmail → primitive = static_key
|
||||
│ b. HTTP POST https://auth-static-key.arcrun.dev
|
||||
│ { action: "authenticate", api_key, service: "gmail" }
|
||||
│ → 回傳 { auth_headers: { Authorization: "Bearer ..." } }
|
||||
│ c. HTTP POST https://gmail.arcrun.dev
|
||||
│ { to, subject, body, _auth_headers }
|
||||
│ → gmail 零件 Worker 執行 WASM → 回傳 { success, data }
|
||||
│
|
||||
└─ 節點 2: component = google_sheets
|
||||
... 相同模式
|
||||
```
|
||||
|
||||
**cypher-executor 本身不做 credential 解密、不做 JWT signing、不做 auth header 組裝**。這些全在 auth primitive WASM 零件內,cypher-executor 只負責 HTTP routing 和工作流排程。
|
||||
|
||||
---
|
||||
|
||||
## 實際禁令(CC 看這裡)
|
||||
|
||||
### 禁止在 `registry/components/` 下建立 TypeScript 檔案
|
||||
零件邏輯一律 TinyGo 或 AssemblyScript,編譯成 `.wasm`。
|
||||
|
||||
### 禁止把 auth 邏輯寫在 `cypher-executor/src/` 裡
|
||||
credential 解密、JWT signing、template 展開(`{{secret.X}}`)全部屬於 auth primitive WASM 零件的職責。cypher-executor 只呼叫它們。
|
||||
|
||||
### 禁止問「怎麼從 R2 取 WASM」
|
||||
平台內建零件**不從 R2 取**。每個零件已部署成獨立 Worker,走 HTTP URL。用戶自製零件才用 R2(Phase 5,未啟用)。
|
||||
|
||||
### 禁止新增 Service Binding
|
||||
15 個現有的 SVC_* 是歷史遺產(邏輯零件效能優化),不新增。新零件(尤其 auth primitive)一律走 HTTP URL。
|
||||
|
||||
### 禁止重建已存在的零件 Worker
|
||||
要改 `gmail` 零件邏輯 → 改 `registry/components/gmail/main.go`,重新編譯 `.wasm`,重新部署對應 Worker。**不要**在 `cypher-executor/src/lib/` 或其他地方建「新的 gmail 實作」。
|
||||
|
||||
---
|
||||
|
||||
## 部署一個新零件的完整步驟(auth_static_key 為例)
|
||||
|
||||
1. 建立 `registry/components/auth_static_key/`:
|
||||
- `main.go`(TinyGo 實作)
|
||||
- `component.contract.yaml`(IO 規格)
|
||||
2. 編譯:`cd registry/components/auth_static_key && tinygo build -target=wasi -o auth_static_key.wasm main.go`
|
||||
3. 建立 `.component-builds/auth_static_key/`:
|
||||
- 複製 `component-worker-template/src/index.ts`
|
||||
- 複製 `component-worker-template/package.json`
|
||||
- 新建 `wrangler.toml`:
|
||||
```toml
|
||||
name = "arcrun-auth-static-key"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2025-02-19"
|
||||
[vars]
|
||||
COMPONENT_ID = "auth_static_key"
|
||||
[[routes]]
|
||||
pattern = "auth-static-key.arcrun.dev/*"
|
||||
zone_name = "arcrun.dev"
|
||||
```
|
||||
- 複製 `auth_static_key.wasm` 到此目錄為 `component.wasm`
|
||||
4. `cd .component-builds/auth_static_key && pnpm install && pnpm deploy`
|
||||
5. **Dashboard 啟用 workers.dev URL**(必須,否則 cypher-executor fetch 不到):
|
||||
- Workers & Pages → `arcrun-auth-static-key` → Settings → Domains & Routes → workers.dev → Enable
|
||||
- 啟用後 URL:`arcrun-auth-static-key.{WORKER_SUBDOMAIN}.workers.dev`
|
||||
6. 驗證對外:`curl https://auth-static-key.arcrun.dev` → 應回 `{ok: true, component: "auth_static_key"}`
|
||||
7. 驗證對內:`curl https://arcrun-auth-static-key.{WORKER_SUBDOMAIN}.workers.dev` → 應同樣回 200
|
||||
8. cypher-executor 透過 `wasmWorkerUrl()` 自動組對內 URL 呼叫(不用手動註冊)
|
||||
|
||||
**這是唯一正確的部署流程**。任何偏離這個流程的「替代方案」都要先和 richblack 確認。
|
||||
|
||||
**Step 5 為什麼必須**:見 arcrun.md P0 #9(2026-05-13)。cypher-executor 走對內 URL 避開同 zone 自循環死鎖;若 workers.dev 未啟用,cypher-executor fetch 該 component 會 404。
|
||||
@@ -0,0 +1,77 @@
|
||||
# 當前進度(SessionStart 會注入此檔重點)
|
||||
|
||||
> 更新時間:2026-04-19
|
||||
> 權威來源:`.agents/specs/arcrun/credential-primitives-wasm/tasks.md`
|
||||
> 此檔僅摘要,詳細狀態以 tasks.md 為準。
|
||||
|
||||
---
|
||||
|
||||
## 封測狀態
|
||||
|
||||
**原定明天封測,richblack 決定推遲**,原因:cypher-executor 有三套 TS 業務邏輯違反「零件一律 WASM」架構原則(Phase 1-3 要清除的程式碼),在清除前不封測。
|
||||
|
||||
---
|
||||
|
||||
## 目前 Phase:Credential Primitives TS → WASM
|
||||
|
||||
**SDD 位置**:`.agents/specs/arcrun/credential-primitives-wasm/design.md` + `tasks.md`
|
||||
|
||||
### 已完成
|
||||
|
||||
- **Phase 0.1–0.5**:核心合併(u6u-core 併入 arcrun、21 個零件 contract 完整、刪除重複 `credentials/` 目錄、CREDENTIALS_KV binding 確認、刪除 `matrix/u6u-core/`)
|
||||
- `registry/components/` 下 21 個零件(邏輯 + API)都有 `main.go` + `.wasm`
|
||||
|
||||
### 進行中 / 未完成
|
||||
|
||||
| Task | 狀態 | 阻擋關係 |
|
||||
|-----|------|---------|
|
||||
| 0.6 wasi-shim 新增 `kv_get` / `crypto_decrypt` / `crypto_sign_rs256` host functions | ⬜ 未開始 | **Phase 1-3 的硬前置** |
|
||||
| 0.7 component-loader 新增 WASM runner 路徑 | ⬜ 未開始 | **Phase 1-3 的硬前置** |
|
||||
| 1.1-1.8 `auth_static_key` WASM 零件(TinyGo) | ⬜ 未開始 | 涵蓋 80% 服務 |
|
||||
| 2.1-2.6 `auth_service_account` WASM 零件(JWT signing) | ⬜ 未開始 | Google Service Account 等 |
|
||||
| 3.1-3.5 清除 `component-loader.ts` 的 `BUILTIN_API_RECIPES` | ⬜ 未開始 | 要先有 Phase 1-2 的 WASM 零件 |
|
||||
| 4.1-4.4 `auth_oauth2` + `auth_mtls`(封測後) | ⬜ 未開始 | 非阻擋項 |
|
||||
| 5.1-5.7 核心穩定驗證(全域搜尋確認無殘餘 TS) | ⬜ 未開始 | 封測啟動門檻 |
|
||||
|
||||
### Phase 1-3 要**徹底刪除**的 TS 檔案(不是搬、不是改,是刪)
|
||||
|
||||
| 檔案 | 違反什麼 |
|
||||
|-----|---------|
|
||||
| `cypher-executor/src/actions/credential-injector.ts` | AES 解密、template 展開、JWT 邏輯 —— 應在 WASM |
|
||||
| `cypher-executor/src/lib/jwt-signer.ts` | RS256 JWT 簽章邏輯 —— 應在 `auth_service_account.wasm` |
|
||||
| `cypher-executor/src/lib/component-loader.ts` 的 `BUILTIN_API_RECIPES`(~100 行) | gmail/telegram/line/gsheets/http_request/cron 的 TS 實作 —— 應全部走對應 WASM 零件 |
|
||||
|
||||
---
|
||||
|
||||
## 下一個 session 第一件要做的事
|
||||
|
||||
**讀 `.agents/specs/arcrun/credential-primitives-wasm/tasks.md`**,然後決定從 Phase 0.6 還是 0.7 開始。
|
||||
|
||||
0.6(host functions)和 0.7(WASM runner)是並列的前置工作,哪個先都可以,但都要在 Phase 1 開始之前完成。
|
||||
|
||||
---
|
||||
|
||||
## SDD 索引
|
||||
|
||||
| 子系統 | SDD |
|
||||
|--------|-----|
|
||||
| **主要(正在動)** Credential Primitives WASM 改寫 | `.agents/specs/arcrun/credential-primitives-wasm/` |
|
||||
| **LI (LLM Interface)** — AI 操盤手使用體驗(2026-05-16 新建,mira dogfood 痛點轉化) | `.agents/specs/llm-interface/` |
|
||||
| arcrun 總進度 | `.agents/specs/arcrun/arcrun.md` |
|
||||
| Auth Recipe 系統(schema、預建 20 個服務) | `.agents/specs/arcrun/auth-recipe.md` |
|
||||
| Landing Page | `.agents/specs/arcrun/landing-page.md` |
|
||||
| SDK + Website | `.agents/specs/arcrun/sdk-and-website/design.md` |
|
||||
| arcrun MVP 整體 | `.agents/specs/arcrun-core-mvp/design.md` |
|
||||
| Credential 長期規格(需求源) | `docs/user_requirements/credential_parts.md` |
|
||||
| Platform Evolution | `.agents/specs/arcrun-platform-evolution/design.md` |
|
||||
| Tech Stack 詳細 | `.agents/steerings/tech.md` |
|
||||
|
||||
---
|
||||
|
||||
## 技術備註(CC 常搞錯的點)
|
||||
|
||||
1. **每個 WASM 零件 = 獨立 Worker = 公開 URL**(例:`gmail.arcrun.dev`)。不是從 R2 動態讀。
|
||||
2. **Cypher binding = YAML 裡寫 URL 清單**。不是 Cloudflare service binding。
|
||||
3. **cypher-executor 只做 routing + host functions**。業務邏輯全在 WASM 零件。
|
||||
4. **TinyGo 有限制**:`crypto/rsa` 支援不全 → 用 host function `crypto_sign_rs256` 讓 Worker 代簽。
|
||||
5. 詳見 `.claude/rules/03-component-architecture.md`。
|
||||
@@ -0,0 +1,138 @@
|
||||
# 部署慣例(CI/CD)
|
||||
|
||||
> **核心原則:新增 Worker = 新目錄 + `wrangler.toml`,不用改 workflow。**
|
||||
|
||||
`.github/workflows/deploy.yml` 是**通用掃描式** workflow,不該為每個 Worker 手寫 job。
|
||||
|
||||
---
|
||||
|
||||
## Workflow 如何找到要部署的 Worker?
|
||||
|
||||
```
|
||||
find . -name 'wrangler.toml' -not -path '*/node_modules/*' -not -name 'wrangler.test.toml'
|
||||
```
|
||||
|
||||
每一個命中的目錄 = 一個部署單位。無論是:
|
||||
|
||||
- `cypher-executor/` (orchestration Worker)
|
||||
- `registry/` (合約管理 Worker)
|
||||
- `.component-builds/{name}/` (零件 Worker,25+ 個)
|
||||
- 未來新增的任何 Worker
|
||||
|
||||
**無需改 workflow,只要符合掃描規則就會自動部署**。
|
||||
|
||||
---
|
||||
|
||||
## 觸發邏輯
|
||||
|
||||
| 觸發 | 部署範圍 |
|
||||
|------|---------|
|
||||
| `push` 到 main | diff 涉及的 Worker 目錄才部署 |
|
||||
| `push` 到 main + 改 `registry/components/{name}/` | 連動 rebuild `.component-builds/{name}/component.wasm` 再 deploy |
|
||||
| `workflow_dispatch` + `force_all=true` | 全部 Worker |
|
||||
| `workflow_dispatch` + `only=a,b,c` | 只部署指定清單 |
|
||||
| `push` 但 base sha 不可及(首次) | 全部 Worker |
|
||||
|
||||
---
|
||||
|
||||
## 新增 Worker 的步驟
|
||||
|
||||
### 如果是新 WASM 零件 Worker
|
||||
|
||||
1. 在 `registry/components/{new_name}/` 建 `main.go` + `component.contract.yaml`
|
||||
2. 在 `.component-builds/{new_name}/` 建 Worker 模板:
|
||||
- `wrangler.toml`(name/routes/bindings)
|
||||
- `package.json`(hono + workers-types + wrangler 即可,參考 `auth_static_key/package.json`)
|
||||
- `tsconfig.json`(可直接複製)
|
||||
- `src/index.ts`(WASI shim,方案 A:import `../../cypher-executor/src/lib/wasi-shim`)
|
||||
3. 本地跑 `pnpm install` 產 `pnpm-lock.yaml`
|
||||
4. 本地跑 `tinygo build -target=wasi -o {new_name}.wasm main.go` 先驗證 build 通過
|
||||
5. Commit push → CI 自動 rebuild WASM + deploy
|
||||
|
||||
### 如果是新 orchestration/service Worker
|
||||
|
||||
1. 在 repo 根建新目錄(類似 `cypher-executor/`)
|
||||
2. `wrangler.toml` + `package.json` + `pnpm-lock.yaml` + `src/index.ts` + `tsconfig.json`
|
||||
3. Push → CI 自動部署
|
||||
|
||||
---
|
||||
|
||||
## Runtime Secret 管理
|
||||
|
||||
**CI 只提供 Cloudflare 驗證,不碰 runtime secret**。
|
||||
|
||||
- GH Actions secrets:`CLOUDFLARE_API_TOKEN`、`CLOUDFLARE_ACCOUNT_ID`(一次性設好)
|
||||
- Runtime secret(例:`ENCRYPTION_KEY`、`OPENAI_KEY`、`GOOGLE_API_KEY`):
|
||||
- **由 richblack 一次性手動** `wrangler secret put <KEY>` 設進各 Worker
|
||||
- 不進 CI,不進 `wrangler.toml` `[vars]`
|
||||
- 需要的 Worker:`auth_static_key`、`auth_service_account`(兩個都要 `ENCRYPTION_KEY`)
|
||||
|
||||
---
|
||||
|
||||
## Lockfile 規範
|
||||
|
||||
- **統一使用 pnpm**。新增 Worker 只放 `pnpm-lock.yaml`,不要 `package-lock.json`
|
||||
- 若新建 Worker 時用 `npm install` 產出 `package-lock.json`,**刪掉它**,改跑 `pnpm install`
|
||||
- `cypher-executor/` 和 `registry/` 的 `package-lock.json` 已於 2026-04-20 刪除
|
||||
|
||||
**現存例外**(歷史遺產,混合期不強制遷移):
|
||||
- `.component-builds/{if_control, switch, ... 16 個舊邏輯零件}/` 仍是 `package-lock.json`,workflow 有 fallback 分支(`pnpm install --no-frozen-lockfile`)可跑
|
||||
- `builtins/`、`landing/` 同上
|
||||
|
||||
**新增 Worker 一律 pnpm,不要製造新的混合情況**。
|
||||
|
||||
---
|
||||
|
||||
## WASM 來源
|
||||
|
||||
> **⚠️ 慣例變更(richblack 2026-06-02,self-hosted 開源策略)**:
|
||||
> 原慣例「`.component-builds/{name}/component.wasm` 不 commit 進 repo」**已推翻**。
|
||||
> 現在 **commit `.component-builds/*/component.wasm` 進 repo**,因為 self-host 用戶 / `acr init --self-hosted`
|
||||
> 從 GitHub(codeload tarball)直接拿這份 wasm 部署到自己的 CF——repo 必須自帶可部署的 wasm。
|
||||
> 決策依據:`.agents/specs/arcrun/sdk-and-website/self-hosted-init.md §6`。
|
||||
|
||||
### 現行規則(2026-06-02 起)
|
||||
|
||||
- **`.component-builds/*/component.wasm` → commit 進 repo**(部署來源)。`.gitignore` 用否定規則放行:
|
||||
```
|
||||
*.wasm # 預設排除
|
||||
!.component-builds/**/component.wasm # 例外放行部署物
|
||||
```
|
||||
- **`registry/components/*.wasm` → 仍不 commit**(build 中間產物,部署不直接用,`.gitignore` 仍排除)。
|
||||
- 本地開發 build:`cd registry/components/{name} && tinygo build -target=wasi -o {name}.wasm main.go && cp {name}.wasm ../../../.component-builds/{name}/component.wasm`,**然後 commit `.component-builds/{name}/component.wasm`**。
|
||||
- CI(deploy.yml):仍在 deploy 前自動 rebuild + copy(部署 prod 用最新 source;與 repo 內 commit 的 wasm 不衝突——前者給 CI deploy prod,後者給 self-host 用戶當部署來源)。
|
||||
|
||||
### 誠實 trade-off(mindset §7)
|
||||
|
||||
commit wasm 進 repo → 每次 rebuild 在 git 歷史累積二進位,**repo 長期會膨脹**。
|
||||
可接受(self-host 體驗優先),未來若膨脹過劇再考慮 git-lfs / 按需安裝(self-hosted-init.md §6.6)。
|
||||
|
||||
---
|
||||
|
||||
## 並行度
|
||||
|
||||
`max-parallel: 5` — 避免觸發 Cloudflare Workers API rate limit。
|
||||
|
||||
Worker 數量 > 5 時,deploy 會分批跑。25 個 Worker 大約 5 輪 × ~30 秒 = 2-3 分鐘可完成全部。
|
||||
|
||||
---
|
||||
|
||||
## 禁止事項
|
||||
|
||||
1. **禁止**為新 Worker 手動加 deploy job 到 `deploy.yml`。通用掃描會自動處理,手加就是重複工作。
|
||||
2. **禁止**把 runtime secret(API key / encryption key / credential)放進 GH Actions secrets 或 `wrangler.toml` `[vars]`,只能用 `wrangler secret put`。
|
||||
3. **禁止**在 CI 裡跑不必要的測試阻擋 deploy。測試在 PR / 本地跑,`main` 推上去就 deploy(trunk-based)。若要測試關,開新 workflow 檔,不要污染 deploy workflow。
|
||||
4. **禁止**跳過 TinyGo rebuild 直接 deploy 舊 `.wasm`。CI 的 rebuild 步驟是確保部署的是最新 source。
|
||||
|
||||
---
|
||||
|
||||
## 驗證指令
|
||||
|
||||
本地模擬 CI 的掃描結果:
|
||||
|
||||
```bash
|
||||
find . -name 'wrangler.toml' -not -path '*/node_modules/*' -not -name 'wrangler.test.toml' \
|
||||
| xargs -n1 dirname | sort -u
|
||||
```
|
||||
|
||||
應列出 ~25 個目錄。任何「我新增了 Worker 但沒被 deploy」的問題,先跑這條確認目錄被掃到。
|
||||
@@ -0,0 +1,60 @@
|
||||
# arcrun mindset(給 CC 的世界觀 — 走歪前先讀這個)
|
||||
|
||||
> 這是「為什麼」層,不是禁令層(禁令在 02-forbidden)。
|
||||
> 違反禁令會被 hook 擋;違反 mindset 不會被擋,但會讓你做出「技術上對、方向上錯」的東西。
|
||||
> 來源:2026-05 richblack 與 CC 的一連串判準釐清(權威記錄在 DECISIONS.md)。
|
||||
>
|
||||
> 註:這是步驟 7「arcrun-mindset Skill」的前身。Skill 正式建立前,本檔是 CC 的 mindset 來源。
|
||||
|
||||
---
|
||||
|
||||
## 1. 工作流是 default,零件是稀有例外
|
||||
|
||||
AI 開發時的預設順序:
|
||||
1. **預設寫工作流**(串服務 / 自用 / 給少數人用 → 全部先工作流,用 http_request + 流程控制 primitive 串)。
|
||||
2. **要打的服務不提供串接但有 API,且有必要讓全 arcrun 生態重用** → 才建零件(零件 = API 薄殼,只打一個 endpoint)。
|
||||
3. **建零件前必問「你有必要嗎?」**:看到「有 API 可包成零件」≠「該包」。自用 → 工作流。
|
||||
|
||||
**CC 的典型走歪**:把「需要一個能力」直接翻成「做一個零件」,把「能包」當「該包」。
|
||||
mira 的 claude_api / km_writer 就是這樣被錯做成零件的(其實是自用服務膠水,該是工作流)。
|
||||
|
||||
## 2. Arcrun 是 AI 呼叫的工具(AI → 工具),不是工具回頭呼叫 AI
|
||||
|
||||
需要 AI 判斷 / 轉換時,是**操盤的 CC 自己做**,再呼叫工作流做確定性的下一步。
|
||||
**不要在工作流裡放零件回頭呼叫一個 LLM**。n8n 需要 AI 節點是因為它沒大腦;arcrun 的大腦就是 CC。
|
||||
(ai_transform_compile/run 因此被刪除。)
|
||||
|
||||
## 3. arcrun 不做授權判斷
|
||||
|
||||
「能不能打通」由發 API key 的服務裁決,不是 arcrun。401/403 是對方服務在行使授權,不是 arcrun 的 bug。
|
||||
auth_recipe 只定義「怎麼認證」,不含「誰准用」清單。不要加「arcrun 替用戶擋掉某些 endpoint」的功能。
|
||||
|
||||
## 4. 零件投稿走 GitHub PR(人 merge = 人類閘門)
|
||||
|
||||
零件投稿不是 registry self-service,是 GitHub PR。人 merge = 天然人類閘門(AI 偽造不了 GitHub approve),
|
||||
把關(假零件偵測 / 純WASI / Gherkin)由 CI PR check 跑(CI 能 runtime 跑 wasm,CF Worker 不能)。
|
||||
§8「不依賴 CI」指執行鏈路(高頻);零件投稿稀有,走 PR/CI 是例外、不違反。
|
||||
|
||||
## 5. 發佈安全的底氣是純 WASI 沙箱,不是 Gherkin
|
||||
|
||||
Gherkin 全綠 ≠ 零件安全(投稿者可寫避重就輕的 Gherkin)。真正框死破壞力的是**純 WASI 沙箱**
|
||||
(零件只能 stdin→stdout、無網路 syscall、無檔案系統)。Gherkin 驗契約 + 沙箱框死 + 市場補長尾 = 風險可控,非零風險。
|
||||
|
||||
## 6. 暴露 / 送資料的動作 → 人類明示同意(資料外流警示)
|
||||
|
||||
把資料 / workflow 變成「可被外部呼叫」(部署 webhook、recipe push)= 暴露面 → 需人類明示同意,不分公私庫。
|
||||
**不禁止**用戶公開(他的自由),但要**確定他自己明示同意**(不是 AI 替他決定)。
|
||||
警示同時是「保護措施入口」(提示可加 API Key / 權限 / 限流)。
|
||||
|
||||
## 7. 誠實限制(最重要的 mindset:不假裝、不假綠)
|
||||
|
||||
- **AI 技術上能偽造人類確認**(confirmed_by_human、exposure_consent、gherkin_evidence 都能塞)。
|
||||
這些機制的價值是**法律歸責 + 軌跡可審**,不是技術防偽。**絕不在文件 / 程式裡聲稱「不可能繞過」。**
|
||||
- **絕不代替人類做有風險的確認**(建零件、暴露資料)。非 TTY(你直跑)就拒絕,不要自己塞 flag 假裝人類同意了 —— 那是明確越界。
|
||||
- **禁假綠**(DECISIONS §3c/§7):stub / 未實作就回 success:false 或明確標 unimplemented,不要回傳假資料假裝成功。
|
||||
缺 credential 打不到 2xx 就誠實標「未驗收:缺 X」,不 mock 充綠燈。
|
||||
- **完成 = 客觀證據**(編譯 exit code / HTTP status + trace),不是口頭宣布「我做好了」。
|
||||
|
||||
---
|
||||
|
||||
詳細判準與來龍去脈見 `DECISIONS.md`。每條都有對應的慘痛教訓,不是憑空規定。
|
||||
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"hooks": {
|
||||
"SessionStart": [
|
||||
{
|
||||
"matcher": "startup|resume|clear",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash .claude/hooks/session-start-load-sdd.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PreToolUse": [
|
||||
{
|
||||
"matcher": "Write|Edit|MultiEdit",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash .claude/hooks/pre-write-guard.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": "Bash",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash .claude/hooks/pre-bash-guard.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"PostToolUse": [
|
||||
{
|
||||
"matcher": "Write|Edit|MultiEdit",
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash .claude/hooks/post-edit-remind-tasks.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"Stop": [
|
||||
{
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "bash .claude/hooks/stop-check-sync.sh",
|
||||
"timeout": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user