Eigene Agents,
eine Zeile JSON.

Jedes Tool kann in Gnista auftauchen: arbeitet, fertig oder braucht dich. Ohne neue Version von Gnista und ohne etwas zu installieren außer Gnista selbst. Immer wenn etwas passiert, schickt dein Tool eine Zeile JSON an Gnistas Helper.

Aktualisiert am

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 ralph

Eine 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 ralph

Der 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üsselWas es ist
sessionPflicht. Eine beliebige ID, die für eine Sitzung gleich bleibt (Text oder Zahl).
eventPflicht, hier oder auf der Befehlszeile. Eines der Events unten.
cwdDer Projektordner. Zeilen zeigen ihn; ohne ihn der Ordner des Helpers.
messageWas der Agent gerade tut, fragt oder zuletzt gesagt hat.
toolDas Tool, das gerade läuft, für tool und tool-done.
titleDer Titel der Sitzung, statt des Ordners angezeigt.
modelDas 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.
transcriptDie Transkript-Datei des Agents, für details (Version 2). Hooks im Claude-Stil senden sie als transcript_path.
pidDer 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.

EventIn Gnista
startDie Sitzung taucht auf und arbeitet.
promptArbeitet: Jemand hat ihn etwas gefragt.
toolArbeitet, mit „Führt einen Befehl aus“, „Bearbeitet api.ts“ oder der message.
tool-doneArbeitet weiter, außer das Tool steht in doneAfterTools.
needs-youBraucht dich: Die Notch sagt es, mit der message.
doneDie Runde ist fertig.
endDie 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üsselWas er bewirkt
nameWie Zeilen und Einstellungen den Agent nennen, bis zu 40 Zeichen. Ohne ihn der Name aus dem Befehl.
iconEine SVG- oder PNG-Datei im selben Ordner, bis 1 MB. Ohne sie Gnistas eigener Funke.
fieldsFü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.
eventsDie 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.
hostDie Bundle-ID der App, in der der Agent läuft: Dorthin führt ein Klick, wenn Gnista es nicht am Prozess erkennt.
jumpEine Sprungregel: siehe unten.
doneAfterToolsFü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üsselWas er bewirkt
version2.
speakerWie ein Satz den Agent nennt: „Ralph möchte ausführen…“. Bis zu 40 Zeichen. Ohne ihn der name.
colourSeine 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.
toolNamesMit claude-style: die Namen deines Tools für Claudes Tools, etwa {"run_shell": "Bash"}, damit Zeilen und Anfragen gleich lauten.
hooksWas Gnista installiert, wenn du es verbindest: die Tabelle darunter.
approvalsSeine 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.
detailsDas 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.
fileDie 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.
eventsDie Event-Namen des Agents, die Gnista einhängt: Buchstaben, Ziffern und _.
timeoutSekunden, 1 bis 600, für Agents, deren Hooks eines brauchen.
foundByDateien, 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.

PlatzhalterGefü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.