mcpField
W
workflows-create

workflows-create

github.com/zapier生産性23522 回インストール3 週間前に更新
リポジトリ

workflows-create について

workflows-createは、合意した自然言語の要件からZapierの永続的なワークフローを作成し、実験的なSDK CLIでテストとデプロイを行うエージェントスキルです。アプリやフィールドの調査から構築、デプロイ確認までを扱います。

主な機能

  1. 01要件と開始モードの確認
  2. 02アプリ、アクション、トリガー、フィールドの調査
  3. 03永続的なTypeScriptワークフローの構築
  4. 04デプロイ前のドラフトテスト
  5. 05ワークフローの公開と確認

活用シーン

  1. 01自然言語の要件からワークフローを作成
  2. 02アプリ連携ワークフローのテストとデプロイ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/zapier/agent-skills --skill workflows-create

インストール後、Claude Code で/workflows-createを入力して読み込まれたか確認します。

詳細

Zapier Workflows の作成

自然言語から完全で永続性のあるワークフローを作成し、必要に応じてテストして、Zapier SDK の実験的な Code Workflows コマンドを使ってデプロイします。

公開 SDK CLI のパスを使用してください。zapier-sdk-code-substrate は使用しないでください。

互換性チェック

このスキルを使用する前に、workflows-doctor バンドルの互換性チェックを実行してください。workflows-doctor がインストールされていないか、読み込めない場合は、続行する前に workflows-install を実行するか、zapier/agent-skills から workflows-doctor をインストールしてください。SDK とスキルの不整合が報告された場合は、その更新手順に従い、このスキルの実行を停止してください。必要に応じてエージェントのワークスペースを再読み込みし、元の依頼を再実行するようユーザーに依頼してください。

前提条件

最初に次の内容を確認してください。

zapier-sdk --version
zapier-sdk get-profile --json
zapier-sdk --stability experimental --help

@zapier/zapier-sdk には "latest" を指定してください。サーバーはサンドボックスにインストール可能な最新リリースを解決し、公開時に正確なバージョンを保存します。ドラフトには指定した値がそのまま保存されます。レジストリへのアクセスも、公開日の計算も必要ありません。これは npm の latest タグではありません。サンドボックスは pnpm install --config.minimumReleaseAge=1440 でインストールし、@zapier/zapier-sdk は 1 日に数回公開されるため、このタグはインストールするには新しすぎるリリースを指すことがよくあります。

--zapier-durable-version はランタイムエンジンのバージョンを設定するフラグです。@zapier/zapier-durable を --dependencies に含めてはいけません。デフォルトではこのフラグを省略してください。新しいドラフトにはサーバーでサポートされているバージョンが設定され、更新時には保存済みのバージョン指定が維持されます。再公開時に get-workflow-version で取得したバージョンを引き継ぐ場合、または意図的にバージョンを固定・アップグレードする場合に限り、明示的に指定してください。永続ランタイムのバージョンに範囲指定(^1.2.3、~1.2)を使うと 400 エラーで拒否されるため、明示する値は正確なバージョンか latest にしてください。

サーバー側で解決されるのは @zapier/zapier-sdk のみです。それ以外の依存関係は指定どおりに保存され、インストールのたびに再解決されるため、浮動する指定は同一実行中のティック間で変わる可能性があります。ドラフトを更新する際は、固定した zod を含め、ソースでインポートするすべての依存関係を宣言してください。そうすることで、未公開状態でのテストに必要なものがすべて揃います。サンドボックスはローカルの package.json ではなく --dependencies からインストールするため、インポートが不足すると、実行時に Cannot find package エラーが発生します。

また、ワークフローで実行するアプリのアクションについては、ユーザーが https://zapier.com/app/assets/connections でアプリの接続を設定している必要があります。

Surface toolbox(SDK CLI)

  • アプリ/アクション/接続を検索する:zapier-sdk list-apps --search "<name>" --json、list-connections <appKey> --owner me --json、list-actions <appKey> --action-type <type> --json、list-action-input-fields、get-action-input-fields-schema、list-action-input-field-choices
  • トリガーを検索する:zapier-sdk --stability experimental list-triggers <appKey> --json、list-trigger-input-fields、list-trigger-input-field-choices
  • テスト用プローブ:zapier-sdk run-action <appKey> <actionType> <actionKey> --connection <connectionId> --inputs '<json>' --json。フェーズ 2 のトリガーサンプルは run-action <appKey> read <triggerKey> --connection <connectionId> --inputs '<published params>' --max-items 1 --json です。
  • ステージング:zapier-sdk --stability experimental create-workflow、create-workflow-draft、update-workflow-draft、get-workflow-draft
  • テスト実行:zapier-sdk --stability experimental run-workflow-draft <workflow-id> <draft-id> <draft-revision> --input '<JSON>' --json、get-workflow-run <run-id> --json
  • デプロイ:zapier-sdk --stability experimental publish-workflow-draft、discard-workflow-draft
  • 検証と実行:zapier-sdk --stability experimental get-workflow、list-workflow-versions、get-workflow-version、trigger-workflow、get-trigger-run、list-workflow-runs、get-workflow-run

selected_api は、list-apps/get-app の implementation_id です。

アクションの入力仕様全体を取得するには、フィールドの検索とあわせて zapier-sdk get-action-input-fields-schema <appKey> <actionType> <actionKey> --json を実行してください。その data はスキーマドキュメントであり、list-action-input-fields が返す編集可能フィールドの配列ではありません。確定した同じ入力値と接続コンテキストを渡してください。サポートされているフラグについては、インストール済みコマンドの --help を参照してください。

AI by Zapier のステップでは、SDK 固有の検索方法の引き継ぎについて、インストール済みの workflows-ai-by-zapier コンパニオンを読み込んでください。これはアクションが所有するスキーマを補足するものであり、別の設定仕様ではありません。コンパニオンがインストールされていない場合は、利用可能な仕様を持つステップを保留せず、ここに記載の検索フローを使用してください。

ワークフローはローカルプロジェクトとして生成してください。<kebab-case-workflow-name>/ に package.json、workflow.ts、およびソースがインポートするヘルパーモジュール(lib/format.ts)を格納します。完了時にはプロジェクトの保存場所を伝え、ファイルが複数ある場合はファイル名を列挙してください。package.json はローカルの型チェック専用であり、source_files には含めません。後続のフェーズではこのディレクトリを走査してそのマップを作成するため、このワークフロー固有のファイルだけを含めてください。

package.json にビルドスクリプトを追加する場合は、SDK/durable の推移的な型宣言による型チェックエラーを避けるため、現時点では --skipLibCheck を使用してください。

{
  "scripts": {
    "build": "tsc --target es2022 --module nodenext --moduleResolution nodenext --skipLibCheck --outDir dist workflow.ts"
  }
}

durable.run is not a function は、バージョンの不一致ではなく、defineDurable の呼び出しにおけるコード形式の不備です。これを修正するために @zapier/zapier-durable や @zapier/zapier-sdk のバージョンを変更しないでください。名前と run 関数を渡すように呼び出しを修正してください。

エントリーポイントの拡張子は .ts ではなく .mts、.js、.mjs、.cjs、.cts でもかまいませんが、必ず 1 つだけにしてください。Publish では、トップレベルの index.*、package.json、.zapierrc、および予約済みの _zapier_* 名は拒否されます。入れ子になった lib/index.ts は問題ありません。

自然言語から完全な durable ワークフローを作成し、テスト、デプロイを行い、稼働中であることを検証してください。

ワークフローは、@zapier/zapier-durable の defineDurable を使用する TypeScript モジュールです。各 ctx.step() はジャーナルに記録されます。実行が再試行またはリプレイされると、完了済みのステップは処理を繰り返す代わりに、記録された結果を返します。公開済みのワークフローは Zapier のインフラストラクチャ上で、この会話とは独立して実行されます。

このスキルのサーフェス固有の各セクションでは、以下で使用する機能(アクションの検索、トリガーの検索、接続一覧、テスト用プローブ、公開、テスト実行)を、利用するサーフェスの具体的なツールまたはコマンドに対応付けています。このスキルで「検索ツール」または「公開方法」と記載されている場合は、その対応付けに従ってください。

フェーズ 1:意図を把握する

ユーザーのリクエストから、以下を抽出します。

  1. 手順とその順序。
  2. 使用するアプリ。
  3. 各手順で受け渡されるデータ。
  4. 手動入力フィールドまたはトリガー入力フィールド。
  5. 条件分岐と、結果が空の場合の動作。
  6. ワークフローを起動するもの(アプリのトリガー、スケジュール、外部からの webhook POST、または手動実行のみ)。
  7. 待機、コールバック、再試行、人による承認ゲート。
  8. 開始モード(必須。以下を参照)。

検出を始める前に、提案するワークフローを要約します。必須の意図が本当に不足しており、安全な既定値がない場合に限り、要点を絞って確認します。たとえば、あいまいな宛先、宛先の欠落、検索結果がない場合の対応などです。ユーザーがワークフローの形に同意するまで、ソースを生成しないでください。

開始モードを分類する(必須)

すべてのワークフローには開始モードが 1 つだけあります。ここで決定する必要があります。

  • trigger — ワークフローは、スケジュールに従うか、外部イベントに応答して自動的に開始します。デプロイ後の最終バージョンには trigger 設定が含まれ、誰かが起動しなくても実行されます。
  • manual — ワークフローにトリガーはなく、使用する環境のワークフロー実行機能を通じたオンデマンド実行のみです。これは意図的な選択であり、トリガーがないことによるものではありません。

ビルド指示でトリガーを探すことを既定とします。意図を示す表現から推測してください。「毎朝」「毎日」「スケジュールに従って」など、繰り返しや時間を表す言葉があれば、スケジュールされた trigger を意味します。「<app> で X が起きたとき」や「新しい <record> が作成されるたびに」は、イベント駆動の trigger を意味します。「手動で」「オンデマンドで」「実行したとき」と明示されていれば、manual を意味します。

開始モードがあいまいな場合、つまり明確なトリガーを示す表現も、明示的な手動実行の指定もない場合は、オンデマンドで手動実行するのか、トリガーを設定するのか、ユーザーに確認します。トリガーが指定されていないという理由だけで、暗黙のうちに manual と決めないでください。確認していない前提に基づいてトリガーなしのワークフローを公開することこそ、この分類で防ぐべき失敗です。

選択した開始モードを以降のフェーズでも引き継ぎます。フェーズ 3 のビルド計画で確認し、フェーズ 5 のデプロイ検証の判定基準にしてください。

不足している意図に該当しないもの
  • 名前が指定されたリソース(Slack の #channel、スプレッドシートのタイトル、フォルダー名、プロジェクト名など)は、意図が与えられています。ユーザーに何かを尋ねる前に、フェーズ 2 の検出で不透明な API 識別子を特定してください。
  • オプションのパラメーター、製品の既定値として返されるフィールド値、安全な既定値がある実装上の選択は、意図の不足ではありません。既定値を使用して、そのまま進めてください。
  • 範囲が限定された AI 検索ステップに自然言語で指定された対象(「アクティブな Platform エピック」など)は、意図が与えられています。その対象を AI ステップの指示に含めてください。ユーザーに正確なクエリ構文への変換を求めないでください。
意味的なイベントの部分集合

ユーザーがアプリのイベントについて意味的な部分集合(「ベンダーが連携を依頼したとき」「メッセージが緊急そうなとき」「フィードバックが実行可能なとき」など)を説明した場合、ビルド前にラベル、送信者リスト、キーワードルールを考案するよう強制しないでください。ユーザーが決定的なルールを指定していない限り、利用可能な送信者、件名、本文、ラベルのフィルターは、信頼できる意味的フィルターではありません。任意のフィルターは空のままにして、範囲の広いソースイベントを設定し、範囲が限定された AI ステップを使ってワークフロー内で該当しないイベントを判定し、スキップしてください。範囲の広いイベントが危険、過度にノイズが多い、またはユーザーが明示的に狭いトリガーを求めている場合に限り、より限定的なトリガーについて確認してください。

フェーズ 2:アプリ、アクション、接続、トリガー、フィールドを確認する

使用しているインターフェースの確認ツールを使い、実際の識別子を調べてください。アプリキー、アクションキー、アクションタイプ、フィールド名、フィールド値、アプリのバージョン、接続 ID を決して推測で作らないでください。学習時の知識は、そもそも古くなっています。

アプリ/アクションごとに作業してください。確認したキー、タイプ、フィールド、選択肢、接続 ID、出力形式を記録します。候補が複数考えられる場合は、候補を提示してユーザーに選んでもらいます。確認ツールが返したアプリ以外は追加しないでください。

返された編集可能フィールド、選択肢、スキーマ、ロックを尊重してください。依存関係を解決する際は、同じアクション/バージョン、接続、確定済みの親入力を使います。それらが変わった場合は、あらためて確認してください。ネストされた契約情報が見つからない場合は、バージョンに対応したインストール済みのコンパニオンによる代替手段のみを使用し、それもなければ制限事項を伝えてください。メタデータや代替手段によって権限が付与されることはありません。

名前付きリソースを、質問する前に解決する

リクエストに記載された人が読める宛先名は、ユーザーが指定した意図であり、必須値が欠けているわけではありません。アクションが必要とする API 識別子に解決してください。

  1. フィールドに選択肢が動的に表示される場合は、アクションフィールドの選択肢を優先します。
  2. それ以外の場合は、選択した接続を使って、対象アプリの文書化された読み取り/一覧表示アクションまたは API からリソースを検索します。
  3. 完全一致が 1 件なら、自動的に処理を続けます。
  4. 検索結果がない場合、候補が複数考えられる場合、または利用可能なツールでは解決できない場合に限り、ユーザーに質問します。

利用可能な検索を試す前に、不透明な ID を貼り付けるようユーザーに求めないでください。アクションが指定された人が読める名前を直接受け付ける場合は、それを最終的な代替手段とします。投稿者が指定されていない場合は、アクションのデフォルトを使用します。アクションで選択が必要な無人ワークフローでは、ボット形式の投稿者を優先します。

AI ステップ、エージェント型のツールループ、意味解析には AI by Zapier を使用する

使用しているインターフェースに AI by Zapier コンパニオンがある場合は、そのインターフェースの手順に従って読み込んでから、ステップを設定してください。

ワークフローで、完全なルールに基づくコピーや計算ではなく、意味の推論が必要な場合は、範囲を限定した AI by Zapier ステップを使用します。要約、生成、文体に幅のある文章からの抽出/分類、リスク分析、曖昧検索、曖昧さの解消は、ユーザーが「AI」と言っていなくても該当します。直接的なマッピング、厳密な書式設定、算術、指定された正規表現/キーワード表、完全に指定された条件は、決定論的な処理のままにします。ユーザーが別のプロバイダーアプリを明示的に要求する場合、または AbZ では対応できない機能が必要な場合を除き、AI by Zapier を優先してください。プロバイダー/モデル名だけを指定されても、AbZ を使わない理由にはなりません。Code by Zapier の明示的なリクエストには従ってください。

トリガーと前のステップにすべての根拠が含まれている場合は、プロンプトのみで AbZ を使用します。モデルが検索先を選択、確認、調整、または繰り返し検索する必要がある場合に限り、読み取り/検索ツールを埋め込みます。あらかじめ定められた検索と最終的な副作用は、AI が型付き出力を返した後に、永続的なワークフローステップとして実行します。

現在の get_completion アクション、その編集可能フィールド、依存する選択肢、利用可能な場合は入力スキーマ全体を確認してください。契約情報はメタデータに従います。スキーマが利用できない場合は、ラベルや記憶している例ではなく、使用しているインターフェースに文書化された AbZ の代替手段のみを使用してください。ユーザーが別の対応モデルを要求しない限り、現在のモデルのデフォルト設定を使用します。inputs.authentication_id: "0" は、管理対象モデルの認証情報入力であり、外側のワークフローやネストされたツールの接続ではありません。get_completion_agentic は呼び出さないでください。

安定した指示は、トリガーや前のステップのコンテキストとは分けて渡します。確認した契約情報に基づいて出力を設定し、実際の結果を検証してください。デフォルトのテキスト出力は result.data[0].output です。設定済みの出力は、名前付きの各項目フィールドに格納されます。

永続的なワークフローでは、トリガー、分岐、宛先、承認、副作用、完了時の動作を引き続き管理します。範囲を限定した LLM/ツールループは、永続的なエージェント自動化ではありません。

接続をマッピングする

認証が必要な各アプリには、接続の検出またはサーバー側バインディングを使用します。エイリアスを選ぶ場合は、slack_work のような短い snake_case 名を使用します。アプリキーを使用するバインディングサーバーでは、独自の規則が適用されます。外側の SDK エイリアスはテスト/公開時に解決されます。トークンや生の認証情報を埋め込まないでください。

アクション入力の接続参照は別のものです。アクションスキーマで必要な場合に限り、検出した識別子を、指定された形式で渡してください。外側のエイリアスに置き換えたり、ID をデコードしたり、外側のバインディングがネストされた入力を書き換えると想定したりしないでください。利用しているインターフェースで必要な参照を検出できない場合は、その制限を報告してください。

組み込みアプリの中には、設計上認証不要のものがあります。Schedule、Webhooks、Code、Formatter、Filter、Delay by Zapier が該当します。これらにはエイリアスを設定せず、接続バインディングにも表示されません。スキーマが管理する認証を持つアプリも同様です。たとえば、AI by Zapier は検出した authentication_id をアクション入力として渡します。

アクションの出力形状を確認する

出力が後続のステップで使われるアクションは、フィールドを推測せず、利用しているインターフェースの読み取りプローブ機能を使ってテストしてください。プローブ結果が大きすぎて全体を読めない場合は、キー名だけでは値が文字列かオブジェクトか分からないため、値を短縮したレコードを1件確認してください。書き込みプローブは実データを作成または変更する可能性があるため、副作用を説明し、実行前に確認を待ってください。

ワークフロー内では、sdk.runAction は { data, nextCursor } を返します。ワークフローのソースでは、最初のアイテムを result.data[0]、アイテムのリスト全体を result.data として読み取ります。アクション出力に対して、value.results || value.items のようなフォールバックチェーンを作らないでください。

トリガーを検出する

トリガーを使用するワークフローでは、利用しているインターフェースのトリガー検出ツールを使って、トリガー、その設定フィールド、フィールドの選択肢を検出してください。検出した値からトリガー設定を作成します。

{
  "selected_api": "[email protected]",
  "action": "new_row",
  "authentication_id": "connection-id-or-null",
  "params": {}
}

selected_api は、検出したトリガー結果に含まれる実装識別子であり、表示名ではありません。値はそのまま、@latest を付けて、またはバージョンを固定して(<app_key>@<app_version>)送信できます。公開時に解決され、公開呼び出しが返すバージョンと、それ以降に読み戻されるバージョンには、固定された値が保持されます。再公開時には、後の公開で気付かないうちに新しいアプリバージョンへ移行しないよう、固定した値を再利用してください。

各トリガーパラメーターには、検出された型を使用してください。配列フィールドには JSON 配列("dow": ["1"])、文字列フィールドには通常の文字列("hod": "9:00 AM")を指定します。配列が必要な箇所にスカラー値を指定すると、公開時に明示的なエラーが発生して拒否されます。認証不要のトリガーでは、authentication_id に null を指定するか、省略してください。それ以外の場合は、選択したトリガー接続 ID を使用します。

Webhooks by Zapier やその他のキャッチフックアプリは、実際のトリガーです。他のトリガーと同様に検出して設定してください。すべてのキャッチフックが認証不要だと決めつけず、アクションキー、認証、パラメーターを確認してください。プロバイダーへのサブスクリプションを登録するクレームを持つアプリでは、通常、接続が必要です。Webhooks by Zapier 自体は認証不要(authentication_id: null)で、params は空です。また、hook_v2(パース済みペイロード。一般的なデフォルト)と hook_raw(生のボディとヘッダー。最大 2MB)を公開します。検出機能でキーを確認してください。このペアは Webhooks by Zapier 固有であり、共通パターンではありません。キャッチフックにはサンプル用のレコードがありません。送信側が投稿すると記載しているフィールドを入力してください。

トリガーをサンプリングする
  1. 利用しているインターフェースの読み取りプローブを使い、トリガー自身のキーを持つ読み取りアクションを実行します。似た別のアクションは使用せず、公開する予定の params を正確に指定してください。
  2. レコードを1件、全体を読み取ります。出力を行単位で切り詰めないでください。
  3. レコードに表示された内容だけを型指定します(フェーズ4)。表示されなかったフィールドには固定の型を設定しないでください。
必要に応じて既存のワークフローを参考にする

同様の動作するワークフローがある場合、現実的なソース、接続のバインディング、トリガー設定を参考にできます。これは任意であり、必須の最初の手順ではありません。使用しているサーフェスのワークフロー確認ツールで読み取り、新しいワークフローに関連するパターンだけを参考にしてください。

フェーズ 3:ビルド計画を確認する

次の計画を提示します。

Workflow: <kebab-case-name>
Input: { field1, field2 }
Connections:
  alias = connectionId (connection title)
Start mode: trigger (<selected_api.action with typed params>)
Trigger sample: <trigger key> with <params> → <keys seen> — or — none, fields read untyped
  — or —
Start mode: manual — on-demand only
Steps:
  1. <step-name> - <AppName>.<actionType>.<actionKey>
  2. <step-name> - <AppName>.<actionType>.<actionKey>
Return: <summary of output>

Start モードの行は必須で、フェーズ 1 で分類した 2 つのモードのうち、いずれか 1 つを正確に指定する必要があります。

必須の詳細が不足しているか、曖昧な場合は、ここで止めて焦点を絞った質問をしてください。すべての情報が提供されているか、調査によって曖昧さなく解決できた場合、ワークフロー作成の依頼自体がすでに承認となります。計画を簡潔に提示し、同じターン内で作業を続けてください。

フェーズ 4:ワークフローのソースを記述する

ソースは { path: contents } マップです。ソースを送信するたびにマップ全体が置き換えられ、サーバー側でマージされることはありません。含めなかったファイルは削除されるため、常にファイル一式を送信してください。

トップレベルのエントリーポイントは 1 つだけにしてください。通常は workflow.ts です。ワークフローが小さいうちはその中に記述し、規模が大きくなったら、純粋なヘルパー、長いスキーマ、プロンプトのテキストを相対パスのモジュールに移してください(拡張子を含む ./lib/format.ts を、そのキーで格納します)。エディターがステップのグラフを読み取れるよう、defineDurable とすべての ctx.step はエントリーポイントに残してください。

エントリーポイントでは、以下を守ってください。

  • defineDurable を @zapier/zapier-durable から、createZapierSdk を @zapier/zapier-sdk から、モジュール先頭の静的な import 文として読み込みます。ソース内の各ファイルで必要なすべてのパッケージを、同じ方法で宣言してください。関数の内部や動的な import() を使って読み込んではいけません。
  • 宣言するすべての依存関係は、実在し、公開から 24 時間以上経過していることを確認した正確なバージョンに固定します。バージョンをでっち上げたり、推測したりしてはいけません。https://registry.npmjs.org/<name> のレジストリドキュメント(スコープ付きの場合は @scope%2Fname)には、各バージョンの公開日時が time の下に記載されています。例外として @zapier/zapier-sdk は、正確なバージョンの固定でも、文字列リテラル "latest" でも構いません。プラットフォームが "latest" を実際にインストールするバージョンに解決します。@zapier/zapier-durable はランタイムエンジン自体であり、そのバージョンは公開手順で設定されるため、依存関係として宣言しません。
  • SDK クライアントをモジュールスコープに 1 つ作成します。const sdk = createZapierSdk() とします。
  • ワークフローに入力がある場合は、Zod を使って検証し、スキーマを inputSchema として渡します。検証の前に、文字列化された入力を正規化してください。実行の継続に不可欠な項目だけを必須にします。トリガーが渡す各フィールドには .nullable().optional() を付けてください。.optional() または .default() だけでは null が渡された際にエラーとなりますが、トリガーのペイロードでは null が頻繁に送られるためです。値を読み取る際は、使用箇所で ?? によるフォールバックを設定してください。
  • 外部呼び出しはすべて、名前付きの ctx.step 内に配置します。アプリのアクションを実行する各ステップには、sdk.runAction を正確に 1 回含めます。認証済み HTTP を実行するステップには、sdk.fetch を 1 回含めます。
  • 決定的な検証、分岐、ガード、データ整形はステップの外に配置します。
  • new Date()、Date.now()、Math.random() など、リプレイごとに変わる可能性のある値はステップ内に配置し、1 回だけジャーナルに記録されるようにします。
  • 発見した正確な read、search、または write のアクションタイプを使用します。
  • 外側の SDK 接続にはエイリアスを使用し、スキーマ所有のアクション入力参照には「接続のマッピング」に従います。
  • 一意で説明的なケバブケースの動詞・名詞形式のステップ名(find-jira-issue、send-approval-email など)を使用し、公開済みのワークフローを変更する際も同じ名前を維持してください。ステップ名を変更すると、ジャーナル上の識別情報が失われます。step-1 のような汎用的な名前は避けてください。

サンプルレコードのキーは、同じ名前のスキーマキーに対応付けます。"user": { "id": "U0…", "name": "alice" } は、user: z.object({ id: z.string(), name: z.string() }).loose().nullable().optional() になります。サンプルに現れないキーには z.unknown() を使い、使用箇所で型を絞り込んでください(typeof v === "string" ? v : v?.id)。

入力は JSON 文字列として届く場合があります。

function normalizeInput(rawInput: unknown): unknown {
  if (typeof rawInput === "string") {
    return JSON.parse(rawInput);
  }
  return rawInput;
}
有効でエディターに適したモジュール形式を使用する

すべての defineDurable 呼び出しで、run が関数に解決される必要があります。オブジェクト形式の defineDurable({ name, inputSchema, run }) を推奨します。defineDurable("name", run) も使用できます。ワークフロー名のない関数のみを渡したり、run のないオブジェクトを渡したりしないでください。これらは durable.run is not a function エラーになります。

各アプリのステップでは、SDK と定数をモジュールレベルに置き、名前付きの durable を使い、runAction を直接呼び出す本体をデフォルトにしてください。

import { defineDurable } from "@zapier/zapier-durable";
import { createZapierSdk } from "@zapier/zapier-sdk";
import { z } from "zod";

const sdk = createZapierSdk();

const InputSchema = z.object({
  ticketId: z.string(),
  label: z.string().nullable().optional(),
});

const JIRA_APP_KEY = "JiraSoftwareCloudCLIAPI";
const JIRA_CONNECTION = "jira_work";
const SLACK_APP_KEY = "SlackCLIAPI";
const SLACK_CONNECTION = "slack_work";
const SLACK_CHANNEL = "C0123456";

const workflow = defineDurable({
  name: "notify-about-jira-issue",
  inputSchema: InputSchema,
  run: async (ctx, rawInput) => {
    const input = InputSchema.parse(normalizeInput(rawInput));

    const issuePage = await ctx.step("find-jira-issue", async () =>
      sdk.runAction({
        appKey: JIRA_APP_KEY,
        actionType: "search",
        actionKey: "search_issues",
        connection: JIRA_CONNECTION,
        inputs: { query: input.ticketId },
      }),
    );

    const issue = issuePage.data[0];
    if (!issue) {
      return { skipped: true, reason: "issue-not-found" };
    }

    const label = input.label ?? "Jira";
    const message = `${label} ${issue.key}: ${issue.summary}`;

    const notification = await ctx.step("notify-slack-channel", async () =>
      sdk.runAction({
        appKey: SLACK_APP_KEY,
        actionType: "write",
        actionKey: "send_channel_message",
        connection: SLACK_CONNECTION,
        inputs: { channel: SLACK_CHANNEL, text: message },
      }),
    );

    return { notification };
  },
});

任意のトリガーフィールドが欠落していたり、名前が変更されていたりしても、それを理由に処理を停止してはいけません。上記の input.label ?? "Jira" のようにフォールバックで解決して、アクションを実行してください。任意の値が渡されなかったことを理由に、throw や早期の return をしてはいけません。任意のフィールドには .nullish() ではなく .nullable().optional() と記述してください。他の製品の画面ではその表記だけが読み取られます。

スキーマで名前が指定されていないキーを保持するには、オブジェクトスキーマに .loose() を追加してください。ペイロードに既知のフィールドがまったくない場合に限り、z.record(z.string(), z.unknown()) または z.looseObject({}) を使用してください。プラットフォームの zod では解析時にクラッシュするため、引数が 1 つだけの z.record(z.unknown()) は使用しないでください。

Zapier エディターでは、文字列リテラルのステップ ID にインラインコールバックがあり、その本体が appKey、actionType、actionKey を指定した sdk.runAction の直接呼び出し 1 つだけである場合、ctx.step はアプリアクションのステップ(アプリアイコン付き)として表示されます。アクションがないステップ、複数のアクションがあるステップ、動的なループ ID を使うステップはコードステップとして表示されます。これらのパターンでは想定どおりの動作です。ループやファンアウトでは動的な ID が必要だからです。

SDK 経由でのみアプリにアクセスする

外部接続には公開済みエイリアスを指定した createZapierSdk() を使用するか、「接続をマップする」で説明されているスキーマ所有のアクション入力参照を使用してください。グローバルな Zapier クライアント、ctx 上の接続オブジェクト、process.env 内の接続トークンはありません。

await ctx.step("send-slack-message", async () =>
  sdk.runAction({
    appKey: "SlackCLIAPI",
    actionType: "write",
    actionKey: "direct_message",
    connection: "slack_work",
    inputs,
  }),
);

const gitlabUser = await ctx.step("fetch-gitlab-user", async () => {
  const response = await sdk.fetch("https://gitlab.com/api/v4/user", {
    connection: "gitlab_work",
    method: "GET",
  });
  if (!response.ok) {
    throw new Error(`GitLab returned ${response.status}`);
  }
  return response.json();
});

// Wrong: ctx.zapier and ctx.connections are undefined.
await ctx.zapier.fetch(url, { connection: ctx.connections.slack });

Zapier アクションがある場合は、sdk.runAction を優先してください。動的フィールドや依存フィールド、アプリ固有の認証方式、正規化されたレスポンスを処理できます。必要な動作を提供するアクションがない場合に限り、認証済みの sdk.fetch を使用してください。Response はステップ内で処理し、シリアライズ可能な JSON またはテキストを返してください。生のレスポンスや本文ストリームをステップの出力として返してはいけません。

フィルターパターン

条件を満たさない実行を除外するには早期リターンを使用し、副作用のない条件ロジックは ctx.step の外に置いてください。フィルターを追加してもステップグラフに価値はありません。複雑な複数条件のフィルターでは、名前付きの const バインディングを使用してください。

const tags = input.tags ?? [];
const isActiveAndUrgent = input.status === "active" && tags.includes("urgent");
const isHighPriority = (input.priority ?? 0) > 8;
const shouldRun = isActiveAndUrgent || isHighPriority;

if (!shouldRun) {
  return { skipped: true, reason: "filter-did-not-match" };
}
Durable パターン

待機処理はステップ内ではなく、ワークフローのスコープに置いてください。

await ctx.wait("wait-before-followup", 3600);

ジャーナル再生で変化する可能性がある値は、1 回だけ記録してください。

const createdAt = await ctx.step("capture-created-at", async () =>
  new Date().toISOString(),
);

人間による承認にはコールバックを使用してください。

const [approvalPromise, callbackUrl] = await ctx.createCallback({
  name: "wait-for-approval",
  payloadSchema: z.object({ approved: z.boolean() }),
  timeoutSeconds: 86400,
});

await ctx.step("send-approval-request", async () =>
  sdk.runAction({
    appKey: "ExampleCLIAPI",
    actionType: "write",
    actionKey: "send_message",
    connection: "example_connection",
    inputs: { callbackUrl },
  }),
);

const approval = await approvalPromise;
if (!approval.approved) {
  return { skipped: true, reason: "denied" };
}

独立した処理には、ステップの外で Promise.all を使い、項目ごとに 1 つのステップを設けてください。

const results = await Promise.all(
  items.map((item, index) =>
    ctx.step(`process-item-${index}`, async () =>
      sdk.runAction({
        appKey: "ExampleCLIAPI",
        actionType: "write",
        actionKey: "do_something",
        connection: "example_connection",
        inputs: { item },
      }),
    ),
  ),
);

不安定な外部呼び出しにはステップの再試行を使用してください。

const result = await ctx.step({
  name: "call-flaky-service",
  maxAttempts: 3,
  retryDelaySeconds: 5,
  run: async () =>
    sdk.runAction({
      appKey: "ExampleCLIAPI",
      actionType: "write",
      actionKey: "do_something",
      connection: "example_connection",
      inputs: {},
    }),
});

フェーズ 5:テスト、公開、確認

テストと公開の手順はサーフェスごとに異なります。それぞれのサーフェスのセクションに従ってください。変わらない原則は次のとおりです。

  • ユーザーがアカウント全体への公開を明示的に求めない限り、プライベートなワークフローをデフォルトにします。
  • トリガーを有効にして公開する前に、実際にテストを実行してワークフローを検証します。ワークフローを作成せずにソースを直接実行できるサーフェスでは、作成前にテストします。未公開のドラフトを実行できるサーフェス(ドラフトテスト実行)では、ドラフトを未公開のままテストし、テストに合格した場合にのみ公開します。どちらも利用できない場合に限り、トリガーなしまたは無効の状態で先に公開してテストし、テストに合格した後でトリガーを追加します。
  • 接続済みアプリに変更を加える可能性のあるテストの前に、起こりうる副作用をそれぞれ説明し、確認を待ちます。サンプルレコードの形式に合った、影響のない代表的な入力を優先します。外部への書き込み前にワークフローがイベントをフィルタリングする場合は、明らかに条件に一致しないサンプルを使うと、安全なスキップ経路を確認できます。この警告は、ユーザーがすでにワークフローの作成を依頼している場合に、二度目の承認を求めるものではありません。破壊的、高コスト、機密性が高い、またはその他予想外のテスト影響がある場合にのみ、先に確認を求めます。
  • テスト結果が確認済みの計画と一致するまで、ソースを修正して再テストします。テスト済みのソースのみを公開します。未テストのバージョンを有効なままにしないでください。
  • トリガーの登録は非同期で行われ、失敗が通知されないことがあります。トリガー付きワークフローの公開後、サーフェスからワークフローの状態を読み戻し、トリガーが有効で、ワークフローが意図した有効状態になるまでポーリングします。ワークフローが有効なままでも、登録に失敗した場合はデプロイ失敗として扱います。ツールの結果で両方を確認するまで、成功を報告しないでください。有効化を推測したり、断言したりしてはいけません。読み戻しの過渡状態(unclaimed/pending)は、さらにポーリングする必要があるだけの場合があります。
  • デプロイメントは、単に enabled かどうかではなく、確認済みの開始モードに照らして検証します。トリガーなしのワークフローも enabled: true として読み戻されるため、enabled だけの確認では、トリガーが必要だったのに設定されていないワークフローを見逃してしまいます。ワークフローの読み戻しにおけるトリガーの実際の有無を正とします。trigger モードのワークフローではトリガーが設定されている必要があり、manual モードのワークフローでは設定されていてはいけません。不一致があれば、成功を報告せず、ユーザーと調整します。
  • トリガーに webhook_url がある場合は、ユーザーに提示します。これは外部サービス向けの受信用 URL であり、ワークフロー単位のトリガー/呼び出し URL とは異なり、共有を想定しています。ほとんどのトリガーには webhook_url がありませんが、これは正常です。受信用フックトリガーが有効なのに webhook_url が表示されない場合は、URL を捏造せず、エディターリンクからトリガーのステップを確認するようユーザーに案内します。ユーザーが明示的に求めない限り、認証済みアカウントとしてワークフローを呼び出すワークフロー単位のトリガー URL は表示しないでください。

最後に、次の内容を報告します。

  • ワークフロー名と ID。
  • テストに合格したかどうか。
  • 有効になっているかどうか。
  • プライベートか、アカウント全体に公開されているか。
  • 確認済みの開始モード:trigger(アプリトリガーまたは受信用フックトリガー)か manual(オンデマンドのみ)か、および開始モードのゲートでデプロイメントがそのモードと一致することを確認した旨。
  • トリガーの webhook_url(存在する場合)。
  • エディターリンク:https://zapier.com/workflow/<workflow-id>。

失敗の兆候

  • 既存のアクションで action-not-found が報告される:ワークフローで誤った actionType が使われている可能性があります。アクションを調べ、検出した正確な read、search、または write のタイプを使用してください。
  • undefined から fetch または接続を読み取る際に呼び出しが失敗する:ソースで ctx.zapier、ctx.connection、または ctx.connections が使われています。モジュールスコープの createZapierSdk() クライアントと接続エイリアスに置き換えてください。
  • トリガー付きワークフローが公開後に無効になる:非同期のトリガー登録に失敗しています。selected_api、アクションキー、params、authentication_id がすべて、検出した一つのトリガー結果から取得されていることを確認してから、再公開してください。

制約

  • ソースに認証情報、トークン、シークレットを埋め込まないでください。外部の接続エイリアスを使用し、アクションの入力にはスキーマで公開され、検出された参照のみを使用してください。
  • アプリキー、アクションキー、アクションの種類、フィールド名、トリガー値、バージョン、接続 ID を決して作り出さないでください。
  • 副作用が発生する可能性のある実行、書き込みプローブ、公開を行う前に、必ず確認してください。
  • 公開エラーを読んで修正し、推測で回避しないでください。

SDK CLI の仕組み:テスト、デプロイ、検証

フェーズ 5(CLI):ワークフローを作成し、ドラフトをステージングしてテストする

まず非公開のワークフローコンテナーを作成し、次にそのドラフトを作成します。コンテナーは無効の状態で、公開済みバージョンがない状態から始まります。レスポンスからワークフロー ID とドラフト ID を取得してください。

zapier-sdk --stability experimental create-workflow "<workflow-name>" --description "<brief>" --private --json
zapier-sdk --stability experimental create-workflow-draft <workflow-id> --json

プロジェクトディレクトリを走査して source_files を作成し、すべてのファイルを含め、どのファイルもひそかに欠落しないようにしてください。

WF_DIR="<working-directory>/<kebab-case-workflow-name>"

SOURCE_FILES="$(cd "$WF_DIR" && find . -type f ! -name package.json ! -path './node_modules/*' -print \
  | sed 's|^\./||' \
  | while IFS= read -r f; do jq -n --arg k "$f" --argjson v "$(jq -Rs . < "$f")" '{($k): $v}'; done \
  | jq -s 'add')"

これにより、各ファイルはプロジェクトからの相対パスでキー付けされ(lib/format.ts は lib/format.ts のままです)、末尾の改行も含めてバイト列がそのまま再現されます。手作業で {"workflow.ts": …} のような単一キーのマップを作成しないでください。ファイルが欠落したマップは、正常に機能したマップと見分けがつかず、その後の公開によってそのファイルがワークフローから削除されます。

zapier-sdk --stability experimental update-workflow-draft <workflow-id> <draft-id> "$SOURCE_FILES" \
  --dependencies '{"@zapier/zapier-sdk":"latest","zod":"4.3.6"}' \
  --connections '{"slack_work":{"connectionId":"12345678"}}' \
  --app-versions '{"SlackCLIAPI":{"implementationName":"SlackCLIAPI","version":"1.42.1"}}' \
  --trigger '<trigger config JSON, for triggered workflows>' \
  --json

確認済みの手動ワークフローの場合は、--trigger を --manual に置き換えてください。トリガーを使うワークフローの場合は、設定を単一の JSON --trigger オブジェクトとして渡してください。使用しない --app-versions と --connections のオプションは省略し、例の値は検出した値に置き換えてください。各接続エイリアスは、connectionId を含むオブジェクトに対応付けます。

古い --trigger-app、--trigger-action、--trigger-auth、--trigger-params フラグは使用しないでください。現在のトリガー指定方法では、単一の JSON --trigger オブジェクトを使います。

アプリの実装/バージョン情報は、list-apps、get-app、list-actions、トリガー/アクションの結果メタデータなど、SDK の検出結果から取得してください。実装/バージョンのバインディングが公開されていない場合は、推測せずに --app-versions を省略してください。「if needed」のようなプレースホルダーテキストを CLI に渡さないでください。

ドラフトを更新する前に、そのフラグがフェーズ 3 で確認した開始モードと一致していることを確認してください。Start mode: trigger の場合は --trigger を渡し、--manual は渡しません。Start mode: manual の場合は --manual を渡し、--trigger は渡しません。どちらか一方だけを渡してください。バージョンはトリガー付き、または manual: true のいずれかであり、両方が同時に指定されることはありません。プラットフォームは両方の指定を拒否します。プラットフォームでは manual 入力が任意扱いですが、開始モードの判断は必須です。このフラグは書き込み専用で必須フィールドではなく、適用はアカウント単位かつフラグで制御されるため、任意扱いなのは段階的ロールアウトの名残であり、判断を省略してよいという意味ではありません。手動にするのは意図的な選択であり、トリガーの設定が難しい場合の代替手段ではありません。ユーザーがトリガーを求めている場合、その設定を構築できないことは解決すべきブロッカーであり、手動に切り替える理由にはなりません。

保存済みのドラフトを読み込み、draft_revision を取得してから、そのリビジョンを実行してください。

zapier-sdk --stability experimental get-workflow-draft <workflow-id> <draft-id> --json
zapier-sdk --stability experimental run-workflow-draft <workflow-id> <draft-id> <draft-revision> \
  --input '<JSON matching input schema>' \
  --json

ワークフローに入力がない場合は、--input を省略してください。このコマンドは未公開ドラフトの実行をワークフローに関連付けて開始し、実行が完了する前に返ります。

返された id を取得し、get-workflow-run <run-id> --json をポーリングしてください。次の条件を満たした場合、テストは成功です。

  • status が "finished"、output が確認済みの計画と一致し、error が null で、トップレベルの errors が空であること。
  • kind が "draft" であり、workflow_id、workflow_draft_id、draft_revision がテストしたドラフトと一致すること。

テストが失敗した場合は、ソースを修正し、完全なマップを再構築して、同じドラフトを更新し、新しいリビジョンをテストしてください。リビジョンの競合が発生した場合は、ドラフトを再読み込みして変更を調整してから、再度テストしてください。

Phase 6 (CLI):テスト済みのドラフトを公開する

テストに合格した後にのみ、テスト済みのリビジョンを使用して公開し、同時編集によって未テストの内容が公開されないようにします:

zapier-sdk --stability experimental publish-workflow-draft <workflow-id> <draft-id> \
  --draft-revision <tested-draft-revision> \
  --enabled \
  --json

公開するとドラフトが消費され、変更できないワークフローバージョンが作成されます。リビジョンの競合が発生した場合は、ドラフトを再読み込みし、現在のリビジョンをテストしてから公開してください。ユーザーが公開前に Zapier エディターで確認したい場合は、テスト済みのドラフトを未公開のままにして、エディターのリンクを渡してください。ユーザーの許可を得てから公開します。未公開の作業を破棄するのは、明示的な確認があった場合に限ります。

Phase 7 (CLI):検証する

get-workflow、list-workflow-versions、get-workflow-version で読み戻します。トリガーを使用するワークフローでは、get-workflow を再読み込みし(ポーリングします。クレームは非同期です)、enabled: true を確認します。--enabled を指定したにもかかわらず false の場合、トリガーのクレームに失敗しています。selected_api、アクションキー、params、authentication_id がすべて、検出した同一のトリガー結果に由来することを確認してください(params の形式が誤っていれば、公開時点ですでに失敗しています)。

enabled だけでなく、Phase 3 で確認した開始モードに基づいて判定します:

  • Start mode: trigger の場合、get-workflow で enabled: true と空でない triggers[] の両方が必要です。triggers[] が空の場合、トリガーが削除されたか、送信されていません。ワークフローが完了したと報告しないでください。
  • Start mode: manual の場合、triggers[] は空である必要があります。triggers[] が空でない場合は不一致です。作業を止め、ユーザーと確認して解決してください。

この判定では triggers[] が基準です。書き込み専用の manual フラグは、get-workflow にもバージョンの読み戻しにも表示されないため、そこにあるかどうかを調べないでください。

catch-hook トリガーが有効なのに、その triggers[] エントリに details.webhook_url がない場合、インストールされている @zapier/zapier-sdk がそのフィールドに対応する前のバージョンである可能性があります。workflows-doctor を実行して更新を確認し、更新されるまではエディターリンクからトリガーステップを開くようユーザーに案内してください。

(副作用を確認した後に)手動で実行するには、trigger-workflow <workflow-id> --input '<JSON>' --json を実行します。実行 ID より先にトリガー ID が返された場合は、get-trigger-run <trigger-id> --json でつなぎ、その後 list-workflow-runs/get-workflow-run を確認してください。

コメント