Skip to content

プラグイン

Triggerfishプラグインはカスタムツールでエージェントを拡張します。プラグインはマニフェスト、 ツール定義、エグゼキューター関数をエクスポートするTypeScriptモジュールです。エージェントは プラグインを自身で構築し、セキュリティ問題をスキャンし、ランタイムでロードできます — すべて1つの会話の中で完結します。

プラグインの仕組み

プラグインはmod.tsエントリーポイントを持つディレクトリに存在します:

~/.triggerfish/plugins/my-plugin/
  mod.ts    # エクスポート:manifest、toolDefinitions、createExecutor

ロードされると、プラグインのツールはplugin_<name>_<toolName>としてエージェントに利用可能になります。 分類、Taint、ポリシーフックは組み込みツールと全く同じように適用されます — プラグインはディスパッチ チェーン内のただの別のツールソースです。

プラグインの書き方

REST APIをクエリする最小限のプラグイン:

typescript
export const manifest = {
  name: "weather",
  version: "1.0.0",
  description: "Weather forecast lookups",
  classification: "PUBLIC" as const,
  trust: "sandboxed" as const,
  declaredEndpoints: ["https://api.weather.com"],
};

export const toolDefinitions = [
  {
    name: "forecast",
    description: "Get the weather forecast for a city.",
    parameters: {
      city: {
        type: "string",
        description: "City name",
        required: true,
      },
    },
  },
];

export const systemPrompt = "Use `forecast` to look up weather for any city.";

export function createExecutor(context) {
  return async (name, input) => {
    if (name !== "forecast") return null;
    const city = input.city;
    context.log.info("Fetching forecast", { city });
    const resp = await fetch(
      `https://api.weather.com/v1/forecast?city=${encodeURIComponent(city)}`,
    );
    return await resp.text();
  };
}

必須エクスポート

エクスポート説明
manifestPluginManifestプラグインのID、分類、trust、エンドポイント
toolDefinitionsToolDefinition[]プラグインが提供するツール
createExecutor(context) => (name, input) => ...ツールハンドラーを返すファクトリー
systemPromptstring(オプション)エージェントのシステムプロンプトに注入される

マニフェストフィールド

フィールド説明
namestringディレクトリ名と一致する必要がある。小文字+ハイフンのみ
versionstringセマンティックバージョン(例:"1.0.0"
descriptionstring人間が読める説明
classificationstring"PUBLIC""INTERNAL""CONFIDENTIAL"、または"RESTRICTED"
truststring"sandboxed"(デフォルト)または"trusted"
declaredEndpointsstring[]サンドボックス化されたプラグインのネットワーク許可リスト

エグゼキューター関数

createExecutor(context)は以下を持つPluginContextを受け取ります:

  • pluginName — プラグインの名前
  • getSessionTaint() — 現在のセッション分類レベル
  • escalateTaint(level) — セッションTaintを上げる(下げることはできない)
  • log — プラグインにスコープされた構造化ロガー(debuginfowarnerror
  • configtriggerfish.yamlからのプラグイン固有の設定

返される関数は(name: string, input: Record<string, unknown>)を取り、string | nullを返します。 認識されないツール名にはnullを返します。

エージェントのBuild→Loadフロー

主要なプラグインワークフロー:エージェントがプラグインを書き、検証し、ロードします — すべてランタイム時に。

1. エージェントがmod.tsを書く  →  exec_write("my-plugin/mod.ts", code)
2. エージェントがプラグインをスキャン  →  plugin_scan({ path: "/workspace/my-plugin" })
3. エージェントがプラグインをロード  →  plugin_install({ name: "my-plugin", path: "/workspace/my-plugin" })
4. プラグインツールがライブに  →  plugin_my-plugin_forecast({ city: "Austin" })

triggerfish.yamlのエントリーは不要です。セキュリティスキャナーがゲートキーパーです — 設定なしにロードされたプラグインはデフォルトでsandboxedなtrustになり、マニフェストの分類を使用します。

エージェントのプラグインツール

エージェントにはプラグイン管理のための4つの組み込みツールがあります:

ツールパラメーター説明
plugin_scanpath(必須)ロード前にプラグインディレクトリをセキュリティスキャン
plugin_installname(必須)、path名前またはパスでプラグインをロード
plugin_reloadname(必須)ソースパスから実行中のプラグインをホットスワップ
plugin_list(なし)メタデータ付きで登録済みのすべてのプラグインをリスト表示

plugin_installの詳細:

  • name — ツール名前空間プレフィックスとして使用される(plugin_<name>_
  • path — プラグインディレクトリへの絶対パス。指定された場合、そのパスからロード(例:エージェントの ワークスペース)。省略された場合は~/.triggerfish/plugins/<name>/からロード
  • セキュリティスキャンはすべてのインストール時に必須。スキャンが失敗するとプラグインは拒否される
  • 設定エントリーは不要。存在する場合はtrustと分類の設定が尊重され、そうでなければsandboxedがデフォルト

plugin_reloadの詳細:

古いプラグインを登録解除し、元のソースパスから再スキャンして再インポートし、再登録します。 いずれかのステップが失敗した場合、古いバージョンが復元されます。エージェントは次のターンで 更新されたツールを見ます。

セキュリティスキャン

すべてのプラグインはロード前に危険なパターンのスキャンにかけられます。スキャナーは 起動時(事前設定済みプラグインの場合)およびランタイム時(すべてのplugin_installplugin_reload時)に実行されます。

スキャンされる内容

スキャナーはプラグインディレクトリのすべての.tsファイルをチェックします:

カテゴリー深刻度
コード実行eval()new Function()atobCritical
プロンプトインジェクション"ignore previous instructions"Critical
サブプロセスアクセスDeno.commandDeno.runCritical
ステガノグラフィーゼロ幅UnicodeキャラクターCritical
ネットワークリスナーDeno.listenDeno.serveCritical
環境アクセスDeno.env.get()Moderate
ファイルシステムアクセスDeno.readTextFileDeno.writeFileModerate
動的インポートimport("https://...")Moderate
難読化ROT13エンコード、base64操作Moderate

スコアリングモデル

各パターンには重み(1〜3)があります。プラグインは以下の場合に拒否されます:

  • Criticalパターン(重み >= 3)が検出された場合、または
  • 累積スコアがしきい値(>= 4)に達した場合

つまり、eval()単独で拒否されます(重み3、Critical)が、Deno.envアクセス(重み2)は 別のModerateパターンと組み合わさった場合のみ失敗します。

plugin_scanによる事前チェック

エージェントはplugin_installの前にplugin_scanを呼び出して問題を検出してください:

plugin_scan({ path: "/workspace/my-plugin" })
→ { "ok": true, "scannedFiles": ["mod.ts"] }

plugin_scan({ path: "/workspace/bad-plugin" })
→ { "ok": false, "warnings": ["eval() detected in mod.ts:3"], "scannedFiles": ["mod.ts"] }

スキャンが失敗した場合、エージェントはコードを修正して再スキャンしてからロードを試みてください。

トラストモデル

トラストは両側が同意する必要があります:

effectiveTrust = (manifest.trust === "trusted" AND config.trust === "trusted")
                 ? "trusted" : "sandboxed"
  • Sandboxed(デフォルト):エグゼキューターのエラーはキャッチされ、ツールの結果として返されます。 ネットワークはdeclaredEndpointsに制限されます。信頼されていないプラグインやエージェントが 構築したプラグインに使用します。
  • Trusted:エグゼキューターは通常のDeno権限で実行されます。Deno.hostname()Deno.memoryUsage()などのシステムAPIが必要なプラグインに使用します。

エージェントが構築したプラグインは常にsandboxedで実行されます(設定エントリーがない = trust: "trusted"の付与なし)。 ~/.triggerfish/plugins/のプラグインは設定でtrustedステータスを付与できます。

設定(オプション)

プラグインは設定なしで動作します。以下の場合のみtriggerfish.yamlに設定エントリーを追加してください:

  • trusted権限を付与する
  • 分類レベルをオーバーライドする
  • プラグイン固有の設定を渡す
yaml
plugins:
  weather:
    enabled: true
    classification: PUBLIC
    trust: sandboxed
    api_key: ${WEATHER_API_KEY}    # context.config.api_keyとして利用可能

設定エントリーなしでエージェントがロードしたプラグインはマニフェストの分類を使用し、 デフォルトでsandboxedなtrustになります。

ツールの名前空間

ツールは衝突を防ぐために自動的にプレフィックスされます:

  • プラグインweatherのプラグインツールforecastplugin_weather_forecastになる
  • エグゼキューターはプレフィックスをデコード(最長一致優先)して、元のツール名で正しいプラグインに 委譲する

分類とTaint

プラグインツールは他のすべてのツールと同じ分類ルールに従います:

  • マニフェストのclassificationレベルはplugin_<name>_プレフィックスを持つすべてのツールに登録される
  • プラグインツールがより高いレベルのデータを返すとセッションTaintがエスカレートする
  • Write-down防止が適用される:CONFIDENTIALのプラグインのデータはPUBLICチャンネルに流れることができない
  • すべてのフック強制(PRE_TOOL_CALL、POST_TOOL_RESPONSE)が変更なく適用される

The Reef:プラグインマーケットプレイス

プラグインはスキルに使用されるのと同じマーケットプレイスであるThe Reefに公開してインストールできます。

CLIコマンド

bash
triggerfish plugin search "weather"     # プラグインを検索
triggerfish plugin install weather      # The Reefからインストール
triggerfish plugin update               # アップデートを確認
triggerfish plugin publish ./my-plugin  # 公開の準備
triggerfish plugin scan ./my-plugin     # セキュリティスキャン
triggerfish plugin list                 # インストール済みプラグインをリスト表示

The Reefからのインストール

Reefのインストールは有効化前にSHA-256チェックサムで検証され、セキュリティスキャンが行われます:

1. catalog.jsonを取得(1時間キャッシュ)
2. プラグインの最新バージョンを見つける
3. mod.tsをダウンロード
4. SHA-256チェックサムがカタログエントリーと一致することを確認
5. ~/.triggerfish/plugins/<name>/mod.tsに書き込む
6. セキュリティスキャン — スキャンが失敗すれば削除
7. .plugin-hash.jsonにインテグリティハッシュを記録

公開

publishコマンドはプラグイン(マニフェスト、エクスポート、セキュリティスキャン)を検証し、 SHA-256チェックサムを計算し、Reefリポジトリへの送信に準備されたディレクトリ構造を生成します。

起動時のロード

~/.triggerfish/plugins/の事前インストール済みプラグインは起動時にロードされます:

  1. ローダーがmod.tsを持つサブディレクトリをスキャンする
  2. 各モジュールが動的にimport()され検証される
  3. 起動時は設定にenabled: trueがあるプラグインのみが初期化される
  4. セキュリティスキャナーがロード前に実行される
  5. Trustが解決され、エグゼキューターが作成され、ツールが登録される
  6. プラグインツールが組み込みツールと並んで即座に表示される

ランタイム時にエージェントがロードしたプラグイン(plugin_install経由)は設定チェックをスキップします — セキュリティスキャナーがゲートキーパーとして機能します。

インラインプラグインSDK(レガシー)

src/plugin/sandbox.tssrc/plugin/sdk.tsSandboxおよびPluginSdkインターフェースは、 インラインコード実行(new Function経由のTypeScriptまたはPyodide WASM経由のPython)をサポートします。 このモデルは完全なプラグインモジュールではなくコードスニペットを実行する組み込み/管理プラグインに 使用されます。

ランタイム環境

  • TypeScriptプラグインはDenoサンドボックス内で直接実行される
  • PythonプラグインはPyodide(WebAssemblyにコンパイルされたPythonインタープリター)内で実行され、 それ自体がDenoサンドボックス内で実行される

SDKメソッド

typescript
// サービスに対するユーザーの委任認証情報を取得
const credential = await sdk.get_user_credential("salesforce");

// ユーザーの権限でサービスをクエリ
const results = await sdk.query_as_user("salesforce", {
  query: "SELECT Name, Amount FROM Opportunity WHERE StageName = 'Closed Won'",
});

// データをエージェントに送信 — 分類ラベルは必須
sdk.emitData({
  classification: "CONFIDENTIAL",
  payload: results,
  source: "salesforce",
});

制約

制約強制方法
宣言されていないネットワークエンドポイントへのアクセスサンドボックスが許可リスト外のすべてのネットワーク呼び出しをブロック
分類ラベルなしでデータを送信SDKが未分類のデータを拒否
Taint伝播なしでデータを読むSDKがデータへのアクセス時にセッションを自動Taint
Triggerfish外にデータを永続化サンドボックス内からのファイルシステムアクセスなし
サイドチャンネル経由で漏洩リソース制限が強制、生ソケットアクセスなし
システム認証情報を使用SDKがget_system_credential()をブロック;ユーザー認証情報のみ

SECURITY sdk.get_system_credential()設計上ブロックされています。プラグインは

sdk.get_user_credential()経由で常に委任されたユーザー認証情報を使用する必要があります。 :::

データベース接続

ネイティブデータベースドライバーはWASMサンドボックス内では動作しません。代わりにHTTPベースの APIを使用してください:

データベースHTTPベースのオプション
PostgreSQLPostgREST、Supabase SDK、Neon API
MySQLPlanetScale API
MongoDBAtlas Data API
SnowflakeREST API
BigQueryREST API
DynamoDBAWS SDK(HTTP)