# arcrun

**讓 AI 用的工作流軟體（目前只支援 Claude Code）**

> 想先看用它做出來的產品？**[Arcrun RAG](https://github.com/youlinhsieh/arcrun-rag)** —— 企業知識庫（丟檔案自動長出可查詢、可問答的知識庫）。
>
> 目前**沒有公開試玩站**（早期那個共用示範站已於 2026-08-08 退場）。想直接看產出長什麼樣，
> 可以看示範知識庫的公開鏡像 [arcrun-rag-demo-knowledge](https://github.com/youlinhsieh/arcrun-rag-demo-knowledge)——純靜態、免登入。

AI 很會寫程式，就要除錯，過程浪費很多 Token 及時間，但絕大部分是重複內容，例如登入認證、存取資料庫等。

既然做的差不多，何不預先寫好？AI 只要把除錯完成的「零件」粘起來，只除錯粘膠程式部分，就省時、省錢。

這就是「工作流」軟體的概念，例如 n8n 等。

但現有工作流軟體是給人用的，對 AI 不友善。比如為了好看界面，程式碼又長又複雜，導致 AI 生成時容易出錯，甚至一個檔就灌爆 Context Window。

所以 Arcrun 是為了 AI Friendly 的目的開發。

因為 AI 很會寫 Code，它不「Low code」，但更適合你用，因為跟 AI 說，它就把後面的事做完了，比 Low code 更簡單。

為了 AI Friendly，arcrun 內含**給 AI（Claude Code）用的 harness**：你叫 AI 用 arcrun 開發時，它知道能用什麼、不能做什麼，做錯了有機制擋住——讓 CC 順暢、且不容易做歪。

---

> ## 🤖 給 AI 操盤手（Claude Code 等）
>
> 如果使用者把這個 repo / 網站丟給你、要你用 arcrun 做自動化——**你的第一步**：
>
> ```
> npm i -g arcrun && acr install-harness
> ```
>
> 這會把 arcrun 的防護（mindset Skill、CLAUDE.md 提醒、防做歪 hook、`/arcrun` 指令）裝進使用者**當前專案**，裝完你就有完整指引。
>
> **裝前先記住**：使用者選 arcrun = 不要自己寫 Python/Node 一次性腳本；打外部 API 寫 recipe；不自製零件；所有 CLI 操作你來做。完整啟動指南見 [`llms.txt`](llms.txt)。

---

## 為什麼做這個？

AI 愈來愈強，但跟 AI 協作做自動化還是很有摩擦：

**問題一：AI 調 API 太耗 token。**
每次讓 AI 幫你查資料、發信、寫試算表，它都要在對話裡描述、確認、執行，token 燒很快。更好的做法是讓 AI 把任務寫成一次性的工作流，之後直接執行。

**問題二：AI 從頭寫腳本容易出 bug。**
讓 AI 從零寫一整個自動化腳本，十次有八次要來回修。根本原因是邏輯沒被複用——每次都是全新的程式。

**問題三：第三方依賴是單點故障。**
每多依賴一個不可掌控的第三方（含 SaaS 平台本身），就多一個會掛掉、會漲價、會關服務的風險。

**解法：把邏輯寫成純文字工作流，跑在你自己的 Cloudflare 上。**
想到工作流你可能想到 n8n。方向一樣，但 arcrun 為 AI 優先設計、且**開源自架**：

| | n8n | arcrun |
|---|---|---|
| 語法 | JSON / 拖拉介面，動輒數千行 | 三行 Cypher，AI 和人都能直接讀 |
| context 消耗 | 大，容易超出 window | 極小，整個 workflow 幾十個 token |
| 擴充方式 | GUI 拖拉，人類操作 | 寫一段 recipe（純文字），AI 自己會寫 |
| 執行環境 | 需自架或付費訂閱 | 部署到**你自己的** Cloudflare，你說了算 |

核心假設：**最好的 AI 協作工具，應該讓 AI 自己能讀、能寫、能執行、能除錯——而且整套跑在你掌控的環境裡。**

---

## 核心概念：零件 vs recipe（最重要，先讀這個）

arcrun 只有兩種東西，分清楚就不會做歪：

### 零件（primitive）— 固定的一小套，由維護者管理，**你不自製**
- 是 WASM 程式，要部署，幾乎不變。**只有四類**：
  1. **流程控制**：`if_control` / `switch` / `filter` / `foreach_control` / `try_catch` / `wait`
  2. **資料處理**：`string_ops` / `number_ops` / `array_ops` / `date_ops` / `set` / `merge` / `validate_json`
  3. **`http_request`**：打任意 HTTP
  4. **credential（auth）**：`auth_static_key` / `auth_service_account` / `auth_oauth2` / `auth_mtls`（背後自動注入，你不直接擺）
- **零件不對外連特定服務。** 任何「打某個固定 API endpoint」的東西**都不是零件**——那是 recipe。
- 新增零件走 **GitHub PR**（人 merge 把關），不是 self-service。日常開發你**不會也不該**自製零件。

### recipe — 你（或 AI）能自由擴充的東西，純文字，不用部署
- recipe = `http_request` + 一組固定設定（endpoint / method / headers / body 模板）。
- 要打 Notion / Slack / 你自己的 API？**寫一個 recipe**，不是做一個零件。
- recipe 是純文字、不用 deploy、改一次零成本。AI 讀得懂 API 文件就能幫你組出 recipe。
- **recipe 是公共資產，發現缺的就做一個投稿。** `acr recipe push` = 投稿到公共庫（公開/私有只是屬性，不是兩條路）。沒有現成 recipe 打你要的 API？**自己寫一個 push 上去**——這是被鼓勵的，不必問人，下一個人也能用。

> **一句話判準**：要打一個固定的外部 endpoint → **recipe**。要做流程控制 / 資料處理 / 通用 HTTP → 用既有**零件**。其他大部分情況 → 直接寫**工作流**把它們串起來。

### 兩條容易誤解的紅線（AI 操盤手特別注意）

- **缺一個能力 → 補 API，不准用 recipe / 多步工作流拼裝。** 口訣：「這段邏輯換個介面（CLI→MCP）要不要重寫？要 → 它是『能力』，該長在 API。」例：缺 `upsert` 就去 API 加 `upsert` endpoint，**不要**在工作流裡拼「先查、沒有再建」、也不要寫 recipe 假裝補上。recipe 只負責「打一個固定外部 API」，不是用來補 arcrun 自己缺的能力。
- **已經有自製零件的，讓它退場。** `claude_api` 之類「工作流回頭叫 LLM」→ 刪掉，AI 判斷由操盤的 CC 自己做；`kbdb_*` 資料存取 → 改走 `acr kbdb` / `kbdb_*` MCP 工具；純打固定外部 API 的假零件 → 改寫成 recipe 投稿。

---

## 快速開始（Self-hosted）

arcrun 是 self-hosted 開源：你用**自己的** Cloudflare 帳號跑整套。一次裝好，之後就是你的，不依賴任何人的服務。

你總共只需要做 4 件事（步驟 1-4），其餘 CLI 自動完成、你只是看著機器跑。

### 1. 申請 Cloudflare 帳號（免費）

到 [dash.cloudflare.com/sign-up](https://dash.cloudflare.com/sign-up) 註冊。免費方案（Workers free tier）就足夠跑起來。

註冊後你需要兩個東西——**Account ID** 和 **API Token**：

**Account ID**：登入後在 [dash.cloudflare.com](https://dash.cloudflare.com) 隨便進一個區段，網址列會是 `dash.cloudflare.com/<這串就是 Account ID>`；或在右側欄 "Account ID" 直接複製。

**API Token**：到 [My Profile → API Tokens](https://dash.cloudflare.com/profile/api-tokens) → **Create Token** → **Create Custom Token**，給以下**兩個**權限（CLI 用它建 KV / 部署 Worker）：

| 類型 | 項目 | 權限 |
|---|---|---|
| Account | Workers Scripts | Edit |
| Account | Workers KV Storage | Edit |

建好後**複製那串 token**（只會顯示一次）。CLI 不代管你的憑證——你自己建、自己持有。

> 只需要這兩個權限。**不需要 R2、不需要綁信用卡**——arcrun self-hosted 只用 Workers + KV，兩者都在 Cloudflare 免費額度。

### 2. 安裝 Cloudflare CLI（wrangler）

CLI 部署 Worker 時會用到 wrangler。先裝它：

```bash
npm i -g wrangler
```

### 3. 安裝 arcrun CLI

```bash
npm i -g arcrun
```

### 4. 一鍵初始化（其餘全自動）

```bash
acr init --self-hosted
```

CLI 會問你 **Account ID** 和 **API Token**（步驟 1 取得的），貼上後它自動完成：

```
→ 驗證 Cloudflare 憑證... ✓
→ KV WEBHOOKS... ✓   （建 KV namespace，已存在則重用）
→ workers.dev subdomain: your-account
→ 下載部署物 + 部署 Worker（從 GitHub 拉預編譯 wasm，用你的 CF token 部署）...
  ✓ 部署完成：所有 Worker 全部成功
→ seed recipe（API recipe + auth recipe，由 API 灌入）... ✓
✓ Cloudflare 資源就緒（KV 全建妥，免費額度即可，無需綁卡）
✓ 設定寫入 ~/.arcrun/config.yaml
```

**非互動 / 給 AI、CI 用**：不想被問答打斷，可用 flag 或環境變數一次帶入：

```bash
# flag（優先序最高）
acr init --self-hosted --account-id <你的 Account ID> --api-token <你的 API Token>

# 或環境變數（與 wrangler 慣例一致）
export CLOUDFLARE_ACCOUNT_ID=<你的 Account ID>
export CLOUDFLARE_API_TOKEN=<你的 API Token>
acr init --self-hosted
```

你不需要懂 git、不需要懂 tinygo、不需要手動建任何東西——預編譯好的零件（`.wasm`）直接從 GitHub 下載，用**你自己的** CF token 部署到**你的**帳號。

**最後一步：身份設定（你自己持有，工具不碰）。** self-hosted 是單租戶——你不需要平台發的 API Key，只需要一個你自己填的值。在專案建一個 `.env`：

```bash
# .env（已被 gitignore；CLI 會自動讀）
NAMESPACE=leo                 # 你的資料分區標籤（明碼即可，這不是密碼）
```

> `NAMESPACE` 只是「你的資料放哪個分區」的標籤，不是密碼——要防別人呼叫你的 webhook，請對 webhook 加保護（見下）。

credential **不需要**你自管加密金鑰：`acr creds push` 走 TLS 把值送進你自己的 worker，由 **Cloudflare Workers Secrets** 託管（連你自己都讀不回，只能覆寫/刪除）。這需要 cypher worker 有一把能打 Workers Scripts secrets API 的 CF token（`acr init` 會印確切指令）：

```bash
wrangler secret put CF_SECRETS_API_TOKEN --name arcrun-cypher-executor
```

完成。之後有新版零件，跑 `acr update` 一樣自動拉新、重部署。

> 想先不碰 Cloudflare、純在本機感受語法？`acr init --local` 然後直接跳到下面「寫一個工作流」。

### 多帳號 / 接案（同一台電腦連不同 CF 帳號）

設定採三層，優先序 **環境變數 > 專案層 `.arcrun.yaml` > 全域 `~/.arcrun/config.yaml`**（仿 `git config`）：

- **自己的專案**：什麼都不放 → 自動用全域（你自己的 CF）。
- **幫客戶接案**：在客戶資料夾放一份 `.arcrun.yaml`（含該客戶的 cypher URL / api_key）→ 只在這個資料夾樹生效，離開自動切回全域。`.arcrun.yaml` 含憑證，`init` 會自動幫你加進 `.gitignore`。
- **不確定現在用哪個帳號？** `acr config --where` 會逐欄告訴你每個值來自哪一層。

### 讓 AI（Claude Code）連到對的 arcrun

arcrun 有一個 **MCP server**（`arcrun/mcp/`），讓 Claude Code 能直接呼叫 arcrun 的工作流/零件功能。
跟 CLI 一樣是「薄殼」——連哪個帳號由同一份設定決定（env > 專案 `.arcrun.yaml` > 全域）。

```bash
acr mcp-setup     # 依你的設定，在當前資料夾寫 .mcp.json（Claude Code 會讀它）
```

- `acr init` 會自動順帶跑這步。
- **接案切帳號**：在客戶資料夾設好 `.arcrun.yaml` 的 `mcp_url`（或 `ARCRUN_MCP_URL` env），重跑 `acr mcp-setup` → Claude Code 在該資料夾就連客戶那台 MCP。
- 沒設 `mcp_url` → 連平台預設（`mcp.arcrun.dev`）。

---

## 裝好之後：開始用

### 寫一個工作流

`hello.yaml`：

```yaml
name: hello
flow:
  - "input >> 完成後 >> transform"
config:
  transform:
    component: string_ops
    operation: upper
```

```bash
acr run hello --input input="Hello, world"   # → HELLO WORLD
```

### 要打外部 API？寫一個 recipe（不是做零件）

```bash
# 上傳一個打外部 API 的 recipe（push 時會幫你檢查打不打得通）
acr recipe push my_api_recipe.yaml
```

recipe 裡寫好 endpoint / method / body 模板，credential 由 auth 自動注入。workflow 裡用 `component: <recipe 名>` 或 `component: rec_xxxx` 引用它。

### 上傳 credential（client 端加密，明文不離開你的機器）

```bash
acr auth-recipe list              # 看支援哪些服務的認證
acr auth-recipe scaffold notion   # 取得 credentials.yaml 範本
acr creds push credentials.yaml   # AES-GCM 加密後上傳到你自己的 KV
```

### 部署 + 觸發

```bash
acr push newsletter.yaml          # 部署，取得 Webhook URL
acr run newsletter --input email=user@example.com
```

> ⚠️ **部署對外 webhook = 把東西暴露給外界。** `acr push` 產生的 trigger URL 任何拿到的人都能打。CLI 會在這類動作前提醒你——確認後就是你的責任（你可以選擇加上 API Key 限制 / 權限）。

---

## Workflow 語法

```
"A >> 關係詞 >> B"
```

這就是全部。每一行是一條邊，描述 A 之後發生什麼。

| 關係詞 | 別名 | 說明 |
|--------|------|------|
| `完成後` | `ON_SUCCESS` | A 成功後執行 B |
| `失敗時` | `ON_FAIL` | A 失敗時執行 B |
| `對每個` | `FOREACH` | 對 A 的每個元素執行 B（支援 `對每個 X` 命名）|
| `條件滿足時` | `IF` | 條件為真時執行 B |
| `CALLS_SUBFLOW` | — | 呼叫另一個 workflow |

整個 workflow 通常不超過十行，AI 一眼掃完不需捲動。

---

## 為什麼零件這麼少？（這是特性，不是缺陷）

你可能覺得「才這幾個零件，n8n 有幾百個」。但 n8n 那幾百個零件，本質多半是「把一個 HTTP request 包成某服務的格式」。在 arcrun，那些**全部是 recipe**——純文字、AI 幫你寫、不用等誰先做好封裝。

對 AI 來說，一個彈性的 `http_request` + recipe，比一百個固定零件封裝更好用：AI 讀得懂 API 文件，直接組出正確的 recipe，不必等有人做「Notion 零件」。

零件少 = 攻擊面小、要驗證的東西少、整套能塞進 AI 的 context。**長尾交給 recipe，核心保持精簡**，是刻意的設計。

---

## recipe 入庫把關（誠實說明）

- **自有庫（你的 self-hosted）**：`acr recipe push` 時 CLI 會 (1) 提醒會不會把資料/服務暴露給外界、(2) 幫你實打一次看 API 通不通（2xx）。這是**提醒級**——arcrun 不替你做授權判斷，打不打得通最終由發 API key 的服務裁決。打不通會誠實標原因（例：缺 credential），不會假裝成功。
- **公共庫（未來）**：recipe 要貢獻給別人用、進公共庫時，由維護者機制檢核「實際打通、真收到成功回傳」（投稿者不能自己驗證自己）。此機制在第一期之後啟用。

---

## CLI 指令

```
acr init --self-hosted             一鍵部署到你的 Cloudflare（貼 token，其餘自動）
acr init --local                   純本機體驗語法，不需 Cloudflare
acr creds push [file]              client 端加密並上傳 credentials
acr recipe push <file>             上傳 API recipe（push 時提醒暴露 + 檢查打通）
acr push <workflow.yaml>           部署 workflow，取得 Webhook URL
acr run <name> [--input k=v]       執行 workflow
acr validate <workflow.yaml>       執行前驗證格式 / 關係詞 / credential
acr parts                          列出可用的核心零件
acr parts scaffold <comp>          取得零件的 workflow config 範本
acr auth-recipe list               列出支援的第三方服務認證
acr auth-recipe scaffold <service> 取得 credentials.yaml 範本 + workflow 範例
acr list                           列出已部署的 workflow
acr logs <name>                    查看執行記錄
acr mcp-setup                      在當前資料夾寫 .mcp.json，讓 Claude Code 連對的 arcrun MCP
acr config --where                 顯示目前生效設定與來源層（避免在錯資料夾用錯帳號）
acr update                         self-hosted：拉新版零件/引擎並重新部署（未變動的 worker 自動跳過）
acr update --force                  強制重部所有 worker（忽略未變動跳過快取）
```

> 給 AI 操盤手：開始前讀 [`llms.txt`](llms.txt)——它說明 arcrun 的世界觀（工作流是 default、零件稀有且不自製、一切外部 API 皆 recipe），讓你一開始就走在正路上。跑過 `acr install-harness` 之後，同一套規範會裝進你的專案（arcrun-mindset Skill）。

---

## 設計原則（節錄）

- **減少對不可控第三方的依賴**：核心 MIT 開源、self-hosted、workflow 是你擁有的純文字。
- **解耦 / 原子化**：零件、recipe、執行引擎彼此可獨立替換。
- **arcrun 是 AI 用的工具**：需要 AI 判斷時是操盤的 CC 自己做，工作流裡**不內嵌**回頭呼叫 LLM 的節點。
- **誠實**：stub / 未驗證就如實標明，不假裝成功；完成以客觀證據（HTTP status / trace）為準。

---

## License

MIT

---

## 致謝

arcrun 的核心架構、WASM 零件、CLI 工具鏈與這份文件，由以下貢獻者共同打造：

- **[@youlinhsieh](https://github.com/youlinhsieh)** — 創始人，產品設計與架構決策
- **Claude（Anthropic）** — 實作夥伴：零件開發、executor 架構、CLI 實作與程式碼審查

想投稿零件？看 [CONTRIBUTING-components.md](CONTRIBUTING-components.md)。
