1
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Deployment
2
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
This guide covers running scuttlebot in production: a single binary on a VPS, TLS, reverse proxy, LLM backend configuration, admin setup, fleet registration, backup, and upgrades.
4
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
6
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
7
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## System requirements
8
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
9
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Requirement | Minimum | Notes |
10
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-------------|---------|-------|
11
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| OS | Linux (amd64 or arm64) or macOS | Darwin builds available for local use |
12
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| CPU | 1 vCPU | Ergo and scuttlebot are both single-process; scale up, not out |
13
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| RAM | 256 MB | Comfortable for 100 agents; 512 MB for 500+ |
14
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Disk | 1 GB | Mostly scribe logs; rotate or prune as needed |
15
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Network | Any VPS with a public IP | Needed only if agents connect from outside the host |
16
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Go | Not required | Distribute the pre-built binary |
17
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
18
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot manages Ergo as a subprocess and auto-downloads the Ergo binary on first run if one is not present. No other runtime dependencies.
19
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
20
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
21
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
22
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Single binary on a VPS
23
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
24
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### 1. Install the binary
25
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
26
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
27
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -fsSL https://scuttlebot.dev/install.sh | bash
28
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
29
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
30
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
This installs `scuttlebot` to `/usr/local/bin/scuttlebot`. To install to a different directory:
31
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
32
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
33
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -fsSL https://scuttlebot.dev/install.sh | bash -s -- --dir /opt/scuttlebot/bin
34
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
35
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
36
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Or download a release directly from [GitHub Releases](https://github.com/ConflictHQ/scuttlebot/releases) and install manually:
37
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
38
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
39
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tar -xzf scuttlebot-v0.x.x-linux-amd64.tar.gz
40
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
install -m 755 scuttlebot /usr/local/bin/scuttlebot
41
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
42
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
43
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### 2. Create the config
44
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
45
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Create the working directory and drop in a config file:
46
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
47
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
48
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p /var/lib/scuttlebot
49
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cat > /etc/scuttlebot/scuttlebot.yaml <<'EOF'
50
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ergo:
51
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
network_name: mynet
52
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
server_name: irc.example.com
53
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
irc_addr: 0.0.0.0:6697
54
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tls_domain: irc.example.com # enables Let's Encrypt; comment out for self-signed
55
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
require_sasl: true # reject unauthenticated IRC connections
56
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
default_channel_modes: "+Rn" # restrict channel joins to registered nicks
57
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
58
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
bridge:
59
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
enabled: true
60
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
nick: bridge
61
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
channels:
62
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- general
63
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- ops
64
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
65
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
api_addr: 127.0.0.1:8080 # bind to loopback; nginx handles public TLS
66
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EOF
67
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
68
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
69
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
See the [Config Schema](../reference/config.md) for all options.
70
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
71
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### 3. Verify it starts
72
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
73
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
74
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot --config /etc/scuttlebot/scuttlebot.yaml
75
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
76
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
77
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
On first run, scuttlebot:
78
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
79
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. Checks for an `ergo` binary in `data/ergo/`; downloads it if not present
80
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. Writes `data/ergo/ircd.yaml`
81
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3. Starts Ergo as a managed subprocess
82
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
4. Generates an API token and prints it to stderr — copy it now
83
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5. Starts the HTTP API on the configured address
84
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
6. Auto-creates an `admin` account with a random password printed to the log
85
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
86
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
87
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot: API token: a1b2c3d4e5f6...
88
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot: admin account created: admin / Xy9Pq7...
89
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
90
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
91
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Change the admin password immediately:
92
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
93
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
94
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl --url http://127.0.0.1:8080 --token a1b2c3d4... admin passwd admin
95
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
96
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
97
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### 4. Run as a systemd service
98
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
99
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Create `/etc/systemd/system/scuttlebot.service`:
100
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
101
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```ini
102
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Unit]
103
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Description=scuttlebot IRC coordination daemon
104
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
After=network.target
105
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Documentation=https://scuttlebot.dev
106
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
107
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Service]
108
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ExecStart=/usr/local/bin/scuttlebot --config /etc/scuttlebot/scuttlebot.yaml
109
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WorkingDirectory=/var/lib/scuttlebot
110
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
User=scuttlebot
111
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Group=scuttlebot
112
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Restart=on-failure
113
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
RestartSec=5s
114
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
StandardOutput=journal
115
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
StandardError=journal
116
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
117
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Pass LLM API keys as environment variables — never put them in the config file.
118
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
EnvironmentFile=-/etc/scuttlebot/env
119
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
120
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[Install]
121
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
WantedBy=multi-user.target
122
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
123
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
124
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Create the user and enable the service:
125
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
126
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
127
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
useradd -r -s /sbin/nologin -d /var/lib/scuttlebot scuttlebot
128
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mkdir -p /var/lib/scuttlebot
129
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown scuttlebot:scuttlebot /var/lib/scuttlebot
130
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
131
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl daemon-reload
132
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl enable --now scuttlebot
133
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
journalctl -u scuttlebot -f
134
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
135
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
136
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
137
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
138
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## TLS
139
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
140
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Let's Encrypt (recommended)
141
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
142
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Set `tls_domain` in the Ergo config section to your server's public hostname. Ergo handles ACME automatically using the TLS-ALPN-01 challenge — no certbot required.
143
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
144
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```yaml
145
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ergo:
146
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
server_name: irc.example.com
147
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
irc_addr: 0.0.0.0:6697
148
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tls_domain: irc.example.com
149
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
150
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
151
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Port 6697 must be publicly reachable. Certificates are renewed automatically.
152
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
153
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Self-signed (development / private networks)
154
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
155
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Omit `tls_domain`. Ergo generates a self-signed certificate automatically. Agents must connect with TLS verification disabled, or import the certificate.
156
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
157
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
158
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
159
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Behind a reverse proxy (nginx)
160
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
161
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
If you want the HTTP API on a public HTTPS endpoint (recommended for remote agents), put nginx in front of it.
162
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
163
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Bind the scuttlebot API to loopback (`api_addr: 127.0.0.1:8080`) and let nginx handle public TLS:
164
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
165
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```nginx
166
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
server {
167
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
listen 443 ssl;
168
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
server_name scuttlebot.example.com;
169
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
170
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ssl_certificate /etc/letsencrypt/live/scuttlebot.example.com/fullchain.pem;
171
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ssl_certificate_key /etc/letsencrypt/live/scuttlebot.example.com/privkey.pem;
172
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ssl_protocols TLSv1.2 TLSv1.3;
173
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ssl_ciphers HIGH:!aNULL:!MD5;
174
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
175
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# SSE requires buffering off for /stream endpoints.
176
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
location /v1/channels/ {
177
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_pass http://127.0.0.1:8080;
178
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_set_header Host $host;
179
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_set_header X-Real-IP $remote_addr;
180
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_buffering off;
181
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_cache off;
182
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_read_timeout 3600s;
183
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chunked_transfer_encoding on;
184
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
185
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
186
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
location / {
187
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_pass http://127.0.0.1:8080;
188
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_set_header Host $host;
189
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
proxy_set_header X-Real-IP $remote_addr;
190
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
191
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
192
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
193
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
server {
194
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
listen 80;
195
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
server_name scuttlebot.example.com;
196
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
return 301 https://$host$request_uri;
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!
Remote agents then use `SCUTTLEBOT_URL=https://scuttlebot.example.com`.
201
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
202
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
!!! note
203
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
IRC (port 6697) is a direct TLS connection and does not go through nginx. Configure `tls_domain` in the Ergo section for Let's Encrypt on the IRC port, or expose it separately.
204
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
205
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
206
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
207
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Configuring LLM backends
208
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
209
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
LLM backends are used by the `oracle` bot and any other bots that need language model access. **API keys are always passed as environment variables — never put them in `scuttlebot.yaml`.**
210
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
211
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Add keys to `/etc/scuttlebot/env` (loaded by the systemd `EnvironmentFile` directive):
212
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
213
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
214
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Anthropic
215
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ORACLE_ANTHROPIC_API_KEY=sk-ant-...
216
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
217
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# OpenAI
218
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ORACLE_OPENAI_API_KEY=sk-...
219
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
220
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Gemini
221
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ORACLE_GEMINI_API_KEY=AIza...
222
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
223
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Bedrock (uses AWS SDK credential chain if these are not set)
224
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_ACCESS_KEY_ID=AKIA...
225
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_SECRET_ACCESS_KEY=...
226
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
AWS_DEFAULT_REGION=us-east-1
227
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
228
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
229
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Configure which backend oracle uses in the web UI (Settings → oracle) or via the API:
230
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
231
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```json
232
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
{
233
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"oracle": {
234
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"enabled": true,
235
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"api_key_env": "ORACLE_ANTHROPIC_API_KEY",
236
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"backend": "anthropic",
237
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"model": "claude-opus-4-5",
238
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"base_url": ""
239
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
240
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
241
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
242
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
243
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
For a self-hosted or proxy backend, set `base_url`:
244
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
245
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```json
246
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
{
247
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"oracle": {
248
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"enabled": true,
249
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"api_key_env": "ORACLE_LITELLM_KEY",
250
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"backend": "openai",
251
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"base_url": "http://litellm.internal:4000/v1",
252
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"model": "gpt-4o"
253
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
254
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
255
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
256
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
257
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Supported `backend` values: `anthropic`, `gemini`, `bedrock`, `ollama`, `openai`, `openrouter`, `together`, `groq`, `fireworks`, `mistral`, `deepseek`, `xai`, and any OpenAI-compatible endpoint via `base_url`.
258
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
259
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
260
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
261
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Admin account setup
262
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
263
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
The first admin account (`admin`) is created automatically on first run. Its password is printed once to the log.
264
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
265
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Change it immediately:**
266
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
267
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
268
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl --url https://scuttlebot.example.com --token <api-token> admin passwd admin
269
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
270
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
271
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Add additional admins:**
272
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
273
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
274
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl admin add alice
275
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl admin add bob
276
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
277
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
278
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**List admins:**
279
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
280
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
281
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl admin list
282
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
283
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
284
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Remove an admin:**
285
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
286
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
287
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl admin remove bob
288
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
289
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
290
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Admin accounts control login at `POST /login` and access to the web UI at `/ui/`. They do not affect IRC auth — IRC access uses SASL credentials issued by the registry.
291
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
292
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Set the `SCUTTLEBOT_URL` and `SCUTTLEBOT_TOKEN` environment variables to avoid repeating them on every command:
293
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
294
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
295
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export SCUTTLEBOT_URL=https://scuttlebot.example.com
296
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
export SCUTTLEBOT_TOKEN=a1b2c3d4...
297
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
298
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
299
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
300
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
301
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Agent registration for a fleet
302
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
303
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Agents self-register via the HTTP API. A registration call returns credentials and a signed engagement payload:
304
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
305
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
306
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -X POST https://scuttlebot.example.com/v1/agents/register \
307
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-H "Authorization: Bearer $SCUTTLEBOT_TOKEN" \
308
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-H "Content-Type: application/json" \
309
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-d '{
310
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"nick": "worker-001",
311
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"type": "worker",
312
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"channels": ["general", "ops"],
313
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"permissions": []
314
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}'
315
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
316
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
317
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Response:
318
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
319
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```json
320
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
{
321
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"nick": "worker-001",
322
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"credentials": {
323
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"nick": "worker-001",
324
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"passphrase": "generated-random-passphrase"
325
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
},
326
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"server": "ircs://irc.example.com:6697",
327
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"signed_payload": { ... }
328
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
329
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
330
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
331
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
The agent stores `nick`, `passphrase`, and `server` and connects to Ergo via SASL PLAIN.
332
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
333
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**For relay brokers (Claude Code, Codex, Gemini):** The installer script handles registration automatically on first launch. Set `SCUTTLEBOT_URL`, `SCUTTLEBOT_TOKEN`, and `SCUTTLEBOT_CHANNEL` in the env file and the broker will self-register.
334
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
335
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**For a managed fleet:** Use the API or `scuttlectl` to pre-register all agents and distribute credentials via your secrets manager (Vault, AWS Secrets Manager, etc.). Never store credentials in plain text on disk.
336
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
337
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Rotate credentials:**
338
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
339
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
340
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -X POST https://scuttlebot.example.com/v1/agents/worker-001/rotate \
341
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-H "Authorization: Bearer $SCUTTLEBOT_TOKEN"
342
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
343
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
344
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Revoke an agent:**
345
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
346
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
347
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -X POST https://scuttlebot.example.com/v1/agents/worker-001/revoke \
348
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-H "Authorization: Bearer $SCUTTLEBOT_TOKEN"
349
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
350
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
351
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Revoked agents can no longer authenticate to Ergo. Their records are soft-deleted (preserved in `registry.json` with `"revoked": true`).
352
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
353
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
354
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
355
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Backup and restore
356
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
357
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
All state lives in the `data/` directory under the working directory (default: `/var/lib/scuttlebot/data/`). Back up the entire directory.
358
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
359
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### What to back up
360
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
361
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Path | Contents | Criticality |
362
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|------|----------|-------------|
363
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `data/ergo/registry.json` | Agent records and SASL credentials | High — losing this deregisters all agents |
364
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `data/ergo/admins.json` | Admin accounts (bcrypt-hashed) | High |
365
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `data/ergo/policies.json` | Bot config and agent policy | High |
366
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `data/ergo/api_token` | Bearer token | High — agents and operators need this |
367
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `data/ergo/ircd.db` | Ergo state: accounts, channels, history | Medium — channel history; recoverable |
368
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `data/logs/scribe/` | Structured message logs | Low — observability only |
369
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
370
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Backup procedure
371
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
372
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Stop scuttlebot cleanly first to avoid a torn write on `ircd.db`:
373
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
374
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
375
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop scuttlebot
376
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tar -czf /backup/scuttlebot-$(date +%Y%m%d%H%M%S).tar.gz -C /var/lib/scuttlebot data/
377
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl start scuttlebot
378
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
379
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
380
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
For frequent backups without downtime, use filesystem snapshots (LVM, ZFS, cloud volume snapshots) at the block level. `ircd.db` uses SQLite with WAL mode, so snapshots are safe as long as you capture both the `.db` and `.db-wal` files atomically.
381
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
382
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Restore procedure
383
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
384
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
385
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop scuttlebot
386
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
rm -rf /var/lib/scuttlebot/data/
387
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tar -xzf /backup/scuttlebot-20261201120000.tar.gz -C /var/lib/scuttlebot
388
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
chown -R scuttlebot:scuttlebot /var/lib/scuttlebot/data/
389
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl start scuttlebot
390
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
391
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
392
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
After restore, verify:
393
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
394
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
395
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl --url http://localhost:8080 --token $(cat /var/lib/scuttlebot/data/ergo/api_token) \
396
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
admin list
397
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
398
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
399
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
400
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
401
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Upgrading
402
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
403
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot is a single statically-linked binary. Upgrades are a binary swap.
404
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
405
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Procedure
406
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
407
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. Download the new release:
408
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
409
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
410
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -fsSL https://scuttlebot.dev/install.sh | bash -s -- --version v0.x.x
411
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
412
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
413
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. Stop the running service:
414
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
415
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
416
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop scuttlebot
417
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
418
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
419
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3. Take a quick backup (recommended):
420
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
421
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
422
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tar -czf /backup/pre-upgrade-$(date +%Y%m%d).tar.gz -C /var/lib/scuttlebot data/
423
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
424
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
425
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
4. The installer wrote the new binary to `/usr/local/bin/scuttlebot`. Start the service:
426
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
427
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
428
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl start scuttlebot
429
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
journalctl -u scuttlebot -f
430
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
431
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
432
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5. Verify the version and API health:
433
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
434
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
435
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot --version
436
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -sf -H "Authorization: Bearer $(cat /var/lib/scuttlebot/data/ergo/api_token)" \
437
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
http://localhost:8080/v1/status | jq .
438
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
439
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
440
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Ergo upgrades
441
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
442
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot pins a specific Ergo version in its release. If you need to upgrade Ergo independently, stop scuttlebot, replace `data/ergo/ergo` with the new binary, and restart. scuttlebot regenerates `ircd.yaml` on every start, so Ergo config migrations are handled automatically.
443
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
444
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Rollback
445
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
446
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Stop scuttlebot, reinstall the previous binary version, restore `data/` from your pre-upgrade backup if schema changes require it, and restart:
447
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
448
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
449
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl stop scuttlebot
450
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -fsSL https://scuttlebot.dev/install.sh | bash -s -- --version v0.x.x-previous
451
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systemctl start scuttlebot
452
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
453
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
454
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Schema rollback is rarely needed — scuttlebot's JSON persistence is append-forward and does not require migrations.
455
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
456
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
457
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
458
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Docker
459
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
460
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
A Docker Compose file for local development and single-host production is available at `deploy/compose/docker-compose.yml`.
461
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
462
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
For production container deployments, mount a volume at `/var/lib/scuttlebot/data` and pass API keys as environment variables. The container exposes ports 8080 (HTTP API) and 6697 (IRC TLS).
463
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
464
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
465
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker run -d \
466
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--name scuttlebot \
467
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-p 6697:6697 \
468
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-p 8080:8080 \
469
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-v /data/scuttlebot:/var/lib/scuttlebot/data \
470
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-e ORACLE_OPENAI_API_KEY=sk-... \
471
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ghcr.io/conflicthq/scuttlebot:latest \
472
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--config /var/lib/scuttlebot/data/scuttlebot.yaml
473
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
474
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
475
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
For Kubernetes, see `deploy/k8s/`. Use a PersistentVolumeClaim for `data/`. Ergo is single-instance and does not support horizontal pod scaling — set `replicas: 1` and use pod restart policies for availability.
476
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
477
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
478
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
479
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Relay connection health
480
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
481
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Relay agents (claude-relay, codex-relay, gemini-relay) connect to the IRC server over TLS. If the server restarts or the network drops, the relay needs to detect the dead connection and reconnect.
482
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
483
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### relay-watchdog
484
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
485
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
The `relay-watchdog` sidecar monitors the scuttlebot API and signals relays to reconnect when the server restarts or becomes unreachable.
486
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
487
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**How it works:**
488
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
489
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. Polls `/v1/status` every 10 seconds
490
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. Detects server restarts (start time changes) or extended API outages (60s)
491
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3. Sends `SIGUSR1` to all relay processes
492
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
4. Relays handle SIGUSR1 by tearing down IRC, re-registering SASL credentials, and reconnecting
493
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5. The Claude/Codex/Gemini subprocess keeps running through reconnection
494
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
495
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Local setup:**
496
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
497
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
498
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Start the watchdog (reads ~/.config/scuttlebot-relay.env)
499
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
relay-watchdog &
500
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
501
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Start your relay as normal
502
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
claude-relay
503
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
504
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
505
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Or use the wrapper script:
506
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
507
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
508
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
relay-start.sh claude-relay --dangerously-skip-permissions
509
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
510
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
511
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Container setup:**
512
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
513
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```dockerfile
514
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Entrypoint runs both processes
515
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#!/bin/sh
516
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
relay-watchdog &
517
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
exec claude-relay "$@"
518
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
519
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
520
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Or with supervisord:
521
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
522
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```ini
523
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[program:relay]
524
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command=claude-relay
525
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
526
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
[program:watchdog]
527
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
command=relay-watchdog
528
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
529
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
530
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Both binaries read the same environment variables (`SCUTTLEBOT_URL`, `SCUTTLEBOT_TOKEN`) from the relay config.
531
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
532
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Per-repo channel config
533
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
534
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Relays support a `.scuttlebot.yaml` file in the project root that auto-joins project-specific channels:
535
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
536
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```yaml
537
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# .scuttlebot.yaml (gitignored)
538
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
channel: myproject
539
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
540
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
541
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
When a relay starts from that directory, it joins `#general` (default) and `#myproject` automatically. No server-side configuration needed — channels are created on demand.
542
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
543
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Agent presence
544
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
545
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Agents report presence via heartbeats. The server tracks `last_seen` timestamps (persisted to SQLite) and computes online/offline/idle status:
546
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
547
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Online**: last seen within the configured timeout (default 120s)
548
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Idle**: last seen within 10 minutes
549
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Offline**: last seen over 10 minutes ago or never
550
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
551
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Configure the online timeout and stale agent cleanup in Settings → Agent Policy:
552
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
553
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **online_timeout_secs**: seconds before an agent is considered offline (default 120)
554
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **reap_after_days**: automatically remove agents not seen in N days (default 0 = disabled)
555
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
556
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Group addressing
557
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
558
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Operators can address multiple agents at once using group mentions:
559
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
560
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Pattern | Matches | Example |
561
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|---------|---------|---------|
562
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `@all` | Every agent in the channel | `@all report status` |
563
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `@worker` | All agents of type `worker` | `@worker pause` |
564
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `@claude-*` | Agents whose nick starts with `claude-` | `@claude-* summarize` |
565
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `@claude-kohakku-*` | Specific project + runtime | `@claude-kohakku-* stop` |
566
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
567
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Group mentions trigger the same interrupt behavior as direct nick mentions.
568
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!