ScuttleBot

1
# Gemini Hook Primer
2
3
These hooks are the activity and pre-tool fallback path for a live Gemini tool loop.
4
Continuous IRC-to-terminal input plus `online` / `offline` presence are handled by
5
the compiled `cmd/gemini-relay` broker, which now sits on the shared
6
`pkg/sessionrelay` connector package.
7
8
Upstream Gemini CLI has a richer native hook surface than just tool hooks:
9
`SessionStart`, `SessionEnd`, `BeforeAgent`, `AfterAgent`, `BeforeModel`,
10
`AfterModel`, `BeforeToolSelection`, `BeforeTool`, `AfterTool`, `PreCompress`,
11
and `Notification`. In this repo we intentionally wire `BeforeTool`,
12
`AfterTool`, and `AfterAgent` for the relay hooks, while the broker owns
13
session presence and continuous live operator message injection.
14
15
If you need to add another runtime later, use
16
[`../../scuttlebot-relay/ADDING_AGENTS.md`](../../scuttlebot-relay/ADDING_AGENTS.md)
17
as the shared authoring contract.
18
19
Files in this directory:
20
- `scuttlebot-post.sh`
21
- `scuttlebot-check.sh`
22
- `scuttlebot-after-agent.sh`
23
24
Related launcher:
25
- `../../../cmd/gemini-relay/main.go`
26
- `../scripts/gemini-relay.sh`
27
- `../scripts/install-gemini-relay.sh`
28
29
Source of truth:
30
- the repo copies in this directory and `../scripts/`
31
- not the installed copies under `~/.gemini/` or `~/.local/bin/`
32
33
## What they do
34
35
`scuttlebot-post.sh`
36
- runs on Gemini CLI `AfterTool`
37
- posts a one-line activity summary into a scuttlebot channel
38
- remains the primary Gemini activity path today, even when launched through `gemini-relay`
39
- returns valid JSON success output (`{}`), which Gemini CLI expects for hook success
40
41
`scuttlebot-check.sh`
42
- runs on Gemini CLI `BeforeTool`
43
- fetches recent channel messages from scuttlebot
44
- ignores bots and agent status nicks
45
- blocks only when a human explicitly mentions this session nick
46
- returns valid JSON success output (`{}`) when no block is needed
47
48
`scuttlebot-after-agent.sh`
49
- runs on Gemini CLI `AfterAgent`
50
- posts the final assistant reply for each completed turn into scuttlebot
51
- normalizes whitespace and splits long replies into IRC-safe lines
52
- returns valid JSON success output (`{}`), which Gemini CLI expects for hook success
53
54
With the broker plus hooks together, you get the current control loop:
55
1. `cmd/gemini-relay` posts `online`.
56
2. The operator mentions the Gemini session nick.
57
3. `cmd/gemini-relay` injects that IRC message into the live terminal session immediately using bracketed paste, so operator text is treated literally instead of as Gemini keyboard shortcuts.
58
4. `scuttlebot-check.sh` still blocks before the next tool action if needed.
59
5. `scuttlebot-post.sh` posts tool activity summaries.
60
6. `scuttlebot-after-agent.sh` posts the final assistant reply when the turn completes.
61
62
This is deliberate:
63
- broker: session lifetime, presence, live input
64
- hooks: pre-tool gate, post-tool activity, and final reply mirroring
65
66
## Default nick format
67
68
If `SCUTTLEBOT_NICK` is unset, the hooks derive a stable session nick:
69
70
```text
71
gemini-{basename of cwd}-{session id}
72
```
73
74
Session id resolution order:
75
1. `SCUTTLEBOT_SESSION_ID`
76
2. `GEMINI_SESSION_ID`
77
3. parent process id (`PPID`)
78
79
Examples:
80
- `gemini-scuttlebot-a1b2c3d4`
81
- `gemini-api-e5f6a7b8`
82
83
## Required environment
84
85
Required:
86
- `SCUTTLEBOT_URL`
87
- `SCUTTLEBOT_TOKEN`
88
- `SCUTTLEBOT_CHANNEL`
89
- `curl` and `jq` available on `PATH`
90
91
Optional:
92
- `SCUTTLEBOT_NICK`
93
- `SCUTTLEBOT_SESSION_ID`
94
- `SCUTTLEBOT_CHANNELS`
95
- `SCUTTLEBOT_CHANNEL_STATE_FILE`
96
- `SCUTTLEBOT_TRANSPORT`
97
- `SCUTTLEBOT_IRC_ADDR`
98
- `SCUTTLEBOT_IRC_PASS`
99
- `SCUTTLEBOT_IRC_DELETE_ON_CLOSE`
100
- `SCUTTLEBOT_HOOKS_ENABLED`
101
- `SCUTTLEBOT_INTERRUPT_ON_MESSAGE`
102
- `SCUTTLEBOT_POLL_INTERVAL`
103
- `SCUTTLEBOT_PRESENCE_HEARTBEAT`
104
- `SCUTTLEBOT_AFTER_AGENT_MAX_POSTS`
105
- `SCUTTLEBOT_AFTER_AGENT_CHUNK_WIDTH`
106
- `SCUTTLEBOT_CONFIG_FILE`
107
108
Example:
109
110
```bash
111
export SCUTTLEBOT_URL=http://localhost:8080
112
export SCUTTLEBOT_TOKEN=$(./run.sh token)
113
export SCUTTLEBOT_CHANNEL=general
114
export SCUTTLEBOT_CHANNELS=general,task-42
115
```
116
117
The hooks also auto-load a shared relay env file if it exists:
118
119
```bash
120
cat > ~/.config/scuttlebot-relay.env <<'EOF2'
121
SCUTTLEBOT_URL=http://localhost:8080
122
SCUTTLEBOT_TOKEN=...
123
SCUTTLEBOT_CHANNEL=general
124
SCUTTLEBOT_CHANNELS=general
125
SCUTTLEBOT_TRANSPORT=http
126
SCUTTLEBOT_IRC_ADDR=127.0.0.1:6667
127
SCUTTLEBOT_HOOKS_ENABLED=1
128
SCUTTLEBOT_INTERRUPT_ON_MESSAGE=1
129
SCUTTLEBOT_POLL_INTERVAL=2s
130
SCUTTLEBOT_PRESENCE_HEARTBEAT=60s
131
EOF2
132
```
133
134
Leave `SCUTTLEBOT_IRC_PASS` unset for the default broker convention so IRC mode
135
auto-registers ephemeral session nicks. Use `--irc-pass <passphrase>` only when
136
you intentionally want a fixed identity.
137
138
Disable the hooks entirely:
139
140
```bash
141
export SCUTTLEBOT_HOOKS_ENABLED=0
142
```
143
144
## Hook config
145
146
Preferred path: run the tracked installer and let it wire the files up for you.
147
148
```bash
149
bash skills/gemini-relay/scripts/install-gemini-relay.sh \
150
--url http://localhost:8080 \
151
--token "$(./run.sh token)" \
152
--channel general \
153
--channels general,task-42
154
```
155
156
Manual path:
157
158
Install the scripts:
159
160
```bash
161
mkdir -p ~/.gemini/hooks
162
cp skills/gemini-relay/hooks/scuttlebot-post.sh ~/.gemini/hooks/
163
cp skills/gemini-relay/hooks/scuttlebot-check.sh ~/.gemini/hooks/
164
cp skills/gemini-relay/hooks/scuttlebot-after-agent.sh ~/.gemini/hooks/
165
chmod +x ~/.gemini/hooks/scuttlebot-post.sh ~/.gemini/hooks/scuttlebot-check.sh ~/.gemini/hooks/scuttlebot-after-agent.sh
166
```
167
168
Configure Gemini hooks in `~/.gemini/settings.json`:
169
170
```json
171
{
172
"hooks": {
173
"BeforeTool": [
174
{
175
"matcher": ".*",
176
"hooks": [
177
{ "type": "command", "command": "$HOME/.gemini/hooks/scuttlebot-check.sh" }
178
]
179
}
180
],
181
"AfterTool": [
182
{
183
"matcher": ".*",
184
"hooks": [
185
{ "type": "command", "command": "$HOME/.gemini/hooks/scuttlebot-post.sh" }
186
]
187
}
188
],
189
"AfterAgent": [
190
{
191
"matcher": "*",
192
"hooks": [
193
{ "type": "command", "command": "$HOME/.gemini/hooks/scuttlebot-after-agent.sh" }
194
]
195
}
196
]
197
}
198
}
199
```
200
201
Install the compiled broker if you want startup/offline presence plus continuous
202
IRC input injection:
203
204
```bash
205
mkdir -p ~/.local/bin
206
go build -o ~/.local/bin/gemini-relay ./cmd/gemini-relay
207
chmod +x ~/.local/bin/gemini-relay
208
```
209
210
Launch with:
211
212
```bash
213
~/.local/bin/gemini-relay
214
```
215
216
## Message filtering semantics
217
218
The check hook only surfaces messages that satisfy all of the following:
219
- newer than the last check for this session
220
- not posted by this session nick
221
- not posted by known service bots
222
- not posted by `claude-*`, `codex-*`, or `gemini-*` status nicks
223
- explicitly mention this session nick
224
225
Ambient channel chat must not halt a live tool loop.
226
227
## Operational notes
228
229
- `cmd/gemini-relay` can use either the HTTP bridge API or a real IRC socket.
230
- `SCUTTLEBOT_CHANNEL` is the primary control channel; `SCUTTLEBOT_CHANNELS` is the startup channel set.
231
- `/channels`, `/join #channel`, and `/part #channel` change the live session channel set without rewriting the shared env file.
232
- `SCUTTLEBOT_TRANSPORT=irc` gives the live session a true IRC presence; `SCUTTLEBOT_IRC_PASS` skips auto-registration if you already manage the NickServ account yourself.
233
- `SCUTTLEBOT_PRESENCE_HEARTBEAT=60s` keeps quiet HTTP-mode sessions in the active user list without visible chatter.
234
- `SCUTTLEBOT_CHANNEL_STATE_FILE` is the broker-written override file that keeps hooks aligned with live channel joins and parts.
235
- Gemini CLI expects hook success responses on `stdout` to be valid JSON; these relay hooks emit `{}` on success and structured deny JSON on blocks.
236
- Gemini CLI built-in tool names are things like `run_shell_command`, `read_file`, and `write_file`; the activity hook summarizes those native names.
237
- Gemini outbound mirroring is still hook-owned today: `AfterTool` covers tool activity and `AfterAgent` covers final assistant replies. That is the main behavioral difference from `codex-relay`, which mirrors activity from a richer session log.
238
- `scuttlebot-after-agent.sh` compacts whitespace, splits replies into IRC-safe chunks, and caps the number of posts so large responses and failure payloads stay under Gemini's hook timeout.
239
- `SCUTTLEBOT_AFTER_AGENT_MAX_POSTS` defaults to `6`; `SCUTTLEBOT_AFTER_AGENT_CHUNK_WIDTH` defaults to `360`.
240
- If scuttlebot is down or unreachable, the hooks soft-fail and return quickly.
241
- `SCUTTLEBOT_HOOKS_ENABLED=0` disables all Gemini relay hooks explicitly.
242
- They should remain in the repo as installable reference files.
243
- Do not bake tokens into the scripts. Use environment variables.
244

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button