Agents maison,
une ligne de JSON.

N’importe quel outil peut apparaître dans Gnista : au travail, terminé, ou qui vous attend. Pas besoin d’une nouvelle version de Gnista, rien à installer à part Gnista lui-même. À chaque événement, votre outil envoie une ligne de JSON à l’utilitaire de Gnista.

Mis à jour le

Essayer

Dans un terminal, avec Gnista lancé :

G=/Applications/Gnista.app/Contents/Helpers/gnista
echo '{"session":"demo","event":"needs-you","message":"Ralph wants to deploy","cwd":"'"$PWD"'"}' | "$G" hook custom ralph

Une session de « Ralph » apparaît, qui vous attend. Cliquez dessus et vous revoilà dans ce terminal. Ensuite :

echo '{"session":"demo","event":"done","message":"Deployed"}' | "$G" hook custom ralph
echo '{"session":"demo","event":"end"}' | "$G" hook custom ralph

L’utilitaire sort toujours avec 0 et n’attend jamais : il ne peut pas bloquer votre outil. Si ce que vous envoyez cloche, il le dit sur stderr et n’envoie rien.

La commande

gnista hook custom <name> [event]

<name> est le nom de votre agent : jusqu’à 32 lettres minuscules, chiffres, - et _, en commençant par une lettre ou un chiffre. Les noms des agents intégrés (claude, codex et les autres) sont pris. L’événement peut être donné ici plutôt que dans le JSON, pour les outils qui lancent une commande différente par événement.

Le JSON

Un objet JSON par appel, sur stdin :

CléCe que c’est
sessionObligatoire. N’importe quel identifiant qui reste le même pendant une session (texte ou nombre).
eventObligatoire, ici ou sur la ligne de commande. L’un des événements ci-dessous.
cwdLe dossier du projet. Les lignes l’affichent ; sans lui, le dossier de l’utilitaire.
messageCe que l’agent fait, demande ou a dit en dernier.
toolL’outil en cours, pour tool et tool-done.
titleLe titre de la session, affiché à la place du dossier.
modelLe modèle, par exemple gpt-5. Les modèles que Gnista connaît apparaissent en petit badge sur l’icône ; pour les autres, décrivez-les vous-même.
transcriptLa transcription de l’agent, pour details (version 2). Les hooks de type Claude l’envoient sous le nom transcript_path.
pidLe processus de l’agent. Quand il se termine, la session aussi. Sans lui, le processus qui a lancé l’utilitaire.

Les événements

Sans tenir compte de la casse ni des séparateurs : needs-you, NeedsYou et needs_you reviennent au même.

ÉvénementDans Gnista
startLa session apparaît, au travail.
promptAu travail : quelqu’un lui a demandé quelque chose.
toolAu travail, avec « Exécute une commande », « Modifie api.ts » ou le message.
tool-doneToujours au travail, sauf si l’outil fait partie de doneAfterTools.
needs-youVous attend : l’encoche le dit, avec le message.
doneLe tour est terminé.
endLa session est finie.

Une session au travail qui ne dit plus rien passe au repos après quelques minutes (Réglages ▸ Général ▸ Inactif après).

Le fichier d’agent

Facultatif. Placez-le dans  /Library/Application Support/Gnista/Agents/<name>.json. Chaque clé est facultative :

{
  "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"]
}
CléCe qu’elle fait
nameLe nom de l’agent dans les lignes et les réglages, jusqu’à 40 caractères. Sans elle, le nom de la commande.
iconUn fichier SVG ou PNG dans le même dossier, jusqu’à 1 Mo. Sans elle, l’étincelle de Gnista.
fieldsPour les outils qui envoient leur propre JSON : où trouver chaque valeur du tableau JSON ci-dessus. Les chemins partent de $, avec .key pour la clé d’un objet et [0] pour l’élément d’une liste. Un champ que vous n’indiquez pas est lu à sa clé habituelle.
eventsLes noms d’événements de votre outil, et à quel événement de Gnista chacun correspond. "ignore" en écarte un sans bruit. Les noms se comparent avec la même souplesse ; ceux de Gnista marchent toujours.
hostL’identifiant de bundle de l’app où tourne l’agent : là où mène un clic quand Gnista ne peut pas le savoir par le processus.
jumpUne règle de saut : voir plus bas.
doneAfterToolsPour les agents qui ne disent jamais qu’un tour est fini : après l’un de ces outils (un événement tool-done), il l’est.

Un fichier de plus de 1 Mo, ou avec la moindre erreur (une clé inconnue, un chemin qui n’en est pas un, un événement que Gnista n’a pas), est ignoré en entier. Réglages ▸ Agents ▸ Agents personnalisés l’affiche avec la raison, et l’utilitaire le dit sur stderr. Le format simple ci-dessus fonctionne toujours en attendant.

Laisser Gnista le connecter

Avec "version": 2, le fichier peut aussi dire à Gnista comment connecter votre agent, comme il connecte ceux qui sont intégrés : quels hooks mettre dans la configuration de l’agent, comment lire ce qu’ils envoient, si ses demandes d’autorisation peuvent recevoir une réponse depuis l’encoche, et où se trouve sa transcription, pour que sa ligne affiche votre prompt, sa réponse et le coût. Les clés de la version 1 gardent leur sens.

{
  "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"
}
CléCe qu’elle fait
version2.
speakerComment une phrase le nomme : « Ralph veut exécuter… ». Jusqu’à 40 caractères. Sans elle, le name.
colourSa couleur, sous la forme "#RRGGBB".
adapter"fields" (par défaut) : fields et events trouvent les valeurs de Gnista dans le JSON de votre outil, comme en version 1. "claude-style" : votre outil envoie les payloads de hooks de Claude Code ; events associe alors ses propres noms d’événements à ceux de Claude.
toolNamesAvec claude-style : les noms que votre outil donne aux outils de Claude, comme {"run_shell": "Bash"}, pour que les lignes et les demandes se lisent pareil.
hooksCe que Gnista installe quand vous le connectez : le tableau ci-dessous.
approvalsSes demandes d’autorisation attendent l’encoche : "plain" (autoriser ou refuser), "answers" (avec des réponses à ses questions) ou "claude" (avec des réponses, des règles « Toujours » et un mode). Seulement avec claude-style et un hook claude-table pour PermissionRequest.
detailsLe format de sa transcription, s’il en écrit une que Gnista lit : "claude", "codex", "gemini" ou "antigravity". Les lignes affichent alors son prompt, sa réponse et, sauf pour antigravity, le coût.

Réglages ▸ Agents liste alors votre agent avec les autres : le connecter ajoute les hooks de Gnista au fichier que vous avez indiqué, et le déconnecter les retire. Gnista ne modifie que ses propres entrées, et sauvegarde le fichier d’abord. Les hooks appellent gnista hook custom <name>, avec l’événement.

Dans « hooks »Ce que ça fait
format"claude-table" : {"hooks": {"<event>": [{"hooks": [{"type": "command", …}]}]}} de Claude Code, l’événement dans le payload. "flat" : {"hooks": {"<event>": [{"command": …}]}}, l’événement sur la ligne de commande. "toml" : des blocs [[hooks]] avec event et command, dans un fichier qui se termine par .toml.
fileLa configuration de l’agent, relative à votre dossier personnel et dans un dossier propre à l’agent : .ralph/settings.json. Que ce dossier soit là signifie que l’agent est sur ce Mac.
eventsLes noms d’événements de l’agent que Gnista accroche : lettres, chiffres et _.
timeoutEn secondes, de 1 à 600, pour les agents dont les hooks en acceptent un.
foundByDes fichiers que seul l’agent écrit, relatifs à votre dossier personnel, quand son dossier seul ne prouve pas qu’il est installé (d’autres apps le créent aussi).

Les règles de saut

Quand vous cliquez sur une session, Gnista vous emmène à son onglet ou à sa fenêtre de terminal. Pour les apps où il n’a aucun moyen d’entrer, une règle de saut lui donne une URL à ouvrir à la place : après avoir essayé l’onglet et la fenêtre exacts, et avant de simplement mettre l’app au premier plan.

{ "url": "myeditor://focus?folder={cwd}&pane={tmux_pane}" }

Utilisez-la comme "jump" dans un fichier d’agent, ou pour toutes les sessions d’une app, dans  /Library/Application Support/Gnista/JumpRules/<bundle id>.json (par exemple com.example.Editor.json). La règle propre à un agent passe en premier.

MarqueurRemplacé par
{session}L’identifiant de la session.
{cwd}Le dossier du projet.
{tty}Le terminal, par exemple /dev/ttys004.
{pid}L’identifiant de processus de l’agent.
{tmux_pane}Le volet tmux, par exemple %3.

Chaque valeur est encodée en entier (/ devient %2F) : elle ne peut pas changer la forme de l’URL. Une règle dont les marqueurs n’ont pas tous une valeur n’est pas utilisée. Les URL qui ouvrent des fichiers ou exécutent du code (file:, javascript:, data: et consorts) sont refusées.

Dans les réglages

Réglages ▸ Agents ▸ Agents personnalisés liste chaque agent qui a un fichier ou qui s’est déjà signalé, et quand Gnista a eu de ses nouvelles pour la dernière fois.