fcode-factorial-actions について
fcode-factorial-actionsは、プロセスをFactorial Actionsとして設定するためのスキルです。同じ実装をFactorial内の複数の入口から呼び出せます。設定契約、実行ポリシー、フォーム、UIボタン、ライフサイクルを説明し、Factorial Oneのツール実行にはまだ対応していません。
主な機能
- 01factorial設定ブロックでアクションを構成
- 02UIボタンやフォームからアクションを公開
- 03呼び出し前にrequiredPoliciesを適用
- 04同期・非同期の結果処理を設定
- 05Factorial Oneのツール契約を説明
活用シーン
- 01Factorialのボタンやフォームから呼び出すプロセスの設定
- 02必要なポリシーを持つユーザーに実行を制限
- 03ファイルアップロードと公開フォームの設定
- 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.factorial | Factorial 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 }
}
}
| フィールド | 型/デフォルト値 | 意味 |
|---|---|---|
enabled | boolean、false | 以下のすべてのエントリーポイントを有効にするマスタースイッチです |
awaitResult | boolean、true | true:Factorial は待機し、プロセスの戻り値を変更せずに受け取ります(fcode-ui-triggers)。false:Factorial が把握するのは実行が開始されたことだけです。プロセス自身が結果を報告します(FactorialClient、通知)。インポートや一括処理では false を使用します |
requiredPolicies | string[][]、[] | ユーザーが保有している必要がある Factorial ポリシーキーのAND グループの ORです。[["a","b"],["c"]] は (a と b) または c を意味します。空の場合、エントリーポイントに到達したユーザーなら誰でも利用できます。コンソールでは、1 行に 1 つの選択肢を入力し、グループ内のキーはカンマで区切ります |
uiTrigger.enabled | boolean | Factorial 内でアクションをボタンとして表示します |
uiTrigger.locationId | string | ボタンを表示する Factorial UI の場所です(例:calendar.header.admin)。有効にする場合は必須で、200 文字以下です。ページを担当する Factorial チームから提供されます。場所の仕様については fcode-ui-triggers を参照してください |
uiTrigger.label | string | ボタンのテキストです。唯一の i18n フィールドです。プレーンテキスト、または fcode.i18n("key") トークンを指定します |
uiTrigger.icon | string | 許可リストに登録されたアイコン名です(fcode-ui-triggers)。テキストのみのボタンにする場合は省略します |
form.enabled | boolean | パラメーターをフォームとして公開します(fcode-forms)。Forms フラグと同じスイッチで、クォータも共通です |
form.appTool | boolean、false | Factorial の App 自体のページで、その App がユーザーに実行させる機能の 1 つとして、会社のユーザーにフォームを提供します。たとえば「同期の問題を報告」や「今すぐ同期」フォームです。App 自身が開くフォームでは false のままにします。これはブロック内で、従来の form.appRole: USER_FACING_FORM に対応する名前であり、両者は同じ値に保たれます |
form.public | boolean、false | Factorial アカウントがなくても、リンクを持っている人なら誰でもフォームを利用できるようにします。従来の form.authMode を切り替えるスイッチで、フォームのエンドポイントがこれを適用します。両者は同じ値に保たれます。有効にすると NONE、無効にすると FACTORIAL が書き込まれます。Factorial 外の人を対象とするフォームでない限り、無効のままにしてください。有効にすると、呼び出し元は認証されません |
agentTool.enabled | boolean | Factorial One アシスタントがプロセスをツールとして呼び出せるようにします。サブブロックの残りの項目がツールの仕様です(次のセクションを参照) |
backend.enabled | boolean | Factorial のバックエンドジョブが、ユーザーを介さずにプロセスを実行できるようにします |
Factorial One のツール仕様(agentTool)
パラメータースキーマは、アシスタントにツールが受け取るものを伝えます。このブロックは、ツールの目的を伝えます。プレーンテキストで、i18n は使用しません。
| フィールド | 型 | モデルにとっての利点 |
|---|---|---|
description | string | ツールが行うことを 1~2 文で説明します。操作対象のオブジェクトと結果を明記します。ユーザーのリクエストとの照合に使われます |
effect | READ | WRITE | DESTRUCTIVE | READ は確認なしで実行されます。WRITE は承認を求めます。DESTRUCTIVE は承認を求め、取り消せないことを警告します。未設定の場合 ⇒ DESTRUCTIVE |
whenToUse | string | ユーザーが尋ねるときの言い方で、ツールを使う状況を記述します |
whenNotToUse | string[] | 似ていても一致しない状況を項目ごとに記述し、代わりに使う隣接ツールの名前を示します |
preconditions | string[] | 呼び出し前に満たされている必要がある条件を項目ごとに記述します。条件が満たされていない場合、アシスタントは呼び出して失敗するのではなく、確認するかユーザーに尋ねます |
doesNotDo | string[] | ユーザーが行われると想定する可能性があるものの、ツールでは発生しない副作用を項目ごとに記述します |
degradation | string | 部分的な成功時の動作を記述します。実行される処理、スキップされる処理、および結果での示し方を説明します |
simulatesFor | string | このプロセスがプレビューするプロセスのスラッグ(ドライラン対象)です。自由入力テキストで、まだ検証されません |
適切なコントラクトテキストを書く
- 平易な言葉で、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 を導出します |
settings | App をインストールした会社が App を設定するために使うフォーム | SETTINGS |
uninstall | 会社が App を削除するときに実行されます | UNINSTALL |
sync | integrations-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 で古いプロセスを廃止してください。
- 予約済みスラッグでプロセスを作成し、ソースと
factorialブロックを移します。 - 同じ push で、古いプロセスの
factorial.form.enabled: falseを設定します。両方を有効にしたままにしないでください。2 つのプロセスが 1 つのライフサイクルスロットを要求した場合、辞書順で最初のスラッグが優先されます。新しい名前(install<net-empregos-install)だけでなく、古い名前(datev-install<install)が優先される可能性も同じようにあります。この競合は、App のカタログエントリーにduplicate_role_warningsの項目として報告されます。 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.enabled | uiTrigger.enabled |
uiTrigger.locationId、uiTrigger.icon、uiTrigger.label | uiTrigger の同じキー |
awaitResult | uiTrigger.awaitResult |
enabled && form.enabled | form.enabled |
form.appTool | form.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)。
リリース前のチェックリスト
factorial.enabledをオンにし、公開するエントリーポイントだけを有効にします。awaitResultを明示的に決定します。時間のかかる処理ではfalseにし、同期アクションは、 実行されるエントリーポイントが読み取れる形式を返します。requiredPoliciesのキーは推測せず Factorial のカタログからコピーします。あるいは、 意図的に空にして、そのアクションに到達できる人なら誰でも利用できる状態にします。agentTool:effectを設定し、whenNotToUseに関連するツールを記載します。ドライランでは、simulatesForに実際のプロセスを指定します。- 通常のアクションで
install、settings、uninstall、syncをスラッグとして使用していないことを確認します。 スキーマにはtitle、description、requiredを指定します。