# Skill: Write Recipe(寫 recipe) ## 何時用這個 skill **`/cypher/search` 回 `not_found` 且 `suggestion` 指「寫 recipe」時,讀這支。** - 要打某個外部 API(Google Slides / Slack / 任何有 HTTP API 的服務),但 `arcrun_recipe_list()` 沒有 - `acr recipe search <關鍵字>` 落空,回「公庫無符合的 recipe」 - 你想把一條常用的 API 呼叫封裝成可重用、可投稿的配方 > 🔴 **不要因為沒有 recipe 就改寫成 `code` 節點**——那是「腹語術」。 > recipe 不用改平台、不用部署 Worker、不用寫程式,**幾行 YAML 就能自己補上**。 ## recipe 是什麼 **「http_request + 參數模板」的具名封裝**(真身存在 cypher-executor 的 RECIPES KV)。 執行時 cypher-executor 直接 fetch 該 endpoint——不 deploy Worker、不寫 WASM。 | 你缺的是… | 走哪條路 | |---|---| | 打**外部 API**(服務有 HTTP API) | **recipe(本 skill)** | | **計算能力**(加解密/壓縮這類純運算) | 零件 PR → `arcrun_get_skill('add_new_wasm_component')` | ## 1. Recipe 的欄位(schema) ```yaml canonical_id: google_slides_create # 必填。小寫底線,全庫唯一的可讀名 endpoint: https://slides.googleapis.com/v1/presentations # 必填。要打的 URL method: POST # 選填,預設 POST(GET/PUT/PATCH/DELETE 皆可) display_name: Google Slides Create # 選填,人看的名字 description: 建立一份新簡報。POST presentations,body 帶 title。auth: google service_account。 auth_service: google_slides_sa # 選填。指向 auth recipe(見第 3 節) headers: {} # 選填。額外固定 header body: {} # 選填。固定 body 欄位(會與節點 payload 合併) ``` - `hash_id`(`rec_xxxxxxxx`)與 `uuid` 由系統自動生成,不用寫。 - **description 認真寫**:AI(包括未來的你)靠它決定要不要用這個 recipe。 照庫裡的慣例寫「做什麼。怎麼打。auth 用什麼。」三段。 ## 2. 真範例(從實際 seed 且實跑過的 recipe 照抄) ### A. token 在 URL path(`telegram_send`) ```yaml canonical_id: telegram_send display_name: Telegram Send description: Telegram sendMessage。token 在 URL path({{auth.bot_token}}),body 帶 chat_id+text。auth: static_key path 注入。 endpoint: https://api.telegram.org/bot{{auth.bot_token}}/sendMessage method: POST auth_service: telegram ``` ### B. Bearer/service account(`gmail_send`) ```yaml canonical_id: gmail_send display_name: Gmail Send description: 寄 Gmail。POST messages/send,body 帶 raw(base64url MIME)。auth: google service_account。 endpoint: https://gmail.googleapis.com/gmail/v1/users/me/messages/send method: POST auth_service: google_gmail_sa ``` ### 模板變數(endpoint 裡可用) | 變數 | 來源 | 例 | |---|---|---| | `{{auth.X}}` | auth recipe 的 `inject.path` 注入 | `bot{{auth.bot_token}}/sendMessage` | | `{{_path}}` | 節點 payload 的 `_path` 欄位(路徑由工作流決定時用) | `https://sheets.googleapis.com{{_path}}` | 🔴 **金鑰只准名字,不准真身**:endpoint/headers 裡**絕不**寫死 token。 真值走 credential 中心(`acr creds push`),recipe 只留 `{{auth.X}}` 這種名字引用。 ## 3. auth 怎麼接(多數 recipe 需要) `auth_service: telegram` 表示執行時去拿 `auth_recipe:telegram` 做認證注入。 先查有沒有:`acr auth-recipe list` 或 `GET /auth-recipes/`。 **沒有就要一併建**(`POST /auth-recipes`,缺這步 recipe 會注入空值打不通): ```yaml service: telegram # 必填 primitive: static_key # 必填:static_key | oauth2 | service_account base_url: https://api.telegram.org # 必填 required_secrets: # 必填,每個 secret 的 help_url 也必填(官方文件連結) - key: telegram_bot_token label: Bot Token(從 @BotFather 取得) help_url: https://core.telegram.org/bots/features#botfather inject: # 必填:secret 注入到哪(header / query / body / path) path: bot_token: "{{secret.telegram_bot_token}}" ``` 然後用戶端上傳真值:`acr creds push`(存進 credential 中心,AI 拿不到真身)。 ## 4. 裝上(三個介面同一個 API) ```bash acr recipe push my_recipe.yaml # CLI:push 時會實打 endpoint 做打通檢查 ``` - MCP:`arcrun_recipe_push(...)` - HTTP:`POST /recipes`(JSON,欄位同上) 裝好後 workflow 直接引用(節點名=canonical_id,或 config 指定): ```yaml config: notify: component: telegram_send # 或穩定引用 rec_xxxxxxxx ``` payload(如 `chat_id`、`text`)由上游節點或 context 給——這正是「AI 只填 payload」。 ## 5. 驗收(誠實原則) 1. push 時的**打通檢查**只是提醒級——真驗收=**跑一次 workflow、`verdict=success`(2xx)** 2. 缺 credential 打不到 2xx → 誠實標「未驗收:缺 X」,**不 mock 充綠燈** 3. 打通後可投稿公庫讓別人用:`acr recipe submit-p `(成為該 recipe 的作者版本) ## 6. 常犯的錯 1. **token 寫死在 endpoint/headers** → 金鑰鐵律違規。只准 `{{auth.X}}` 名字引用 2. **method 用猜的** → 查官方文件。實錄:Sheets append 被猜成 PUT(官方是 POST `:append`), seed 到壞 recipe 每個新用戶都打 400 3. **只建 recipe 忘了 auth recipe** → `{{auth.X}}` 注入空值打不通。實錄:telegram auth recipe 漏進種子,所有新實例的 telegram 發訊全斷 4. **落空就寫 code 節點** → 腹語術。recipe 是正路,且寫好可投稿讓全生態重用 5. **canonical_id 用大寫/空白** → 一律小寫底線(系統會 trim+lowercase,但別靠它救) ## 7. 相關 - 寫意圖工作流(上游,先寫意圖再查缺什麼):`arcrun_get_skill('write_intent_workflow')` - 缺的是計算零件不是 API:`arcrun_get_skill('add_new_wasm_component')` - 查公庫現貨:`acr recipe search <關鍵字>` / `arcrun_recipe_search(...)` - 拉別人寫好的:`acr recipe pull [--author=]`