Ausprobieren
In einem Terminal, während Gnista läuft:
G=/Applications/Gnista.app/Contents/Helpers/gnista
echo '{"session":"demo","event":"needs-you","message":"Ralph wants to deploy","cwd":"'"$PWD"'"}' | "$G" hook custom ralphEine Sitzung von „Ralph“ taucht auf und braucht dich. Klick sie an, und du bist zurück in diesem Terminal. Dann:
echo '{"session":"demo","event":"done","message":"Deployed"}' | "$G" hook custom ralph
echo '{"session":"demo","event":"end"}' | "$G" hook custom ralphDer Helper endet immer mit 0 und wartet nie, er kann dein Tool also nicht aufhalten. Stimmt etwas mit dem Gesendeten nicht, sagt er es auf stderr und schickt nichts.
Der Befehl
gnista hook custom <name> [event]<name> ist der Name deines Agents: bis zu 32 Kleinbuchstaben, Ziffern, - und _, am Anfang ein Buchstabe oder eine Ziffer. Die Namen der eingebauten Agents (claude, codex und die anderen) sind vergeben. Das Event kann statt im JSON auch hier stehen, für Tools, die für jedes Event einen anderen Befehl ausführen.
Das JSON
Ein JSON-Objekt pro Aufruf, auf stdin:
| Schlüssel | Was es ist |
|---|---|
session | Pflicht. Eine beliebige ID, die für eine Sitzung gleich bleibt (Text oder Zahl). |
event | Pflicht, hier oder auf der Befehlszeile. Eines der Events unten. |
cwd | Der Projektordner. Zeilen zeigen ihn; ohne ihn der Ordner des Helpers. |
message | Was der Agent gerade tut, fragt oder zuletzt gesagt hat. |
tool | Das Tool, das gerade läuft, für tool und tool-done. |
title | Der Titel der Sitzung, statt des Ordners angezeigt. |
model | Das Modell, z. B. gpt-5. Modelle, die Gnista kennt, erscheinen als kleines Badge auf dem Icon; für alle anderen kannst du deine eigenen beschreiben. |
transcript | Die Transkript-Datei des Agents, für details (Version 2). Hooks im Claude-Stil senden sie als transcript_path. |
pid | Der Prozess des Agents. Endet er, endet die Sitzung. Ohne ihn der Prozess, der den Helper gestartet hat. |
Events
Groß- und Kleinschreibung und Trennzeichen sind egal: needs-you, NeedsYou und needs_you sind dasselbe.
| Event | In Gnista |
|---|---|
start | Die Sitzung taucht auf und arbeitet. |
prompt | Arbeitet: Jemand hat ihn etwas gefragt. |
tool | Arbeitet, mit „Führt einen Befehl aus“, „Bearbeitet api.ts“ oder der message. |
tool-done | Arbeitet weiter, außer das Tool steht in doneAfterTools. |
needs-you | Braucht dich: Die Notch sagt es, mit der message. |
done | Die Runde ist fertig. |
end | Die Sitzung ist vorbei. |
Eine Sitzung, die arbeitet und dann still wird, gilt nach ein paar Minuten als untätig (Einstellungen ▸ Allgemein ▸ Inaktiv nach).
Die Agent-Datei
Optional. Sie liegt unter ~/Library/Application Support/Gnista/Agents/<name>.json. Jeder Schlüssel ist optional:
{
"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"]
}| Schlüssel | Was er bewirkt |
|---|---|
name | Wie Zeilen und Einstellungen den Agent nennen, bis zu 40 Zeichen. Ohne ihn der Name aus dem Befehl. |
icon | Eine SVG- oder PNG-Datei im selben Ordner, bis 1 MB. Ohne sie Gnistas eigener Funke. |
fields | Für Tools, die ihr eigenes JSON schicken: wo jeder Wert aus der JSON-Tabelle oben steht. Pfade beginnen bei $, mit .key für den Schlüssel eines Objekts und [0] für ein Element einer Liste. Ein Feld, das du nicht zuordnest, wird unter seinem üblichen Schlüssel gelesen. |
events | Die Event-Namen deines Tools, und welches von Gnistas Events jeder ist. "ignore" lässt eines still fallen. Namen werden genauso großzügig verglichen; Gnistas eigene funktionieren weiter. |
host | Die Bundle-ID der App, in der der Agent läuft: Dorthin führt ein Klick, wenn Gnista es nicht am Prozess erkennt. |
jump | Eine Sprungregel: siehe unten. |
doneAfterTools | Für Agents, die nie sagen, dass eine Runde fertig ist: Nach einem dieser Tools (einem tool-done-Event) ist sie es. |
Eine Datei über 1 MB, oder mit irgendeinem Fehler darin (ein unbekannter Schlüssel, ein Pfad, der keiner ist, ein Event, das Gnista nicht kennt), wird als Ganzes ignoriert. Einstellungen ▸ Agents ▸ Eigene Agents zeigt sie mit dem Grund, und der Helper sagt es auf stderr. Das einfache Format von oben funktioniert so lange weiter.
Gnista verbindet es für dich
Mit "version": 2 kann die Datei Gnista auch sagen, wie es deinen Agent verbindet, so wie es die eingebauten verbindet: welche Hooks in die eigene Konfiguration des Agents kommen, wie Gnista liest, was sie senden, ob sich seine Berechtigungsanfragen von der Notch aus beantworten lassen und wo sein Transkript liegt, damit seine Zeile deine Eingabe, seine Antwort und die Kosten zeigt. Die Schlüssel von Version 1 behalten ihre Bedeutung.
{
"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"
}| Schlüssel | Was er bewirkt |
|---|---|
version | 2. |
speaker | Wie ein Satz den Agent nennt: „Ralph möchte ausführen…“. Bis zu 40 Zeichen. Ohne ihn der name. |
colour | Seine Farbe, als "#RRGGBB". |
adapter | "fields" (Standard): fields und events finden Gnistas Werte im JSON deines Tools, wie in Version 1. "claude-style": Dein Tool sendet die Hook-Payloads von Claude Code; events ordnet dann seine eigenen Event-Namen denen von Claude zu. |
toolNames | Mit claude-style: die Namen deines Tools für Claudes Tools, etwa {"run_shell": "Bash"}, damit Zeilen und Anfragen gleich lauten. |
hooks | Was Gnista installiert, wenn du es verbindest: die Tabelle darunter. |
approvals | Seine Berechtigungsanfragen warten auf die Notch: "plain" (erlauben oder ablehnen), "answers" (mit Antworten auf seine Fragen) oder "claude" (mit Antworten, „Immer“-Regeln und einem Modus). Nur mit claude-style und einem claude-table-Hook für PermissionRequest. |
details | Das Format seines Transkripts, falls er eines schreibt, das Gnista liest: "claude", "codex", "gemini" oder "antigravity". Zeilen zeigen dann seine Eingabe, seine Antwort und, außer bei antigravity, die Kosten. |
Einstellungen ▸ Agents listet deinen Agent dann zu den anderen: Verbindest du ihn dort, fügt Gnista seine Hooks in die Datei ein, die du genannt hast, und beim Trennen nimmt es sie wieder heraus. Gnista ändert nur seine eigenen Einträge und legt vorher eine Sicherung der Datei an. Die Hooks rufen gnista hook custom <name> auf, mit dem Event.
| In „hooks“ | Was es bewirkt |
|---|---|
format | "claude-table": Claude Codes {"hooks": {"<event>": [{"hooks": [{"type": "command", …}]}]}}, das Event steht in der Payload. "flat": {"hooks": {"<event>": [{"command": …}]}}, das Event steht auf der Befehlszeile. "toml": [[hooks]]-Blöcke mit event und command, in einer Datei, die auf .toml endet. |
file | Die Konfiguration des Agents, relativ zu deinem Home-Ordner und in einem eigenen Ordner des Agents: .ralph/settings.json. Ist dieser Ordner da, ist der Agent auf diesem Mac. |
events | Die Event-Namen des Agents, die Gnista einhängt: Buchstaben, Ziffern und _. |
timeout | Sekunden, 1 bis 600, für Agents, deren Hooks eines brauchen. |
foundBy | Dateien, die nur der Agent selbst schreibt, relativ zu deinem Home-Ordner, wenn sein Ordner allein nicht zeigt, dass er installiert ist (andere Apps legen ihn auch an). |
Sprungregeln
Klickst du auf eine Sitzung, bringt Gnista dich zu ihrem Terminal-Tab oder Fenster. Für Apps, in die es keinen Weg hinein hat, gibt ihm eine Sprungregel stattdessen eine URL zum Öffnen: nachdem der genaue Tab und das Fenster versucht wurden und bevor die App einfach nach vorn geholt wird.
{ "url": "myeditor://focus?folder={cwd}&pane={tmux_pane}" }Nutze sie als "jump" in einer Agent-Datei, oder für jede Sitzung in einer App als ~/Library/Application Support/Gnista/JumpRules/<bundle id>.json (zum Beispiel com.example.Editor.json). Die eigene Regel eines Agents geht vor.
| Platzhalter | Gefüllt mit |
|---|---|
{session} | Die ID der Sitzung. |
{cwd} | Der Projektordner. |
{tty} | Das Terminal, z. B. /dev/ttys004. |
{pid} | Die Prozess-ID des Agents. |
{tmux_pane} | Das tmux-Pane, z. B. %3. |
Jeder Wert wird als Ganzes prozentkodiert (aus / wird %2F), er kann die Form der URL also nicht ändern. Eine Regel, deren Platzhalter nicht alle einen Wert haben, wird nicht benutzt. URLs, die Dateien öffnen oder Code ausführen (file:, javascript:, data: und Ähnliche), werden abgelehnt.
In den Einstellungen
Einstellungen ▸ Agents ▸ Eigene Agents zeigt jeden Agent mit Datei oder der sich schon gemeldet hat, und wann Gnista zuletzt von ihm gehört hat.