自定义 Agent,
一行 JSON。

任何工具都能出现在 Gnista 里:工作中、完成,或需要你。不用等 Gnista 发新版,除了 Gnista 本身也不用装别的。每当有事发生,你的工具就把一行 JSON 交给 Gnista 的辅助程序。

更新于

试一试

在终端里,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> 是你的 Agent 的名字:最多 32 个小写字母、数字、- 和 _,以字母或数字开头。内置 Agent 的名字(claude、codex 等)已被占用。事件也可以写在这里而不写在 JSON 里,适合每个事件运行不同命令的工具。

JSON

每次调用一个 JSON 对象,从 stdin 传入:

键含义
session必填。在一个会话里保持不变的任意 ID(文本或数字)。
event必填,写在这里或命令行上。下面的事件之一。
cwd项目文件夹。会显示在行里;不填则用辅助程序自己所在的文件夹。
messageAgent 正在做的、在问的,或最后说的话。
tool正在用的工具,用于 tool 和 tool-done。
title会话标题,显示在文件夹的位置。
model模型,例如 gpt-5。Gnista 认识的模型会在图标上显示一个小角标;其他模型可以自己描述。
transcriptAgent 的记录文件,用于 details(版本 2)。Claude 风格的钩子会把它作为 transcript_path 发来。
pidAgent 的进程。进程退出,会话就结束。不填则用运行辅助程序的那个进程。

事件

匹配时不区分大小写,也不管分隔符:needs-you、NeedsYou 和 needs_you 是同一个。

事件在 Gnista 里
start会话出现,工作中。
prompt工作中:有人问了它问题。
tool工作中,显示“正在运行命令”“正在编辑 api.ts”或 message。
tool-done仍是工作中,除非这个工具在 doneAfterTools 里。
needs-you需要你:刘海会告诉你,并显示 message。
done这一轮结束了。
end会话结束了。

工作中的会话安静下来,几分钟后就变为空闲(设置 ▸ 通用 ▸ 视为空闲)。

Agent 文件

可选。放在 ~/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行和设置里显示的 Agent 名字,最多 40 个字符。不填则用命令里的名字。
icon同一文件夹里的 SVG 或 PNG 文件,最大 1 MB。不填则用 Gnista 自己的火花。
fields给发送自己格式 JSON 的工具用:上面 JSON 表格里每个值在哪里找。路径以 $ 开头,.key 取对象的键,[0] 取列表的项。没映射的字段照常从同名的键读取。
events你的工具的事件名,各自对应 Gnista 的哪个事件。"ignore" 会悄悄丢掉一个事件。名字按同样宽松的方式匹配;Gnista 自己的事件名照样有效。
hostAgent 所在应用的 bundle ID:Gnista 从进程看不出来时,点击会带你去那里。
jump一条跳转规则:见下文。
doneAfterTools给从不说一轮已结束的 Agent 用:用过其中任何一个工具之后(一个 tool-done 事件),这一轮就算结束。

超过 1 MB 的文件,或者有任何错误的文件(未知的键、不是路径的路径、Gnista 没有的事件),会被整个忽略。设置 ▸ 智能体 ▸ 自定义智能体会列出它并说明原因,辅助程序也会在 stderr 上说。在此期间,上面的简单格式照样能用。

让 Gnista 来接入

写上 "version": 2,文件还能告诉 Gnista 怎样接入你的 Agent,就像接入内置 Agent 那样:要在 Agent 自己的配置里放哪些钩子、怎样读懂它们发来的内容、它的权限请求能不能在刘海里回答,以及它的记录文件在哪里,这样它的行里就会显示你的提问、它的回复和花费。版本 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"
}
键作用
version2。
speaker句子里怎样称呼它:“Ralph 想运行……”。最多 40 个字符。不填则用 name。
colour它的颜色,写成 "#RRGGBB"。
adapter"fields"(默认):像版本 1 那样,用 fields 和 events 在你的工具的 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 除外)。

设置 ▸ 智能体会把你的 Agent 和其他 Agent 列在一起:在那里接入它,就会把 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 结尾。
fileAgent 的配置文件,相对于你的主文件夹,并且位于 Agent 自己的文件夹里:.ralph/settings.json。这个文件夹存在,就说明该 Agent 装在这台 Mac 上。
eventsGnista 要挂钩的 Agent 事件名:字母、数字和 _。
timeout秒数,1 到 600,给钩子需要超时设置的 Agent 用。
foundBy只有 Agent 自己才会写的文件,相对于你的主文件夹,用于仅凭它的文件夹还不能确定它已安装的情况(其他应用也会创建该文件夹)。

跳转规则

点一个会话,Gnista 会带你去它的终端标签页或窗口。对于它没法进入的应用,跳转规则给它一个 URL 去打开:先试过精确的标签页和窗口,再打开这个 URL,最后才只是把应用调到前台。

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

在 Agent 文件里写成 "jump";或者要对某个应用里的所有会话生效,放在 ~/Library/Application Support/Gnista/JumpRules/<bundle id>.json(例如 com.example.Editor.json)。Agent 自己的规则优先。

占位符填入
{session}会话 ID。
{cwd}项目文件夹。
{tty}终端,例如 /dev/ttys004。
{pid}Agent 的进程 ID。
{tmux_pane}tmux 窗格,例如 %3。

每个值都整体做百分号编码(/ 变成 %2F),所以改变不了 URL 的结构。占位符没有全部取到值的规则不会被使用。会打开文件或运行代码的 URL(file:、javascript:、data: 之类)一律拒绝。

在设置里

设置 ▸ 智能体 ▸ 自定义智能体列出每个有文件或汇报过的 Agent,以及 Gnista 最后一次收到它消息的时间。