Spirit Agent

拡張機能

パッケージレイアウト、spiritExtensionフィールド、activate API、公式レジストリへの掲載。

拡張機能は、spiritExtension を含む package.json を持つフォルダです。Spirit はこれをワークスペースの .spirit/ ディレクトリではなく、ユーザーごと、ホストごとにインストールします。

ホストパス
Desktop{spiritDataDir}/extensions/desktop/
CLI{spiritDataDir}/extensions/cli/

これは SkillsSKILL.md フォルダ)、MCP(外部サーバー)、Hookshooks.json スクリプト)とは異なります。contributes.cli.hooks は CLI TUI スロットをスタイルします。これは hooks.json ではありません。

拡張機能ごとの有効化スイッチはありません。インストール後、拡張機能が貢献します。CLI パネルのトグルはプレースホルダーです。

パッケージレイアウト

example-extension/
  package.json
  dist/index.js
  assets/icon.svg
  styles/desktop.css
  cli-hooks.json
{
  "name": "@example/spirit-extension",
  "version": "0.1.0",
  "description": "Example Spirit Agent extension.",
  "author": { "name": "example" },
  "homepage": "https://example.com/spirit-extension",
  "main": "dist/index.js",
  "spiritExtension": {
    "schemaVersion": 1,
    "displayName": "Example extension",
    "icon": "assets/icon.svg",
    "supportedHosts": ["cli", "desktop"],
    "activationEvents": ["onStartup", "onUserMessage"],
    "requestedCapabilities": [
      "tool-definitions",
      "tool-execution",
      "system-prompt",
      "settings",
      "secret-storage",
      "desktop-ui",
      "cli-ui"
    ],
    "contributes": {
      "tools": [
        {
          "name": "lookup_item",
          "description": "Look up an item by id.",
          "inputSchema": {
            "type": "object",
            "properties": {
              "id": { "type": "string" }
            },
            "required": ["id"]
          },
          "approvalMode": "allowed",
          "executionMode": "foreground"
        }
      ],
      "desktop": {
        "css": [{ "path": "styles/desktop.css" }],
        "settingsPage": { "title": "Example extension" }
      },
      "cli": {
        "hooks": { "path": "cli-hooks.json" }
      }
    },
    "settingsSchema": [
      {
        "key": "region",
        "type": "select",
        "title": "Region",
        "required": true,
        "defaultValue": "us",
        "options": [
          { "value": "us", "label": "US" },
          { "value": "eu", "label": "EU" }
        ]
      }
    ],
    "secretSlots": [
      {
        "key": "api_token",
        "title": "API token",
        "required": true
      }
    ]
  }
}

package.jsonname は拡張機能 ID です。^(?:@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*$ に一致する必要があります。

package.json フィールド

フィールド説明
name必須。npm パッケージ名。拡張機能 ID として使用されます
version必須。バージョン文字列
spiritExtension必須。オブジェクト。以下を参照
description任意。文字列
author任意。文字列または { name }
homepage任意。文字列
main任意。activate エントリへの相対パス。activationEvents、ツール実行、またはシステムプロンプトを使用する場合に必要です

mainspiritExtension.icon、CSS パス、CLI フックパスは相対パスで、パッケージ内に収まる必要があります。

spiritExtension

フィールド説明
schemaVersion任意。デフォルトは 1。サポートされているのは 1 のみ
displayName必須。ユーザーに表示される名前
icon任意。パッケージルートからの相対パス
supportedHosts必須。cli または desktop の非空配列
activationEvents任意。アクティベーションイベント を参照
requestedCapabilities任意。機能 を参照
contributes任意。toolsdesktop、または cli
settingsSchema任意。設定定義
secretSlots任意。シークレットスロット定義

機能

ランタイム
tool-definitionscontributes.tools をモデルに公開するには tool-execution が必要
tool-executionこれらのツールを実行するには tool-definitions が必要
system-promptシステムプロンプトフラグメントを提供するには main が必要
desktop-uicontributes.desktop と対で指定する必要があります
cli-uicontributes.cli と対で指定する必要があります
approval-flow宣言のみ。承認は各ツールの approvalMode によって行われます
questions-flow宣言のみ。質問は approvalMode: need-questions によって行われます
settings宣言のみ。設定は settingsSchema から取得されます
secret-storagesecretSlots と一緒に使用されます
structured-results宣言のみ

desktop-ui / cli-ui と対応する contributes ブロックは、両方存在するか、両方存在しないかのどちらかでなければなりません。

アクティベーションイベント

イベント発火タイミング
onStartupホストのウォームアップ
onExtensionInstalledZIPまたはマーケットプレイスからのインストール後
onSessionOpenedセッションがアクティブになったとき
onSessionResetセッションのリセット
onUserMessageユーザーがメッセージを送信したとき
onToolCallツールが実行されようとしているとき
onToolResultツールの結果が利用可能になったとき
onApprovalResolved承認の決定が解決されたとき

ホストは、拡張機能がイベントをリストし、読み取り可能な main を持っている場合に activate を呼び出します。

contributes.tools

フィールド説明
name必須。[a-z0-9]+(?:[._-][a-z0-9]+)*
description必須。モデルに表示されます
inputSchema必須。JSONスキーマオブジェクト
outputSchema任意。JSONスキーマオブジェクト
approvalMode任意。allowedneed-approval、または need-questions
executionMode任意。foreground または background

モデルは name をそのまま認識しません。ホストは extension__{id}__{tool}__{hash} のような呼び出し名を構築します。

contributes.desktop

desktop-ui が必要です。

フィールド説明
css[].path必須。パッケージルートからの相対パスで指定するCSSファイル
css[].media任意。CSSメディアクエリ
settingsPage任意。true{}、または { title } — Desktopの設定エントリを追加します

contributes.cli

cli-ui が必要です。hooks はインライン配列ではなく、path を持つオブジェクトです:

{
  "hooks": { "path": "cli-hooks.json" }
}

ファイルは { "hooks": [ ... ] } の形式である必要があります。

フィールド説明
slot必須。以下のスロットのいずれか
variant任意。default, accented, muted, warning, success, danger
tokens任意。{ foreground?, border?, accent? }
prefix任意。文字列
suffix任意。文字列

スロット: message.user, message.assistant, message.tool, assistant.thinking, input.frame, bottom_form, bottom_form.section, slash_suggestions, approval.panel, questions.panel

トークンの役割: default, primary, secondary, muted, accent, success, warning, danger

{
  "hooks": [
    {
      "slot": "input.frame",
      "variant": "accented",
      "tokens": { "border": "accent" },
      "prefix": "[",
      "suffix": "]"
    }
  ]
}

settingsSchema

フィールド説明
key必須。ツール名と同じパターン
type必須。string, boolean, number, または select
title必須。UIラベル
description任意
placeholder任意
required任意。ブール値
defaultValue任意。type と一致する必要があります
optionsselect には必須。{ value, label, description? } の配列

値は string, number, boolean, または null です。null は必須でない設定をクリアします。

secretSlots

フィールド説明
key必須
title必須
description任意
required任意。ブール値

デスクトップはシークレットをOSキーリングに保存します。CLIデーモンパスでは、secrets.set / secrets.delete が利用できない場合があります。

activate

main は動的な import で読み込まれます。次のいずれかをエクスポートします:

  • export function activate(ctx) { ... }
  • export default function activate(ctx) { ... }
  • export default { activate }

ctx

フィールド説明
extension{ id, name, version, directoryPath, manifestPath, main }
hostホストAPI。デスクトップは showMessageBox を実装します。CLIは {}
log(message: string) => void
settingsget(key), getAll(), set(key, value), setAll(values)
secretsget(key), has(key), set(key, value), delete(key) — キーは secretSlots で宣言されている必要があります
activationEvent任意。{ type, detail? }

戻り値

オブジェクトを返すか、モジュールから同じフィールドをエクスポートします。

フィールド説明
toolsRecord<string, (ctx) => unknown>。キーはマニフェストのツール名です
invokeTool(ctx) => unknown。存在する場合は tools[name] の代わりに使用されます
systemPrompt静的システムフラグメント
getSystemPrompt() => string | Promise<string>。存在する場合は systemPrompt の代わりに使用されます
onEvent(event) => void
dispose() => void。削除または再読み込み時に呼び出されます

ツールハンドラー ctx

フィールド説明
extensionactivate と同じランタイム情報
host同じホスト API
toolNameマニフェストのツール名
argumentsモデルからのオブジェクト
log同じロガー
settings同じ設定アクセサー
secrets同じシークレットアクセサー
toolCallId任意
questionsResult任意。approvalModeneed-questions の場合に設定されます

string の結果はそのまま渡されます。その他の値は JSON.stringify(value, null, 2) になります。undefined"" になります。

デスクトップ host.showMessageBox

フィールド説明
title必須。文字列
message必須。文字列
detail任意。文字列
buttons任意。文字列配列
cancelId任意。数値
defaultId任意。数値
noLink任意。ブール値
type任意。noneinfoerrorquestionwarning
export function activate(ctx) {
  return {
    systemPrompt: "Use lookup_item when the user asks for an item by id.",
    async invokeTool({ toolName, arguments: args, settings, secrets }) {
      if (toolName !== "lookup_item") {
        throw new Error(`Unknown tool: ${toolName}`);
      }
      const region = await settings.get("region");
      const token = await secrets.get("api_token");
      return { id: args.id, region, hasToken: Boolean(token) };
    },
    dispose() {
      ctx.log("example-extension disposed");
    },
  };
}

インストール

  • ZIP — アーカイブには正確に 1 つの package.json が含まれている必要があります(サブディレクトリにある場合もあります)。spirit extension import ./extension.zip または Settings → Extensions でインポートします。
  • マーケットプレイスの tarball — アーカイブのルートに package/ ディレクトリが含まれている必要があります。

supportedHosts には現在のホストが含まれている必要があります。同じ ID の 2 回目のインストールは、デフォルトでは既存のコピーを置き換えません。チャンネルとインストール UI については Marketplace を参照してください。

公式レジストリに公開

SpiritAgents/registry リポジトリはマーケットプレイスのインデックスです。拡張機能のソース、dist、ZIP ファイル、または tarball はホストされません。

次の手順をこの順序で実行してください:

  1. 公開のnpmパッケージを公開します。
  2. そのパッケージをリストする pull request を開きます。

1. npmパッケージを公開する

公開された package.json が信頼できる情報源であり、特に spiritExtension が重要です。レジストリビルダーには次のものが必要です:

  • spiritExtension.schemaVersion
  • spiritExtension.displayName
  • spiritExtension.supportedHosts
  • spiritExtension.requestedCapabilities

また、nameversiondescriptionauthorrepositoryhomepagekeywords、およびオプションの spiritExtension.icon も読み取ります。icon を設定する場合は、そのファイルを公開パッケージに含めてください。spiritExtension オブジェクトがないと、そのバージョンのレジストリビルドは失敗します。

公式例:@spiritagent/extension-system-message-demospiritagent.system-message-demo)。

2. パッケージをリストする

registry/extensions/<extension-id>/ を作成し、次のものを含めます:

ファイル説明
entry.jsonマーケットプレイスのガバナンス
README.mdマーケットプレイスの詳細コピー

これらを手動で編集しないでください(再生成するものです):

  • registry/catalog.json
  • registry/extensions/<extension-id>/detail.json

extensionId は、少なくとも2つのドット区切りのセグメント、小文字の英数字、セグメント内にドットまたはハイフンを使用する必要があります。例:spiritagent.system-message-demoyourteam.some-extensionpackageNameextensionId はリポジトリ内で一意である必要があります。

entry.json

フィールド説明
schemaVersion必須。1
extensionId必須。上記のルールを参照
packageName必須。npmパッケージ名
status必須。listedhiddendeprecated、または blocked
featured必須。ブール値
defaultVersion必須。デフォルトのバージョン文字列
defaultReviewStatus必須。unverifiedverified、または revoked
versions必須。少なくとも1つの項目

versions[] 項目:

フィールド説明
version必須
channel必須。stablepreview、または experimental
reviewStatus必須。unverifiedverified、または revoked
changelogオプション。{ summary, body } — 存在する場合は両方必須
{
  "schemaVersion": 1,
  "extensionId": "example.spirit-extension",
  "packageName": "@example/spirit-extension",
  "status": "listed",
  "featured": false,
  "defaultVersion": "0.1.0",
  "defaultReviewStatus": "unverified",
  "versions": [
    {
      "version": "0.1.0",
      "channel": "stable",
      "reviewStatus": "unverified",
      "changelog": {
        "summary": "Initial public release.",
        "body": "- Initial public release."
      }
    }
  ]
}

マーケットプレイスのREADMEでは、拡張機能の機能、パッケージ名、デフォルトの承認バージョン、ホストと機能の互換性、マーケットプレイスの読者向けのメモをカバーする必要があります。

派生ファイルをローカルで再生成します:

./scripts/build-registry.ps1

スクリプトは、リストされたバージョンのnpmメタデータを取得し、catalog.jsonと各detail.jsonを再構築して、一貫性を検証します。

Pull request

entry.json、マーケットプレイスのREADME.md、再生成されたcatalog.json / detail.jsonを含めてください。npmで公開されているバージョンのみをリストしてください。reviewStatuschannelを正確に設定してください。新しいバージョンは通常unverifiedから始まります。

拡張機能のソースツリー、dist、ZIPファイル、tarball、その他のバイナリアーティファクトをコミットしないでください。

pull request を開いてもリスト掲載が保証されるわけではありません。レビューでは、バージョンが承認または検証される前に変更が要求される場合があります。