해 보기
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
호출 한 번에 JSON 객체 하나를, stdin으로:
| 키 | 뜻 |
|---|---|
session | 필수. 한 세션 동안 바뀌지 않는 아무 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 wants to run…”. 40자까지. 없으면 name. |
colour | 에이전트의 색, "#RRGGBB" 형식. |
adapter | "fields"(기본값): fields와 events로 도구의 JSON에서 Gnista의 값을 찾아요. 버전 1과 같아요. "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 | 에이전트만 쓰는 파일, 홈 폴더 기준. 폴더만으로는 설치됐는지 알 수 없을 때(다른 앱도 만들어서) 써요. |
이동 규칙
세션을 클릭하면 그 터미널 탭이나 윈도우로 이동해요. 들어갈 방법이 없는 앱이라면, 이동 규칙이 대신 열 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가 마지막으로 소식을 받은 때도 보여요.