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