mcpField
F
fcode-factorial-actions

fcode-factorial-actions

github.com/factorialco開発1146 回インストール1 日前に更新
リポジトリ

fcode-factorial-actions について

fcode-factorial-actionsは、プロセスをFactorial Actionsとして設定するためのスキルです。同じ実装をFactorial内の複数の入口から呼び出せます。設定契約、実行ポリシー、フォーム、UIボタン、ライフサイクルを説明し、Factorial Oneのツール実行にはまだ対応していません。

主な機能

  1. 01factorial設定ブロックでアクションを構成
  2. 02UIボタンやフォームからアクションを公開
  3. 03呼び出し前にrequiredPoliciesを適用
  4. 04同期・非同期の結果処理を設定
  5. 05Factorial Oneのツール契約を説明

活用シーン

  1. 01Factorialのボタンやフォームから呼び出すプロセスの設定
  2. 02必要なポリシーを持つユーザーに実行を制限
  3. 03ファイルアップロードと公開フォームの設定
  4. 04将来のFactorial One対応に向けたagentToolメタデータの準備

インストール

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

$npx skills add https://github.com/factorialco/factorial-code-skills --skill fcode-factorial-actions

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

詳細

Factorial Code — Factorial アクション

Factorial アクションとは、アプリをインストールした顧客が、Factorial Code の存在を知らなくてもFactorial 内から利用できるプロセスです。1つのプロセスが1つのアクションに相当し、同じアクションを複数のエントリーポイントから同時に公開できます。Factorial UI のボタン、フォーム、Factorial One ツール、バックエンドジョブなどです。エントリーポイントにかかわらず、Factorial はプロセスにパラメーターを渡し、要求された場合は結果を待ちます。プロセスはどのエントリーポイントから開始されたかを認識しないため、1つの実装ですべてに対応できます。

アクションに必要なものはすべて、1つの設定ブロック factorial に含まれます。コンソールのプロセスページにあるFactorial からのトリガーセクション、または processes/<slug>/metadata.json の factorial キーです(fcode pull / fcode push で相互に反映されます。フィールドのリファレンスは fcode-cli を参照してください)。

現在利用できる機能と、今後追加される機能

現在利用可能今後追加予定
コンソールと metadata.json の factorial ブロック、および API の settings.factorialFactorial One ツール:アシスタントが agentTool コントラクトを読み取り、プロセスを呼び出す機能
Factorial が呼び出すアクション API:会社のアクション一覧の取得、アクションのフォームスキーマの読み取り、アクションの呼び出し、アップロード許可の発行、アプリのインストール前にそのアプリが宣言したアクションの一覧の取得
すべての呼び出しで、実行前に requiredPolicies を適用
uiTrigger:ボタンはこのコントラクトを使ってアクションを一覧表示し、実行します。プロセスのスラッグはブラウザーに渡らず、不透明な action_id で指定されます
form:Factorial から開いたフォームは Factorial のバックエンド経由で送信されます。バックエンドはユーザーの ID を引き継ぎ、信頼されたコンテキストを注入します
フォームには Factorial 認証が必要です。ただし form.public で認証を不要にできます。これはフォームのエンドポイントが確認する認証モードの切り替え設定です
Factorial Code ストレージに許可を使って直接アップロードされるファイルパラメーター(x-fcode-file)。送信内容には fcode.storage:// パスが含まれます
?locale= の一覧で fcode.i18n("key") トークンを使ってローカライズされる uiTrigger.label
プロセスの form.appRole から派生するか、指定がない場合は予約済みスラッグから派生し、コンソールでタグ付けされる lifecycleRole

つまり、現在は uiTrigger、form、requiredPolicies、awaitResult が機能します。agentTool と backend は保存され、利用可能ですが、ツールのコントラクトを読み取るアシスタントはまだありません。アクションが対応可能な状態になるよう、今のうちに設定しておいてください。

注意点

  • enabled はマスタースイッチです。 これが false の間は、各エントリーポイントの enabled の設定にかかわらず、以下の内容は何も公開されません。再び有効にすると、エントリーポイントは変更前の状態に戻ります。
  • awaitResult のデフォルトは true(同期)です。 従来の uiTrigger は、実行結果を待たずに処理を開始する設定がデフォルトでした。ミラーは factorial.awaitResult を uiTrigger.awaitResult にコピーするため、ボタンを factorial ブロックに移すと、"awaitResult": false を指定しない限り、同期処理になります。同期アクションは約 50 秒の制限内に収めてください(fcode-ui-triggers)。
  • requiredPolicies は適用されますが、キーは自由入力です。 Factorial は処理の実行前にこれらを確認しますが、キーが存在するかどうかは確認しません。認識されないキーは許可されないだけなので、それを含む AND グループ全体が失敗します。つまり、タイプミスによってアクションが許可されることはなく、拒否されるだけです。キーは Factorial のポリシーカタログから選び、長いグループを 1 つ作るより、短い代替グループを複数用意してください。
  • ポリシーがなければ、誰でも利用できます。 空のリスト、またはリスト自体がない場合は、エントリーポイントにアクセスできる人なら誰でもアクションを実行できます。残る制限は、エントリーポイント自体のゲート(ボタンの場所に応じたアクセス許可、インストール済みアプリなど)だけです。空でないリスト内のグループが空の場合、「すべて許可」とは扱われず、そのグループは削除されるため、[["a"], []] では引き続き a が必要です。
  • 翻訳可能なのは uiTrigger.label だけです。 これはユーザーが目にする唯一のテキストなので、fcode.i18n("key") トークンを使用します(fcode-i18n)。agentTool のテキストはモデル向けです。プレーンテキストで 1 つの言語のみを使用し、ユーザーには表示されません。プロセス自体の name と description は、人間とマーケットプレイスのカード向けです。このブロックには独自のタイトルはありません。
  • effect を設定しない場合は、DESTRUCTIVE として扱われます。 READ または WRITE を指定するまで、すべてのツールは安全側に倒して失敗し(承認が必要となり、「元に戻せない」という警告が表示されます)、実行されません。
  • 4 つのライフサイクルスラッグは予約済みです。 install、settings、uninstall、sync はブロックに関係なく Factorial によって特別な意味で扱われます。通常のアクションには使用しないでください。
  • デフォルト値は省略してください。 fcode pull は、awaitResult が true の場合、requiredPolicies が空の場合、form.public と form.appTool が false の場合、agentTool のテキストが未設定またはリストが空の場合、および enabled が false のサブブロックを省略します。Factorial に公開されていないプロセスには、factorial キー自体がありません。部分更新では、指定されていないフィールドは変更されません。
  • 従来の form / uiTrigger キーも引き続きラウンドトリップできます。 ファイルに両方が含まれている場合、fcode push は factorial を送信し、残りはミラーに更新させます。factorial(以下)を記述することをおすすめします。

factorial ブロックの各フィールド

{
  "factorial": {
    "enabled": true,
    "awaitResult": false,
    "requiredPolicies": [["company.manage_timeoff"], ["company.admin"]],
    "uiTrigger": { "enabled": true, "locationId": "calendar.header.admin", "label": "fcode.i18n(\"acme.approve.button\")", "icon": "Bell" },
    "form": { "enabled": true, "public": false, "appTool": true },
    "agentTool": { "enabled": true, "description": "…", "effect": "WRITE" },
    "backend": { "enabled": true }
  }
}
フィールド型/デフォルト値意味
enabledboolean、false以下のすべてのエントリーポイントを有効にするマスタースイッチです
awaitResultboolean、truetrue:Factorial は待機し、プロセスの戻り値を変更せずに受け取ります(fcode-ui-triggers)。false:Factorial が把握するのは実行が開始されたことだけです。プロセス自身が結果を報告します(FactorialClient、通知)。インポートや一括処理では false を使用します
requiredPoliciesstring[][]、[]ユーザーが保有している必要がある Factorial ポリシーキーのAND グループの ORです。[["a","b"],["c"]] は (a と b) または c を意味します。空の場合、エントリーポイントに到達したユーザーなら誰でも利用できます。コンソールでは、1 行に 1 つの選択肢を入力し、グループ内のキーはカンマで区切ります
uiTrigger.enabledbooleanFactorial 内でアクションをボタンとして表示します
uiTrigger.locationIdstringボタンを表示する Factorial UI の場所です(例:calendar.header.admin)。有効にする場合は必須で、200 文字以下です。ページを担当する Factorial チームから提供されます。場所の仕様については fcode-ui-triggers を参照してください
uiTrigger.labelstringボタンのテキストです。唯一の i18n フィールドです。プレーンテキスト、または fcode.i18n("key") トークンを指定します
uiTrigger.iconstring許可リストに登録されたアイコン名です(fcode-ui-triggers)。テキストのみのボタンにする場合は省略します
form.enabledbooleanパラメーターをフォームとして公開します(fcode-forms)。Forms フラグと同じスイッチで、クォータも共通です
form.appToolboolean、falseFactorial の App 自体のページで、その App がユーザーに実行させる機能の 1 つとして、会社のユーザーにフォームを提供します。たとえば「同期の問題を報告」や「今すぐ同期」フォームです。App 自身が開くフォームでは false のままにします。これはブロック内で、従来の form.appRole: USER_FACING_FORM に対応する名前であり、両者は同じ値に保たれます
form.publicboolean、falseFactorial アカウントがなくても、リンクを持っている人なら誰でもフォームを利用できるようにします。従来の form.authMode を切り替えるスイッチで、フォームのエンドポイントがこれを適用します。両者は同じ値に保たれます。有効にすると NONE、無効にすると FACTORIAL が書き込まれます。Factorial 外の人を対象とするフォームでない限り、無効のままにしてください。有効にすると、呼び出し元は認証されません
agentTool.enabledbooleanFactorial One アシスタントがプロセスをツールとして呼び出せるようにします。サブブロックの残りの項目がツールの仕様です(次のセクションを参照)
backend.enabledbooleanFactorial のバックエンドジョブが、ユーザーを介さずにプロセスを実行できるようにします

Factorial One のツール仕様(agentTool)

パラメータースキーマは、アシスタントにツールが受け取るものを伝えます。このブロックは、ツールの目的を伝えます。プレーンテキストで、i18n は使用しません。

フィールド型モデルにとっての利点
descriptionstringツールが行うことを 1~2 文で説明します。操作対象のオブジェクトと結果を明記します。ユーザーのリクエストとの照合に使われます
effectREAD | WRITE | DESTRUCTIVEREAD は確認なしで実行されます。WRITE は承認を求めます。DESTRUCTIVE は承認を求め、取り消せないことを警告します。未設定の場合 ⇒ DESTRUCTIVE
whenToUsestringユーザーが尋ねるときの言い方で、ツールを使う状況を記述します
whenNotToUsestring[]似ていても一致しない状況を項目ごとに記述し、代わりに使う隣接ツールの名前を示します
preconditionsstring[]呼び出し前に満たされている必要がある条件を項目ごとに記述します。条件が満たされていない場合、アシスタントは呼び出して失敗するのではなく、確認するかユーザーに尋ねます
doesNotDostring[]ユーザーが行われると想定する可能性があるものの、ツールでは発生しない副作用を項目ごとに記述します
degradationstring部分的な成功時の動作を記述します。実行される処理、スキップされる処理、および結果での示し方を説明します
simulatesForstringこのプロセスがプレビューするプロセスのスラッグ(ドライラン対象)です。自由入力テキストで、まだ検証されません
適切なコントラクトテキストを書く
  • 平易な言葉で、i18n は使わず、1 つの言語で書きます。 画面向けではなく、英語を読むモデル向けに書いてください。ここでは fcode.i18n(...) トークンを絶対に使わないでください。
  • description:対象のオブジェクト+結果。 「チームの保留中の休暇申請をすべて承認する」は、「休暇ツール」より適切です。
  • whenToUse には 1 つの状況を書きます。 「または」が必要なら、ツールを 2 つに分けるべきかもしれません。ユーザーが尋ねるときの言い方で表現してください。
  • whenNotToUse では近接するツールを挙げます。 「ユーザーが 1 件の申請の承認を希望している場合:approve-timeoff-request を使用します。」各項目には状況を 1 つだけ記載してください。
  • preconditions は確認可能な事実(「チームに保留中の申請が少なくとも 1 件ある」)であり、アドバイスではありません。
  • doesNotDo には、ユーザーが実行されると思いそうなことを列挙します。 通知、付随する書き込み、取り消しなど、実行されないことを明記し、アシスタントが不足している手順を提案できるようにしてください。
  • degradation には部分的な結果を記述します。 そうすれば、アシスタントは失敗として報告せずに、その結果を説明できます。
  • ドライランのプロセスは、simulatesFor で実際のプロセスを示し、自身は READ にします。 実際のプロセスは WRITE または DESTRUCTIVE です。

予約済みライフサイクルスラッグ

スラッグ役割プラットフォームの動作
install会社が App をインストールするときに Factorial が表示するフォームlifecycleRole: INSTALL を導出します
settingsApp をインストールした会社が App を設定するために使うフォームSETTINGS
uninstall会社が App を削除するときに実行されますUNINSTALL
syncintegrations-framework App の同期プロセスSYNC

lifecycleRole は読み取り専用です。コンソールにはプロセス一覧とプロセスヘッダーに色付きの Install / Settings / Uninstall / Sync タグが表示され、CLI と API はその値を報告します。これに書き込まれることはありません(metadata.json に含まれず、コンテンツハッシュにも含まれません)。install、settings、uninstall はマーケットプレイスのライフサイクルフォームであり、他のフォームと同様に factorial.form.enabled を受け取ります。再度開かれた install/settings フォームの事前レンダリングパターンについては、fcode-forms を参照してください。

この値の導出元は、プロセスで宣言された form.appRole です。宣言されていない場合に限り、予約済みスラッグが使われます。この順序である必要があります。マーケットプレイスのカタログでは、以前から appRole をキーにこれらのフォームを識別しており、本番環境の Apps では、適切なロールを設定したうえで datev-install、net-empregos-install などの名前をフォームに付けています。スラッグだけをキーにすると、これらの App には install、settings、uninstall フォームがまったくなくなってしまいます。また、設定待ちのインストールに提示されるのはライフサイクルフォームのみなので、インストールを完了できなくなります。

フォールバックは永続的です。 appRole に廃止予定日はなく、必須の移行作業もありません。新しいプロセスでは、より分かりやすい名前である予約済みスラッグを使ってください。ロールを宣言している既存のプロセスは、変更せずに動作します。

既存の App で予約済みスラッグを採用する

任意の対応で、より分かりやすい名前にする場合にのみ行う価値があります。fcode push はローカルのプロセスとリモートのプロセスをスラッグで照合するため、プロセスフォルダーの名前を変更しても、プロセスの名前は変わりません。代わりに 2 つ目のプロセスが作成され、最初のプロセスはワークスペースに残ります。同じ push で古いプロセスを廃止してください。

  1. 予約済みスラッグでプロセスを作成し、ソースと factorial ブロックを移します。
  2. 同じ push で、古いプロセスの factorial.form.enabled: false を設定します。両方を有効にしたままにしないでください。2 つのプロセスが 1 つのライフサイクルスロットを要求した場合、辞書順で最初のスラッグが優先されます。新しい名前(install < net-empregos-install)だけでなく、古い名前(datev-install < install)が優先される可能性も同じようにあります。この競合は、App のカタログエントリーに duplicate_role_warnings の項目として報告されます。
  3. fcode push を実行します。

アクション ID はスラッグから導出されるため、変更されます。永続化されるものはないため、インストールとその設定には影響しませんが、ブックマークしたフォーム URL は解決できなくなります。

パラメーター:Factorial との契約

エントリーポイントにかかわらず、Factorial から送信される内容はプロセスの parametersSchema.json(fcode-json-schema)で定義されます。フォームはこれを表示し、 アシスタントはツールが受け取る内容を把握するためにこれを読み取り、Factorial はこれに照らして検証します。 すべてのパラメーターに title と description を指定し、必須のものを required に列挙してください。また、スキーマの変更はすべて、Factorial から 渡される可能性のある内容の変更として扱ってください。UI トリガーが挿入する信頼済みキー(company_id、 triggered_from_location、access_id)については、fcode-ui-triggers に記載されています。

form と uiTrigger からの移行

factorial ブロックは、フォームフラグ(form)とUI トリガーボタン(uiTrigger)に 置き換わるものです。どちらも現時点では引き続き利用でき、プラットフォームによって相互に同期されます。 どちらを編集しても、もう一方が更新され、最後に書き込まれた値が優先されます。

factorial に書き込む内容……で更新されるレガシー設定
enabled && uiTrigger.enableduiTrigger.enabled
uiTrigger.locationId、uiTrigger.icon、uiTrigger.labeluiTrigger の同じキー
awaitResultuiTrigger.awaitResult
enabled && form.enabledform.enabled
form.appToolform.appRole = USER_FACING_FORM

レガシーブロックに書き込んだ場合も、同じフィールドが逆方向に同期されます。また、いずれかのエントリーポイントが有効になると、 factorial.enabled も有効になります。

form.appRole は、このブロックが一部だけ管理する唯一のレガシーフィールドです。4 つの値のうち、 USER_FACING_FORM が form.appTool に相当します。フラグをオンにするとこの値が設定され、オフにすると、この値が設定されていた場合に限り解除されます。 appTool について何も指定しない書き込みでは、ロールは変更されません。そのため、このフラグが存在する前に作成されたファイルは、プッシュ時もロールを維持します。 CLI は appRole を読み取り、それに合わせてフラグを送信します。

INSTALL/SETTINGS/UNINSTALL はこの仕組みの対象外です。このブロックにはそれらを切り替える設定がないため、 form.appRole に残り、lifecycleRole はまずそこを参照します。これらは引き続きそこに記述してください。予約済みスラッグは、 プロセスがロールを宣言していない場合の代替手段であり、移行が必要な置き換え先ではありません。

factorial を優先してください:新しいプロセスではこれを記述し、古い metadata.json を編集する場合は、 uiTrigger を編集するのではなく、設定を factorial に移してください。

記述例 — SILTRA FIE インポート(ドライラン+適用)

siltra-integration-app をもとにしています。fie-import は、企業が SILTRA からダウンロードする .msj ファイルを読み取り、 Factorial で作成、関連付け、または終了する病欠情報を報告しますが、書き込みは行いません。fie-import-apply は、 バックグラウンドで書き込みを行います。

processes/fie-import/metadata.json:

{
  "name": "FIE Import",
  "description": "Reads the .msj file the company downloads from SILTRA and shows what importing it would change in Factorial. Writes nothing — the import only happens after confirmation.",
  "tags": ["inbound", "siltra", "fie"],
  "factorial": {
    "enabled": true,
    "requiredPolicies": [["company.manage_timeoff"], ["company.admin"]],
    "uiTrigger": {
      "enabled": true,
      "locationId": "calendar.header.admin",
      "label": "fcode.i18n(\"calendar.import.fie.button\")",
      "icon": "Upload"
    },
    "form": { "enabled": true },
    "agentTool": {
      "enabled": true,
      "description": "Reads a SILTRA FIE transmission (.msj) and reports which sick leaves it would create, link or close in Factorial, and which events it would leave out and why. It writes nothing.",
      "effect": "READ",
      "whenToUse": "The user has downloaded a FIE file from SILTRA and wants to know what importing it would change before anything is written.",
      "whenNotToUse": [
        "The user has already reviewed the report and wants the leaves written: use fie-import-apply.",
        "The file is not a SILTRA .msj transmission."
      ],
      "preconditions": ["The .msj file has been uploaded and its storage reference is passed as msj_file."],
      "doesNotDo": ["It does not create, change or close any leave.", "It does not notify employees or managers."],
      "degradation": "If Factorial cannot be consulted, the report still lists every event in the file, marked as not compared against Factorial.",
      "simulatesFor": "fie-import-apply"
    }
  }
}

processes/fie-import-apply/metadata.json — ボタンもフォームもなく、非同期で実行される、ペアの書き込み側です:

{
  "name": "FIE Import — apply",
  "tags": ["inbound", "siltra", "fie"],
  "factorial": {
    "enabled": true,
    "awaitResult": false,
    "requiredPolicies": [["company.manage_timeoff"], ["company.admin"]],
    "agentTool": {
      "enabled": true,
      "description": "Writes the sick leaves a SILTRA FIE transmission describes into Factorial: creates, links or closes them.",
      "effect": "WRITE",
      "whenToUse": "The user has seen the fie-import report for a file and asks to apply it.",
      "whenNotToUse": ["The user only wants to know what the file would change: use fie-import."],
      "preconditions": ["fie-import has reported on this same file and the user confirmed the result."],
      "doesNotDo": ["It does not send SILTRA anything back.", "It does not notify employees."],
      "degradation": "Leaves that fail to write are skipped and listed in the result; the rest are applied."
    },
    "backend": { "enabled": true }
  }
}

ポリシーキーは例示用です。実際のキーは Factorial のポリシーカタログから取得してください。 通常どおりパラメーターを読み取ります(fcode.context.parameters.msj_file、 fcode.storage://… 参照 — fcode-forms)。

リリース前のチェックリスト

  1. factorial.enabled をオンにし、公開するエントリーポイントだけを有効にします。
  2. awaitResult を明示的に決定します。時間のかかる処理では false にし、同期アクションは、 実行されるエントリーポイントが読み取れる形式を返します。
  3. requiredPolicies のキーは推測せず Factorial のカタログからコピーします。あるいは、 意図的に空にして、そのアクションに到達できる人なら誰でも利用できる状態にします。
  4. agentTool:effect を設定し、whenNotToUse に関連するツールを記載します。ドライランでは、 simulatesFor に実際のプロセスを指定します。
  5. 通常のアクションで install、settings、uninstall、sync をスラッグとして使用していないことを確認します。 スキーマには title、description、required を指定します。

コメント