試してみる
Gnistaを起動した状態で、ターミナルで:
G=/Applications/Gnista.app/Contents/Helpers/gnista
echo '{"session":"demo","event":"needs-you","message":"Ralph wants to deploy","cwd":"'"$PWD"'"}' | "$G" hook custom ralph「Ralph」のセッションが現れ、対応待ちになります。クリックすると、このターミナルに戻ります。続けて:
echo '{"session":"demo","event":"done","message":"Deployed"}' | "$G" hook custom ralph
echo '{"session":"demo","event":"end"}' | "$G" hook custom ralphヘルパーは必ず0で終了し、待つこともないので、ツールを止めることはありません。送った内容に問題があれば、stderrにそう書き、何も送りません。
コマンド
gnista hook custom <name> [event]<name>はエージェントの名前です。小文字の英字、数字、-、_で32文字まで、先頭は英字か数字です。組み込みのエージェントの名前(claude、codexなど)は使えません。イベントはJSONの代わりにここで渡すこともできます。イベントごとに別のコマンドを実行するツール向けです。
JSON
1回の呼び出しにつき1つのJSONオブジェクトを、stdinに:
| キー | 内容 |
|---|---|
session | 必須。1つのセッションの間ずっと変わらない任意のID(テキストか数値)。 |
event | 必須。ここかコマンドラインで。下のイベントのどれか。 |
cwd | プロジェクトのフォルダ。行に表示されます。ないときはヘルパー自身のフォルダ。 |
message | エージェントがしていること、求めていること、最後に言ったこと。 |
tool | 使っているツール。toolとtool-doneで。 |
title | セッションのタイトル。フォルダの代わりに表示されます。 |
model | モデル。例:gpt-5。Gnistaが知っているモデルは、アイコンに小さなバッジで表示されます。それ以外は独自に記述できます。 |
transcript | エージェントのトランスクリプトファイル。detailsで使います(バージョン2)。Claude形式のフックはtranscript_pathとして送ります。 |
pid | エージェントのプロセス。終了するとセッションも終わります。ないときはヘルパーを実行したプロセス。 |
イベント
大文字小文字や区切り文字は区別しません。needs-you、NeedsYou、needs_youはどれも同じです。
| イベント | Gnistaでは |
|---|---|
start | セッションが現れ、作業中になります。 |
prompt | 作業中:誰かが何かを頼みました。 |
tool | 作業中。「コマンドを実行中」「編集中:api.ts」かmessageを表示します。 |
tool-done | 作業中のまま。ただしツールがdoneAfterToolsのどれかなら完了。 |
needs-you | 対応待ち:ノッチがmessageとともに知らせます。 |
done | ターンが完了しました。 |
end | セッションが終わりました。 |
作業中のセッションが静かになると、数分後にアイドルになります(設定 ▸ 一般 ▸ アイドルまでの時間)。
エージェントファイル
任意です。~/Library/Application Support/Gnista/Agents/<name>.jsonに置きます。どのキーも任意です:
{
"name": "Ralph",
"icon": "ralph.svg",
"fields": {
"session": "$.conversation_id",
"event": "$.hook_event_name",
"cwd": "$.workspace_roots[0]",
"tool": "$.tool.name"
},
"events": {
"beforeSubmitPrompt": "prompt",
"afterToolUse": "tool-done",
"stop": "done",
"heartbeat": "ignore"
},
"host": "com.example.Ralph",
"jump": { "url": "ralph://open?session={session}" },
"doneAfterTools": ["attempt_completion"]
}| キー | 役割 |
|---|---|
name | 行と設定に表示されるエージェントの名前。40文字まで。ないときはコマンドの名前。 |
icon | 同じフォルダにあるSVGかPNGのファイル。1MBまで。ないときはGnista自身の火花。 |
fields | 独自のJSONを送るツール向け:上のJSONの表の各値をどこから読むか。パスは$から始まり、オブジェクトのキーは.key、リストの項目は[0]。指定しないフィールドは、いつものキーから読みます。 |
events | ツール独自のイベント名と、それぞれがGnistaのどのイベントにあたるか。"ignore"で静かに捨てられます。名前は同じゆるさで照合され、Gnista自身の名前もそのまま使えます。 |
host | エージェントが動くアプリのバンドルID。Gnistaがプロセスから判断できないとき、クリックでここへジャンプします。 |
jump | ジャンプのルール。下を参照。 |
doneAfterTools | ターンの完了を伝えないエージェント向け:これらのツールのどれかのあと(tool-doneイベント)で完了とします。 |
1MBを超えるファイルや、どこかに誤りがあるファイル(知らないキー、パスになっていないパス、Gnistaにないイベント)は、まるごと無視されます。設定 ▸ エージェント ▸ カスタムエージェントに理由とともに表示され、ヘルパーもstderrに書きます。その間も、上のシンプルな形式はそのまま使えます。
Gnistaに接続を任せる
"version": 2にすると、ファイルでエージェントの接続のしかたもGnistaに伝えられます。組み込みのエージェントと同じように、エージェント自身の設定に入れるフック、フックが送る内容の読み方、許可リクエストをノッチから答えられるか、トランスクリプトの場所(行にプロンプトと返信とコストが表示されます)です。バージョン1のキーの意味は変わりません。
{
"version": 2,
"name": "Ralph",
"colour": "#2EB872",
"adapter": "claude-style",
"hooks": {
"format": "claude-table",
"file": ".ralph/settings.json",
"events": ["UserPromptSubmit", "PreToolUse", "PostToolUse", "PermissionRequest", "Stop", "SessionEnd"],
"timeout": 5
},
"approvals": "plain",
"details": "claude"
}| キー | 内容 |
|---|---|
version | 2。 |
speaker | 文中での呼び方:「Ralphが…を実行したがっています」。40文字まで。ないときはname。 |
colour | 色。"#RRGGBB"の形で。 |
adapter | "fields"(既定):fieldsとeventsで、バージョン1と同じようにツールのJSONからGnistaの値を探します。"claude-style":ツールがClaude Codeのフックのペイロードを送ります。その場合eventsは、ツール独自のイベント名をClaudeのものに対応づけます。 |
toolNames | claude-styleのとき:Claudeのツールに対するツール独自の名前。例:{"run_shell": "Bash"}。行とリクエストの表示がそろいます。 |
hooks | 接続したときにGnistaが入れるもの:下の表。 |
approvals | 許可リクエストをノッチで待ちます:"plain"(許可か拒否)、"answers"(質問への答え付き)、"claude"(答え、「常に」ルール、モード付き)。claude-styleで、PermissionRequestにclaude-tableのフックがあるときだけ。 |
details | Gnistaが読めるトランスクリプトを書き出すなら、その形式:"claude"、"codex"、"gemini"、"antigravity"。行にはプロンプトと返信が表示され、antigravity以外ではコストも表示されます。 |
設定 ▸ エージェントには、あなたのエージェントが他のエージェントと並びます。そこで接続すると、指定したファイルにGnistaのフックが加わり、接続を外すと取り除かれます。Gnistaが変えるのは自分のエントリだけで、先にファイルをバックアップします。フックはイベントを付けてgnista hook custom <name>を呼びます。
| 「hooks」の中 | 内容 |
|---|---|
format | "claude-table":Claude Codeの{"hooks": {"<event>": [{"hooks": [{"type": "command", …}]}]}}。イベントはペイロードに入ります。"flat":{"hooks": {"<event>": [{"command": …}]}}。イベントはコマンドラインに入ります。"toml":eventとcommandを持つ[[hooks]]ブロック。ファイル名は.tomlで終わること。 |
file | エージェントの設定ファイル。ホームフォルダからの相対パスで、エージェント自身のフォルダの中:.ralph/settings.json。そのフォルダがあれば、このMacにエージェントがあるとみなします。 |
events | Gnistaがフックするエージェントのイベント名:英字、数字、_。 |
timeout | 秒数(1〜600)。フックにタイムアウトを持つエージェント向け。 |
foundBy | エージェント自身だけが書くファイル(ホームフォルダからの相対パス)。フォルダだけではインストール済みか分からないとき(他のアプリも作るため)に使います。 |
ジャンプのルール
セッションをクリックすると、Gnistaはそのターミナルのタブかウインドウへ連れて行きます。中に入る手段がないアプリでは、ジャンプのルールが代わりに開くURLを渡します。正確なタブとウインドウを試したあと、アプリを手前に出すだけの前に使われます。
{ "url": "myeditor://focus?folder={cwd}&pane={tmux_pane}" }エージェントファイルの"jump"として使うか、あるアプリのすべてのセッションに向けて~/Library/Application Support/Gnista/JumpRules/<bundle id>.json(例:com.example.Editor.json)に置きます。エージェント自身のルールが優先です。
| プレースホルダー | 入る値 |
|---|---|
{session} | セッションID。 |
{cwd} | プロジェクトのフォルダ。 |
{tty} | ターミナル。例:/dev/ttys004。 |
{pid} | エージェントのプロセスID。 |
{tmux_pane} | tmuxのペイン。例:%3。 |
どの値もまるごとパーセントエンコードされる(/は%2Fになる)ので、URLの形は変えられません。プレースホルダーのどれかに値がないルールは使われません。ファイルを開いたりコードを実行したりするURL(file:、javascript:、data:など)は拒否されます。
設定で
設定 ▸ エージェント ▸ カスタムエージェントには、ファイルがあるか報告してきたエージェントがすべて並び、Gnistaが最後に連絡を受けた時刻も表示されます。