1
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# scuttlebot Bootstrap
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 is the primary conventions document. All agent shims (`CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `calliope.md`) point here.
4
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
An agent given this document and a business requirement should be able to generate correct, idiomatic code without exploring the codebase.
6
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
7
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
8
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
9
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Why IRC (and not NATS or RabbitMQ)
10
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
11
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
The short answer: IRC is a coordination protocol. NATS and RabbitMQ are message brokers. The difference matters.
12
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
13
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### IRC
14
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
15
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
IRC has presence, identity, channels, topics, ops hierarchy, DMs, and bots — natively. These map directly to agent coordination concepts without bolting anything on. A channel is a team. A topic is shared state. Ops are authority. Bots are services. It all just works.
16
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
17
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
It is also **human observable by default**. No dashboards, no special tooling, no translation layer. Open any IRC client, join a channel, and you see exactly what agents are doing. This is the single biggest advantage for debugging and operating agent systems.
18
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
19
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Other properties that matter for agent coordination:
20
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Latency tolerant** — fire-and-forget, designed for unreliable networks. Agents can reconnect, miss messages, catch up via history. This is a feature, not a limitation.
21
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Battle-tested** — 35+ years, RFC 1459 (1993), proven at scale. Not going anywhere.
22
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Self-hostable, zero vendor lock-in** — Ergo is MIT, single Go binary. No cloud, no subscription.
23
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Bots are a solved problem** — NickServ, ChanServ, BotServ, 35 years of tooling. We inherit all of it.
24
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Simple enough to debug naked** — the protocol is plain text. When something breaks, you can read it.
25
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
26
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Why not NATS
27
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
28
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
NATS is excellent and fast. It is the right choice when you need guaranteed delivery, high-throughput pub/sub, or JetStream persistence at scale. It is not the right choice here because:
29
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
30
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- No native presence model — you cannot `WHOIS` a subject or see who is subscribed to a stream
31
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- No ops hierarchy — authority and trust are not protocol concepts
32
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Not human observable without NATS-specific tooling (no standard client exists for "just watching")
33
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- More moving pieces — JetStream, clustering, leaf nodes, consumers, streams. Powerful but not simple.
34
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- The subject hierarchy (`project.myapp.tasks`) is conceptually identical to our channel naming convention — if we ever needed to swap, the mapping is straightforward
35
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
36
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Why not RabbitMQ
37
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
38
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
RabbitMQ is a serious enterprise message broker designed for guaranteed delivery workflows. It is operationally heavy (Erlang runtime, clustering, exchanges, bindings, queues), not human observable without a management UI, and not designed for real-time coordination between actors. Wrong tool for this job.
39
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
40
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Swappability
41
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
42
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
The JSON envelope format and the SDK abstraction (`pkg/client/`) are intentionally transport-agnostic. The channel naming convention maps cleanly to NATS subjects. If a use case demands NATS-level throughput or delivery guarantees, swapping the transport is a backend concern that does not affect the agent-facing API.
43
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
44
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
45
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
46
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## What is scuttlebot
47
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
48
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
An agent coordination backplane built on IRC. Agents connect as IRC users, coordinate via channels, and communicate via structured messages. IRC is an implementation detail — users configure scuttlebot, never Ergo directly.
49
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
50
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Why IRC:** lightweight TCP transport, encryption, channels, presence, ops hierarchy, DMs, human observable by default. Humans and agents share the same backplane with no translation layer.
51
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
52
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
**Ergo** (https://ergo.chat) is the IRC server. scuttlebot manages its lifecycle and config. Federation, auth, history, TLS, rate limiting — all Ergo. scuttlebot abstracts it.
53
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
54
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
55
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
56
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Monorepo Layout
57
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
58
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
59
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
cmd/
60
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot/ # daemon binary
61
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl/ # admin CLI
62
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
internal/apiclient/ # typed API client used by scuttlectl
63
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
internal/
64
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
api/ # HTTP API server (Bearer auth) + embedded web UI at /ui/
65
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ui/index.html # single-file operator web UI
66
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
auth/ # admin account store — bcrypt hashed, persisted to JSON
67
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
bots/
68
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
manager/ # bot lifecycle — starts/stops bots on policy change
69
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
auditbot/ # immutable append-only audit trail
70
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
herald/ # external event → channel routing (webhooks)
71
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
oracle/ # on-demand channel summarization via LLM (PM only)
72
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scribe/ # structured logging to rotating files
73
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scroll/ # history replay to PM on request
74
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
snitch/ # flood + join/part cycling detection → operator alerts
75
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
systembot/ # IRC system events (joins, parts, modes, kicks)
76
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
warden/ # channel moderation — warn → mute → kick
77
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
config/ # YAML config loading + validation
78
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
ergo/ # Ergo IRC server lifecycle + config generation
79
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
mcp/ # MCP server for AI agent connectivity
80
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
registry/ # agent registration + SASL credential issuance
81
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
topology/ # channel provisioning + mode/topic management
82
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
pkg/
83
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
client/ # Go agent SDK (public)
84
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
protocol/ # JSON envelope wire format
85
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
deploy/
86
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker/ # Dockerfile(s)
87
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
compose/ # Docker Compose (local dev + single-host)
88
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
k8s/ # Kubernetes manifests
89
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
standalone/ # single binary, no container required
90
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
tests/
91
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
e2e/ # Playwright end-to-end tests (require scuttlebot running)
92
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
go.mod
93
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
go.sum
94
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
bootstrap.md
95
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
CLAUDE.md # Claude Code shim — points here
96
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
97
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
98
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Single Go module. All state persisted as JSON files under `data/` (no database required).
99
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
100
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
101
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
102
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Architecture
103
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
104
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Ergo relationship
105
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
106
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlebot owns the Ergo process and config. Users never edit `ircd.yaml` directly. scuttlebot generates it from its own config and manages Ergo as a subprocess.
107
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
108
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Ergo provides: TLS, SASL accounts, channel persistence, message history, ops hierarchy, server federation, rate limiting
109
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- scuttlebot provides: agent registration, topology provisioning, rules-of-engagement delivery, built-in bots, SDK/MCP layer
110
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
111
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Agent lifecycle
112
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
113
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. Agent calls scuttlebot registration endpoint
114
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. scuttlebot creates Ergo account, issues SASL credentials
115
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3. On connect, agent receives signed rules-of-engagement payload (channel assignments, engagement rules, permissions)
116
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
4. Agent connects to Ergo with SASL credentials
117
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5. scuttlebot verifies presence, assigns channel modes
118
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
119
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Channel topology
120
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
121
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Hierarchical, configurable. Convention:
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!
#fleet fleet-wide, quiet, announcements only
125
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#project.{name} project coordination
126
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#project.{name}.{topic} swarming, chatty, active work
127
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#project.{name}.{topic}.{subtopic} deep nesting
128
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#task.{id} ephemeral, auto-created/destroyed
129
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
#agent.{name} agent-specific inbox
130
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
131
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
132
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Users define topology in scuttlebot config. scuttlebot provisions the channels, sets modes and topics.
133
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
134
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Wire format
135
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
136
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Agent messages:** JSON envelope in `PRIVMSG`
137
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **System/status:** `NOTICE` — human readable, machines ignore
138
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Agent context packets** (summarization, history replay): TOON format (token-efficient for LLM consumption)
139
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
140
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
JSON envelope structure:
141
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
142
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```json
143
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
{
144
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"v": 1,
145
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"type": "task.create",
146
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"id": "ulid",
147
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"from": "agent-nick",
148
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"ts": 1234567890,
149
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
"payload": {}
150
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
151
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
152
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
153
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Authority / trust hierarchy
154
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
155
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
IRC ops model maps directly:
156
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `+o` (channel op) — orchestrator agents, privileged
157
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `+v` (voice) — trusted worker agents
158
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- no mode — standard agents
159
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
160
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Built-in bots
161
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
162
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
All 10 bots are implemented. Enabled/configured via the web UI or `scuttlectl bot list`. The manager (`internal/bots/manager/`) starts/stops them dynamically when policies change. All bots set `+B` (bot) user mode on connect and auto-accept INVITE.
163
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
164
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Bot | Nick | Role |
165
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|-----|------|------|
166
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `auditbot` | auditbot | Immutable append-only audit trail of agent actions and credential events |
167
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `herald` | herald | Routes inbound webhook events to IRC channels |
168
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `oracle` | oracle | On-demand channel summarization via DM — calls any OpenAI-compatible LLM |
169
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `scribe` | scribe | Structured message logging to rotating files (jsonl/csv/text) |
170
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `scroll` | scroll | History replay to PM on request (`replay #channel [format=toon]`) |
171
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `sentinel` | sentinel | LLM-powered channel observer — detects policy violations, posts structured incident reports to mod channel. Never takes enforcement action. |
172
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `snitch` | snitch | Flood and join/part cycling detection, MONITOR-based presence tracking, away-notify alerts |
173
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `steward` | steward | Acts on sentinel incident reports — issues warnings, mutes (extended ban `m:`), or kicks based on severity |
174
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `systembot` | systembot | Logs IRC system events (joins, parts, quits, mode changes) |
175
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `warden` | warden | Channel moderation — warn → mute (extended ban) → kick on flood |
176
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
177
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Oracle uses TOON format (`pkg/toon/`) for token-efficient LLM context. Scroll supports `format=toon` for compact replay output. Configure `api_key_env` to the name of the env var holding the API key (e.g. `ORACLE_OPENAI_API_KEY`), and `base_url` for non-OpenAI providers.
178
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
179
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Scale
180
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
181
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Target: 100s to low 1000s of agents on a private network. Single Ergo instance handles this comfortably (documented up to 10k clients, 2k per channel). Ergo scales up (multi-core), not out — no horizontal clustering today. Federation is planned upstream but has no timeline; not a scuttlebot concern for now.
182
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
183
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Persistence
184
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
185
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
No database required. All state is persisted as JSON files under `data/` by default.
186
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
187
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| What | File | Notes |
188
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|------|------|-------|
189
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Agent registry | `data/ergo/registry.json` | Agent records + SASL credentials |
190
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Admin accounts | `data/ergo/admins.json` | bcrypt-hashed; created by `scuttlectl admin add` |
191
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Policies | `data/ergo/policies.json` | Bot config, agent policy, logging settings |
192
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Bot passwords | `data/ergo/bot_passwords.json` | Auto-generated SASL passwords for system bots |
193
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| API token | `data/ergo/api_token` | Legacy token; migrated to api_keys.json on first run |
194
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| API keys | `data/ergo/api_keys.json` | Per-consumer tokens with scoped permissions (SHA-256 hashed) |
195
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Ergo state | `data/ergo/ircd.db` | Ergo-native: accounts, channels, topics, history |
196
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| scribe logs | `data/logs/scribe/` | Rotating log files (jsonl/csv/text); configurable |
197
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
198
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
K8s / Docker: mount a PersistentVolume at `data/`. Ergo is single-instance — HA = fast pod restart with durable storage, not horizontal scaling.
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!
202
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Conventions
203
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
204
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Go
205
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
206
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Go 1.22+
207
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `gofmt` + `golangci-lint`
208
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Errors returned, not panicked. Wrap with context: `fmt.Errorf("registry: create account: %w", err)`
209
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Interfaces defined at point of use, not in the package that implements them
210
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- No global state. Dependencies injected via struct fields or constructor args.
211
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Config via struct + YAML/TOML — no env var spaghetti (env vars for secrets only)
212
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
213
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Tests
214
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
215
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- `go test ./...`
216
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Integration tests use a real Ergo instance (Docker Compose in CI)
217
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Assert against observable state — channel membership, messages received, account existence
218
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Both happy path and error cases
219
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- No mocking the IRC connection in integration tests
220
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
221
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Commits + branches
222
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
223
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Branch: `feature/{issue}-short-description` or `fix/{issue}-short-description`
224
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- No rebases. New commits only.
225
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- No AI attribution in commits.
226
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
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!
## HTTP 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!
`internal/api/` — two-mux pattern:
232
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
233
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Outer mux** (unauthenticated): `POST /login`, `GET /` (redirect), `GET /ui/` (web UI)
234
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- **Inner mux** (`/v1/` routes): require `Authorization: Bearer <token>` header
235
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
236
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Auth
237
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
238
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
API keys are per-consumer tokens with scoped permissions. Each key has a name, scopes, optional expiry, and last-used tracking. Scopes: `admin`, `agents`, `channels`, `chat`, `topology`, `bots`, `config`, `read`. The `admin` scope implies all others.
239
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
240
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
`POST /login` accepts `{username, password}` and returns a 24h session token with admin scope. Rate limited to 10 attempts per minute per IP.
241
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
242
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
On first run, the legacy `api_token` file is migrated into `api_keys.json` as the first admin-scope key. New keys are created via `POST /v1/api-keys`, `scuttlectl api-key create`, or the web UI settings tab.
243
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
244
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Admin accounts managed via `scuttlectl admin` or web UI. First run auto-creates `admin` with a random password printed to the log.
245
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
246
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Key endpoints
247
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
248
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
All `/v1/` endpoints require a Bearer token with the appropriate scope.
249
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
250
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Method | Path | Scope | Description |
251
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|--------|------|-------|-------------|
252
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/login` | — | Username/password login (unauthenticated) |
253
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/status` | read | Server status |
254
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/metrics` | read | Runtime metrics + bridge stats |
255
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/settings` | read | Full settings (policies, TLS, bot commands) |
256
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET/PUT/PATCH` | `/v1/settings/policies` | admin | Bot config, agent policy, logging |
257
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/agents` | agents | List all registered agents |
258
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/agents/{nick}` | agents | Get single agent |
259
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `PATCH` | `/v1/agents/{nick}` | agents | Update agent |
260
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/agents/register` | agents | Register an agent |
261
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/agents/{nick}/rotate` | agents | Rotate credentials |
262
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/agents/{nick}/adopt` | agents | Adopt existing IRC nick |
263
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/agents/{nick}/revoke` | agents | Revoke agent credentials |
264
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `DELETE` | `/v1/agents/{nick}` | agents | Delete agent |
265
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/channels` | channels | List joined channels |
266
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/channels/{ch}/join` | channels | Join channel |
267
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `DELETE` | `/v1/channels/{ch}` | channels | Leave channel |
268
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/channels/{ch}/messages` | channels | Get message history |
269
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/channels/{ch}/messages` | chat | Send message |
270
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/channels/{ch}/presence` | chat | Touch presence (keep web user visible) |
271
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/channels/{ch}/users` | channels | User list with IRC modes |
272
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/channels/{ch}/config` | channels | Per-channel display config |
273
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `PUT` | `/v1/channels/{ch}/config` | channels | Set display config (mirror detail, render mode) |
274
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/channels/{ch}/stream` | channels | SSE stream (`?token=` query param auth) |
275
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/channels` | topology | Provision channel via ChanServ |
276
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `DELETE` | `/v1/topology/channels/{ch}` | topology | Drop channel |
277
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/topology` | topology | Channel types, static channels, active channels |
278
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET/PUT` | `/v1/config` | config | Server config read/write |
279
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/config/history` | config | Config change history |
280
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET/POST` | `/v1/admins` | admin | List / add admin accounts |
281
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `DELETE` | `/v1/admins/{username}` | admin | Remove admin |
282
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `PUT` | `/v1/admins/{username}/password` | admin | Change password |
283
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET/POST` | `/v1/api-keys` | admin | List / create API keys |
284
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `DELETE` | `/v1/api-keys/{id}` | admin | Revoke API key |
285
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET/POST/PUT/DELETE` | `/v1/llm/backends[/{name}]` | bots | LLM backend CRUD |
286
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `GET` | `/v1/llm/backends/{name}/models` | bots | List models for backend |
287
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/llm/discover` | bots | Discover models from provider |
288
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| `POST` | `/v1/llm/complete` | bots | LLM completion proxy |
289
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
290
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
291
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
292
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Adding a New Bot
293
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
294
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. Create `internal/bots/{name}/` package with a `Bot` struct and `Start(ctx context.Context) error` method
295
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. Set `+B` user mode on connect, handle INVITE for auto-join
296
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3. Add a `BotSpec` config struct if the bot needs user-configurable settings
297
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
4. Register in `internal/bots/manager/manager.go`:
298
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Add a case to `buildBot()` that constructs your bot from the spec config
299
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
- Add a `BehaviorConfig` entry to `defaultBehaviors` in `internal/api/policies.go`
300
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
5. Add commands to `botCommands` map in `internal/api/policies.go` for the web UI command reference
301
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
6. Add the UI config schema to `BEHAVIOR_SCHEMAS` in `internal/api/ui/index.html`
302
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
7. Use `internal/bots/cmdparse/` for command routing if the bot accepts DM commands
303
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
8. Write tests: bot logic, config parsing, edge cases. IRC connection can be skipped in unit tests.
304
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
9. Update this bootstrap
305
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
306
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
No separate registration file or global registry. The manager builds bots by ID from the `BotSpec`. Bots satisfy the `bot` interface (unexported in manager package):
307
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
308
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```go
309
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
type bot interface {
310
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Start(ctx context.Context) error
311
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
}
312
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
313
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
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!
## Adding a New SDK
317
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
318
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
1. Create `sdk/{language}/` as its own module
319
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
2. Implement the client interface defined in `pkg/client/` as reference
320
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
3. Cover: connect, register, send message, receive message, disconnect
321
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
4. Own CI workflow in `.github/workflows/sdk-{language}.yml`
322
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
323
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
324
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
325
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Ports (local)
326
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
327
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Service | Address |
328
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|---------|---------|
329
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Ergo IRC | `ircs://localhost:6697` |
330
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| scuttlebot API | `http://localhost:8080` |
331
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| MCP server | `http://localhost:8081` |
332
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
333
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
---
334
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
335
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Common Commands
336
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
337
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```bash
338
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Dev helper (recommended)
339
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
./run.sh # build + start
340
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
./run.sh restart # rebuild + restart
341
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
./run.sh stop # stop
342
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
./run.sh token # print current API token
343
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
./run.sh log # tail the log
344
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
./run.sh test # go test ./...
345
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
./run.sh e2e # Playwright e2e (requires scuttlebot running)
346
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
347
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Direct Go commands
348
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
go build ./cmd/scuttlebot # build daemon
349
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
go build ./cmd/scuttlectl # build CLI
350
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
go test ./... # run all tests
351
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
golangci-lint run # lint
352
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
353
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Admin CLI
354
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl status # server health
355
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl admin list # list admin accounts
356
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl admin add alice # add admin (prompts for password)
357
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl admin passwd alice # change password
358
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl admin remove alice # remove admin
359
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl api-key list # list API keys
360
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl api-key create --name "relay" --scopes chat,channels
361
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl api-key revoke <id> # revoke key
362
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl topology list # show channel types + static channels
363
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl topology provision #channel # create channel
364
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl topology drop #channel # remove channel
365
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl config show # dump config JSON
366
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl config history # config change history
367
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl bot list # show system bot status
368
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl agent list # list agents
369
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl agent register <nick> --type worker --channels #fleet
370
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl agent rotate <nick> # rotate credentials
371
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
scuttlectl backend list # LLM backends
372
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
373
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Docker
374
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
docker compose -f deploy/compose/docker-compose.yml up
375
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
376
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
377
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
## Optional: IRC Chatbot Agents
378
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
379
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
`cmd/claude-agent`, `cmd/codex-agent`, and `cmd/gemini-agent` are standalone IRC bots that connect to a channel and respond to prompts using an LLM backend. They are **not part of the default build** — they exist as a reference pattern for operators who want a persistent chatbot presence in a channel.
380
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
381
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
These are distinct from the relay brokers (`claude-relay`, `codex-relay`, `gemini-relay`). The difference:
382
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
383
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| | Chatbot agent | Relay broker |
384
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
|---|---|---|
385
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Wraps a coding CLI | No | Yes |
386
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Reads/writes files, runs commands | No | Yes (via the CLI) |
387
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Always-on, responds to any mention | Yes | No — tied to an active session |
388
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
| Useful for fleet coordination | Novelty only | Core pattern |
389
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
390
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
The relay broker is the right tool for agent work. The chatbot agent is a nice-to-have for operators who want an LLM available in IRC for quick Q&A, but it cannot act — it can only respond.
391
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
392
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
### Running one
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!
# Build (not included in make all)
396
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
make chatbots
397
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
398
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Register a nick in scuttlebot
399
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
TOKEN=$(./run.sh token)
400
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
401
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-H "Content-Type: application/json" \
402
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
-d '{"nick":"claude","type":"worker","channels":["#general"]}' \
403
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
http://localhost:8080/v1/agents/register
404
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
405
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
# Connect (use the passphrase from the register response)
406
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
bin/claude-agent --irc 127.0.0.1:6667 --nick claude --pass <passphrase> \
407
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
--api-url http://localhost:8080 --token $TOKEN --backend anthro
408
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
```
409
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
410
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!
Swap `claude-agent` → `codex-agent` (backend `openai`) or `gemini-agent` (backend `gemini`) for other providers. All three accept the same flags.
411
{ copied = false; pop = false }, 1000)" :class="copied && 'copied'">
Copy link Copied!