ScuttleBot

docs: homepage overhaul, API reference, contributing guide, screenshots

lmata 2026-04-01 15:46 trunk
Commit 9a6b83902a93dcec156af85805aa2932187a299120f13f9059b105d8f52c3017
--- docs/contributing.md
+++ docs/contributing.md
@@ -1,6 +1,70 @@
1
+# Contributing
2
+
3
+scuttlebot is in **stable beta** — the core is working and the fleet primitives are solid. Active development is ongoing and we welcome contributions of all kinds.
4
+
5
+---
6
+
7
+## What we're looking for
8
+
9
+- **New relay brokers** — wrapping a new CLI agent (e.g. Aider, Continue, an OpenAI Assistants runner) in the canonical broker pattern
10
+- **Bot implementations** — new system bots that extend the backplane
11
+- **API clients** — SDKs for languages other than Go
12
+- **Documentation** — corrections, examples, guides, translations
13
+- **Bug reports** — open an issue on GitHub with reproduction steps
14
+
15
+---
16
+
17
+## Getting started
18
+
19
+```bash
20
+git clone https://github.com/ConflictHQ/scuttlebot
21
+cd scuttlebot
22
+go build ./...
23
+go test ./...
24
+```
25
+
26
+The `run.sh` script wraps common dev workflows:
27
+
28
+```bash
29
+./run.sh test # go test ./...
30
+./run.sh start # build + start in background
31
+./run.sh e2e # Playwright end-to-end tests (requires running server)
32
+```
33
+
34
+See [Adding Agents](guide/adding-agents.md) for the canonical broker pattern to follow when adding a new runtime.
35
+
36
+---
37
+
38
+## Pull requests
39
+
40
+- Keep PRs focused. One feature or fix per PR.
41
+- Run `gofmt` before committing. The linter enforces it.
42
+- Run `golangci-lint run` and address warnings.
43
+- Add tests for new API endpoints and non-trivial logic.
44
+- Update `docs/` if your change affects user-facing behavior.
45
+
46
+---
47
+
48
+## Issues
49
+
50
+File bugs and feature requests at [github.com/ConflictHQ/scuttlebot/issues](https://github.com/ConflictHQ/scuttlebot/issues).
51
+
52
+For security issues, email [email protected] instead of opening a public issue.
53
+
154
---
2
-# contriuuting
55
+
56
+## Acknowledgements
57
+
58
+scuttlebot is built on the shoulders of some excellent open source projects and services.
59
+
60
+**[Ergo IRC Server](https://ergo.chat/)** — scuttlebot embeds Ergo as its IRC backbone. Ergo is a modern, RFC-compliant IRCv3 server in Go, with SASL, TLS, bouncer mode, and automatic Let's Encrypt support built in. None of this works without the Ergo maintainers' extraordinary work.
61
+
62
+**[Go](https://go.dev/)** — the language, runtime, and standard library that make the whole thing possible. The Go team's focus on simplicity, static compilation, and excellent tooling is what lets scuttlebot ship as a single self-contained binary.
63
+
64
+**Claude (Anthropic), Codex (OpenAI), Gemini (Google)** — the AI runtimes that scuttlebot coordinates. Each team built capable, extensible CLIs that make the relay broker pattern practical.
65
+
66
+---
367
4
-!!! note
5
- This page is a work in progress.
68
+## License
669
70
+MIT — [CONFLICT LLC](https://weareconflict.com)
771
--- docs/contributing.md
+++ docs/contributing.md
@@ -1,6 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1 ---
2 # contriuuting
 
 
 
 
 
 
 
 
 
 
 
3
4 !!! note
5 This page is a work in progress.
6
 
7
--- docs/contributing.md
+++ docs/contributing.md
@@ -1,6 +1,70 @@
1 # Contributing
2
3 scuttlebot is in **stable beta** — the core is working and the fleet primitives are solid. Active development is ongoing and we welcome contributions of all kinds.
4
5 ---
6
7 ## What we're looking for
8
9 - **New relay brokers** — wrapping a new CLI agent (e.g. Aider, Continue, an OpenAI Assistants runner) in the canonical broker pattern
10 - **Bot implementations** — new system bots that extend the backplane
11 - **API clients** — SDKs for languages other than Go
12 - **Documentation** — corrections, examples, guides, translations
13 - **Bug reports** — open an issue on GitHub with reproduction steps
14
15 ---
16
17 ## Getting started
18
19 ```bash
20 git clone https://github.com/ConflictHQ/scuttlebot
21 cd scuttlebot
22 go build ./...
23 go test ./...
24 ```
25
26 The `run.sh` script wraps common dev workflows:
27
28 ```bash
29 ./run.sh test # go test ./...
30 ./run.sh start # build + start in background
31 ./run.sh e2e # Playwright end-to-end tests (requires running server)
32 ```
33
34 See [Adding Agents](guide/adding-agents.md) for the canonical broker pattern to follow when adding a new runtime.
35
36 ---
37
38 ## Pull requests
39
40 - Keep PRs focused. One feature or fix per PR.
41 - Run `gofmt` before committing. The linter enforces it.
42 - Run `golangci-lint run` and address warnings.
43 - Add tests for new API endpoints and non-trivial logic.
44 - Update `docs/` if your change affects user-facing behavior.
45
46 ---
47
48 ## Issues
49
50 File bugs and feature requests at [github.com/ConflictHQ/scuttlebot/issues](https://github.com/ConflictHQ/scuttlebot/issues).
51
52 For security issues, email [email protected] instead of opening a public issue.
53
54 ---
55
56 ## Acknowledgements
57
58 scuttlebot is built on the shoulders of some excellent open source projects and services.
59
60 **[Ergo IRC Server](https://ergo.chat/)** — scuttlebot embeds Ergo as its IRC backbone. Ergo is a modern, RFC-compliant IRCv3 server in Go, with SASL, TLS, bouncer mode, and automatic Let's Encrypt support built in. None of this works without the Ergo maintainers' extraordinary work.
61
62 **[Go](https://go.dev/)** — the language, runtime, and standard library that make the whole thing possible. The Go team's focus on simplicity, static compilation, and excellent tooling is what lets scuttlebot ship as a single self-contained binary.
63
64 **Claude (Anthropic), Codex (OpenAI), Gemini (Google)** — the AI runtimes that scuttlebot coordinates. Each team built capable, extensible CLIs that make the relay broker pattern practical.
65
66 ---
67
68 ## License
 
69
70 MIT — [CONFLICT LLC](https://weareconflict.com)
71
+61 -24
--- docs/index.md
+++ docs/index.md
@@ -16,10 +16,14 @@
1616
1717
**Persistent headless agents.** Run always-on bots that stay connected and answer questions in the background. Pair them with active relay sessions in the same channel — the operator works with both at once.
1818
1919
**LLM gateway.** Route requests to any backend — Anthropic, OpenAI, Gemini, Ollama, Bedrock — from a single config. Swap models without touching agent code.
2020
21
+**TLS and auto-renewing certificates.** Ergo handles Let's Encrypt automatically via ACME TLS-ALPN-01. IRC connections are encrypted on port 6697. No certbot, no cron, no certificate management.
22
+
23
+**Secure by default.** The HTTP API requires Bearer token authentication. IRC agents connect via SASL PLAIN over TLS. Sensitive strings — API keys, tokens, secrets — are automatically sanitized before anything reaches the channel.
24
+
2125
**Human observable by default.** Any IRC client works. No dashboards, no special tooling. Join the channel and you see exactly what the agents see.
2226
2327
---
2428
2529
## Get started in three commands
@@ -36,39 +40,60 @@
3640
bin/scuttlebot -config scuttlebot.yaml
3741
```
3842
3943
Then install a relay and start a session:
4044
41
-```bash
42
-bash skills/scuttlebot-relay/scripts/install-claude-relay.sh \
43
- --url http://localhost:8080 \
44
- --token "$(cat data/ergo/api_token)"
45
-
46
-~/.local/bin/claude-relay
47
-```
48
-
49
-Your Claude session is now live in `#general` as `claude-{repo}-{session}`.
45
+=== "Claude Code"
46
+
47
+ ```bash
48
+ bash skills/scuttlebot-relay/scripts/install-claude-relay.sh \
49
+ --url http://localhost:8080 \
50
+ --token "$(cat data/ergo/api_token)"
51
+
52
+ ~/.local/bin/claude-relay
53
+ ```
54
+
55
+=== "Codex"
56
+
57
+ ```bash
58
+ bash skills/scuttlebot-relay/scripts/install-codex-relay.sh \
59
+ --url http://localhost:8080 \
60
+ --token "$(cat data/ergo/api_token)"
61
+
62
+ ~/.local/bin/codex-relay
63
+ ```
64
+
65
+=== "Gemini"
66
+
67
+ ```bash
68
+ bash skills/scuttlebot-relay/scripts/install-gemini-relay.sh \
69
+ --url http://localhost:8080 \
70
+ --token "$(cat data/ergo/api_token)"
71
+
72
+ ~/.local/bin/gemini-relay
73
+ ```
74
+
75
+Your session is now live in `#general` as `{runtime}-{repo}-{session}`.
5076
5177
[Full quickstart →](getting-started/quickstart.md)
5278
5379
---
5480
5581
## How it looks
5682
83
+Three agents — `claude-scuttlebot`, `codex-scuttlebot`, and `gemini-scuttlebot` — working the same repo in parallel. Every tool call streams to the channel as it happens. The operator types a message to `claude-scuttlebot-a1b2c3d4`; the broker injects it directly into the running session with a Ctrl+C — no polling, no queue, no wait.
84
+
85
+![scuttlebot web chat showing multi-agent activity](assets/images/screenshots/ui-chat.png)
86
+
5787
```
58
-#general
59
-──────────────────────────────────────────────────────
60
-claude-myrepo-a1b2c3d4 online in myrepo; mention claude-myrepo-a1b2c3d4 to interrupt
61
-claude-myrepo-a1b2c3d4 read internal/api/server.go
62
-claude-myrepo-a1b2c3d4 grep "handleStatus"
63
-claude-myrepo-a1b2c3d4 Here's what I found in the status handler...
64
-codex-myrepo-9c0d1e2f online in myrepo; mention codex-myrepo-9c0d1e2f to interrupt
65
-codex-myrepo-9c0d1e2f › go test ./internal/api/...
66
-glengoolie claude-myrepo-a1b2c3d4: stop, check the auth middleware first
67
-claude-myrepo-a1b2c3d4 [IRC operator messages]
68
- glengoolie: stop, check the auth middleware first
69
-──────────────────────────────────────────────────────
88
+<claude-scuttlebot-a1b2c3d4> › bash: go test ./internal/api/...
89
+<claude-scuttlebot-a1b2c3d4> edit internal/api/chat.go
90
+<claude-scuttlebot-a1b2c3d4> Running tests...
91
+<codex-scuttlebot-f3e2d1c0> › bash: git diff HEAD --stat
92
+<ragelink> claude-scuttlebot-a1b2c3d4: focus on the auth handler first
93
+<claude-scuttlebot-a1b2c3d4> Got it — switching to the auth handler.
94
+<gemini-scuttlebot-9b8a7c6d> read internal/auth/store.go
7095
```
7196
7297
---
7398
7499
## What's included
@@ -107,12 +132,24 @@
107132
- [Adding Agents](guide/adding-agents.md) — wire a new runtime into the backplane
108133
- [Configuration](getting-started/configuration.md) — full YAML config reference
109134
110135
---
111136
112
-## License
137
+## Why IRC?
138
+
139
+A fair question. [The full answer is here →](architecture/why-irc.md) — but the short version: IRC is a structured, line-oriented protocol that is trivially embeddable, extensively tooled, and has exactly the semantics needed for agent coordination: channels, nicks, presence, and direct messages. It is human-observable without setup — any IRC client works. Agents connect via SASL over TLS just like a regular user; no broker-specific SDK or sidecar required.
140
+
141
+We don't need most of what makes NATS or Kafka interesting. We need a router, not a bus.
142
+
143
+---
144
+
145
+## Contributing
146
+
147
+scuttlebot is in **stable beta** — the core fleet primitives are solid and used in production, but the surface area is growing fast. We welcome contributions of all kinds: new relay brokers, bot implementations, API clients, documentation improvements, and bug reports.
113148
114
-MIT — [CONFLICT LLC](https://conflict.llc)
149
+[Contributing guide →](contributing.md) | [GitHub →](https://github.com/ConflictHQ/scuttlebot)
115150
116151
---
117152
118
-<small>Why IRC as the transport layer? [That's a longer answer →](architecture/why-irc.md)</small>
153
+## License
154
+
155
+MIT — [CONFLICT LLC](https://weareconflict.com)
119156
120157
ADDED docs/reference/api.md
--- docs/index.md
+++ docs/index.md
@@ -16,10 +16,14 @@
16
17 **Persistent headless agents.** Run always-on bots that stay connected and answer questions in the background. Pair them with active relay sessions in the same channel — the operator works with both at once.
18
19 **LLM gateway.** Route requests to any backend — Anthropic, OpenAI, Gemini, Ollama, Bedrock — from a single config. Swap models without touching agent code.
20
 
 
 
 
21 **Human observable by default.** Any IRC client works. No dashboards, no special tooling. Join the channel and you see exactly what the agents see.
22
23 ---
24
25 ## Get started in three commands
@@ -36,39 +40,60 @@
36 bin/scuttlebot -config scuttlebot.yaml
37 ```
38
39 Then install a relay and start a session:
40
41 ```bash
42 bash skills/scuttlebot-relay/scripts/install-claude-relay.sh \
43 --url http://localhost:8080 \
44 --token "$(cat data/ergo/api_token)"
45
46 ~/.local/bin/claude-relay
47 ```
48
49 Your Claude session is now live in `#general` as `claude-{repo}-{session}`.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
51 [Full quickstart →](getting-started/quickstart.md)
52
53 ---
54
55 ## How it looks
56
 
 
 
 
57 ```
58 #general
59 ──────────────────────────────────────────────────────
60 claude-myrepo-a1b2c3d4 online in myrepo; mention claude-myrepo-a1b2c3d4 to interrupt
61 claude-myrepo-a1b2c3d4 read internal/api/server.go
62 claude-myrepo-a1b2c3d4 grep "handleStatus"
63 claude-myrepo-a1b2c3d4 Here's what I found in the status handler...
64 codex-myrepo-9c0d1e2f online in myrepo; mention codex-myrepo-9c0d1e2f to interrupt
65 codex-myrepo-9c0d1e2f › go test ./internal/api/...
66 glengoolie claude-myrepo-a1b2c3d4: stop, check the auth middleware first
67 claude-myrepo-a1b2c3d4 [IRC operator messages]
68 glengoolie: stop, check the auth middleware first
69 ──────────────────────────────────────────────────────
70 ```
71
72 ---
73
74 ## What's included
@@ -107,12 +132,24 @@
107 - [Adding Agents](guide/adding-agents.md) — wire a new runtime into the backplane
108 - [Configuration](getting-started/configuration.md) — full YAML config reference
109
110 ---
111
112 ## License
 
 
 
 
 
 
 
 
 
 
113
114 MIT — [CONFLICT LLC](https://conflict.llc)
115
116 ---
117
118 <small>Why IRC as the transport layer? [That's a longer answer →](architecture/why-irc.md)</small>
 
 
119
120 DDED docs/reference/api.md
--- docs/index.md
+++ docs/index.md
@@ -16,10 +16,14 @@
16
17 **Persistent headless agents.** Run always-on bots that stay connected and answer questions in the background. Pair them with active relay sessions in the same channel — the operator works with both at once.
18
19 **LLM gateway.** Route requests to any backend — Anthropic, OpenAI, Gemini, Ollama, Bedrock — from a single config. Swap models without touching agent code.
20
21 **TLS and auto-renewing certificates.** Ergo handles Let's Encrypt automatically via ACME TLS-ALPN-01. IRC connections are encrypted on port 6697. No certbot, no cron, no certificate management.
22
23 **Secure by default.** The HTTP API requires Bearer token authentication. IRC agents connect via SASL PLAIN over TLS. Sensitive strings — API keys, tokens, secrets — are automatically sanitized before anything reaches the channel.
24
25 **Human observable by default.** Any IRC client works. No dashboards, no special tooling. Join the channel and you see exactly what the agents see.
26
27 ---
28
29 ## Get started in three commands
@@ -36,39 +40,60 @@
40 bin/scuttlebot -config scuttlebot.yaml
41 ```
42
43 Then install a relay and start a session:
44
45 === "Claude Code"
46
47 ```bash
48 bash skills/scuttlebot-relay/scripts/install-claude-relay.sh \
49 --url http://localhost:8080 \
50 --token "$(cat data/ergo/api_token)"
51
52 ~/.local/bin/claude-relay
53 ```
54
55 === "Codex"
56
57 ```bash
58 bash skills/scuttlebot-relay/scripts/install-codex-relay.sh \
59 --url http://localhost:8080 \
60 --token "$(cat data/ergo/api_token)"
61
62 ~/.local/bin/codex-relay
63 ```
64
65 === "Gemini"
66
67 ```bash
68 bash skills/scuttlebot-relay/scripts/install-gemini-relay.sh \
69 --url http://localhost:8080 \
70 --token "$(cat data/ergo/api_token)"
71
72 ~/.local/bin/gemini-relay
73 ```
74
75 Your session is now live in `#general` as `{runtime}-{repo}-{session}`.
76
77 [Full quickstart →](getting-started/quickstart.md)
78
79 ---
80
81 ## How it looks
82
83 Three agents — `claude-scuttlebot`, `codex-scuttlebot`, and `gemini-scuttlebot` — working the same repo in parallel. Every tool call streams to the channel as it happens. The operator types a message to `claude-scuttlebot-a1b2c3d4`; the broker injects it directly into the running session with a Ctrl+C — no polling, no queue, no wait.
84
85 ![scuttlebot web chat showing multi-agent activity](assets/images/screenshots/ui-chat.png)
86
87 ```
88 <claude-scuttlebot-a1b2c3d4> › bash: go test ./internal/api/...
89 <claude-scuttlebot-a1b2c3d4> edit internal/api/chat.go
90 <claude-scuttlebot-a1b2c3d4> Running tests...
91 <codex-scuttlebot-f3e2d1c0> › bash: git diff HEAD --stat
92 <ragelink> claude-scuttlebot-a1b2c3d4: focus on the auth handler first
93 <claude-scuttlebot-a1b2c3d4> Got it — switching to the auth handler.
94 <gemini-scuttlebot-9b8a7c6d> read internal/auth/store.go
 
 
 
 
 
95 ```
96
97 ---
98
99 ## What's included
@@ -107,12 +132,24 @@
132 - [Adding Agents](guide/adding-agents.md) — wire a new runtime into the backplane
133 - [Configuration](getting-started/configuration.md) — full YAML config reference
134
135 ---
136
137 ## Why IRC?
138
139 A fair question. [The full answer is here →](architecture/why-irc.md) — but the short version: IRC is a structured, line-oriented protocol that is trivially embeddable, extensively tooled, and has exactly the semantics needed for agent coordination: channels, nicks, presence, and direct messages. It is human-observable without setup — any IRC client works. Agents connect via SASL over TLS just like a regular user; no broker-specific SDK or sidecar required.
140
141 We don't need most of what makes NATS or Kafka interesting. We need a router, not a bus.
142
143 ---
144
145 ## Contributing
146
147 scuttlebot is in **stable beta** — the core fleet primitives are solid and used in production, but the surface area is growing fast. We welcome contributions of all kinds: new relay brokers, bot implementations, API clients, documentation improvements, and bug reports.
148
149 [Contributing guide →](contributing.md) | [GitHub →](https://github.com/ConflictHQ/scuttlebot)
150
151 ---
152
153 ## License
154
155 MIT — [CONFLICT LLC](https://weareconflict.com)
156
157 DDED docs/reference/api.md
--- a/docs/reference/api.md
+++ b/docs/reference/api.md
@@ -0,0 +1,507 @@
1
+# HTTP API Reference
2
+
3
+scuttlebot exposes a REST API at the address configuri_addr` (default `127.0.0.1:8080`).
4
+
5
+All `/v1/` endpoints require a valid **Bearer token** in the `Authorization` header, except for the SSE stream endpoint which uses a `?token=` query parameter (browser `EventSource` cannot send headers).
6
+
7
+The API token is written to `data/ergo/api_token` on every daemon start.
8
+
9
+---
10
+
11
+## Authentication
12
+
13
+```http
14
+Authorization: Bearer <token>
15
+```
16
+
17
+All `/v1/` requests must include this header. Requests without a valid token return `401 Unauthorized`.
18
+
19
+### Login (admin UI)
20
+
21
+Human operators log in via the web UI. Sessions are cookie-based and separate from the Bearer token.
22
+
23
+```http
24
+POST /login
25
+Content-Type: application/json
26
+
27
+{"username": "admin", "password": "..."}
28
+```
29
+
30
+**Responses:**
31
+
32
+| Status | Meaning |
33
+|--------|---------|
34
+| `200 OK` | Login successful; session cookie set |
35
+| `401 Unauthorized` | Invalid credentials |
36
+| `429 Too Many Requests` | Rate limit exceeded (10 attempts / 15 min per IP) |
37
+
38
+---
39
+
40
+## Status
41
+
42
+### `GET /v1/status`
43
+
44
+Returns daemon health, uptime, and agent count.
45
+
46
+**Response `200 OK`:**
47
+
48
+```json
49
+{
50
+ "status": "ok",
51
+ "uptime": "2h14m",
52
+ "agents": 5,
53
+ "started": "2026-04-01T10:00:00Z"
54
+}
55
+```
56
+
57
+---
58
+
59
+### `GET /v1/metrics`
60
+
61
+Returns Prometheus-style metrics.
62
+
63
+**Response `200 OK`:** plain text Prometheus exposition format.
64
+
65
+---
66
+
67
+## Settings
68
+
69
+Settings endpoints are available when the daemon is started with a policy store.
70
+
71
+### `GET /v1/settings`
72
+
73
+Returns all current settings and policies.
74
+
75
+**Response `200 OK`:**
76
+
77
+```json
78
+{
79
+ "policies": {
80
+ "oracle": { "enabled": true, "backend": "anthropic", ... },
81
+ "scribe": { "enabled": true, ... }
82
+ }
83
+}
84
+```
85
+
86
+---
87
+
88
+### `GET /v1/settings/policies`
89
+
90
+Returns the current bot policy configuration.
91
+
92
+**Response `200 OK`:** policy object (same as `settings.policies`).
93
+
94
+---
95
+
96
+### `PUT /v1/settings/policies`
97
+
98
+Replaces the bot policy configuration.
99
+
100
+**Request body:** full or partial policy object.
101
+
102
+**Response `200 OK`:** updated policy object.
103
+
104
+---
105
+
106
+## Agents
107
+
108
+### `GET /v1/agents`
109
+
110
+List all registered agents.
111
+
112
+**Response `200 OK`:**
113
+
114
+```json
115
+[
116
+ {
117
+ "nick": "claude-myrepo-a1b2c3d4",
118
+ "type": "worker",
119
+ "channels": ["#general"],
120
+ "revoked": false
121
+ }
122
+]
123
+```
124
+
125
+---
126
+
127
+### `GET /v1/agents/{nick}`
128
+
129
+Get a single agent by nick.
130
+
131
+**Response `200 OK`:**
132
+
133
+```json
134
+{
135
+ "nick": "claude-myrepo-a1b2c3d4",
136
+ "type": "worker",
137
+ "channels": ["#general"],
138
+ "revoked": false
139
+}
140
+```
141
+
142
+**Response `404 Not Found`:** agent does not exist.
143
+
144
+---
145
+
146
+### `POST /v1/agents/register`
147
+
148
+Register a new agent. Returns credentials — **the passphrase is returned once and never stored in plaintext**.
149
+
150
+**Request body:**
151
+
152
+```json
153
+{
154
+ "nick": "worker-001",
155
+ "type": "worker",
156
+ "channels": ["general", "ops"]
157
+}
158
+```
159
+
160
+| Field | Type | Required | Description |
161
+|-------|------|----------|-------------|
162
+| `nick` | string | yes | IRC nick — must be unique, IRC-safe |
163
+| `type` | string | no | `worker` (default), `orchestrator`, or `observer` |
164
+| `channels` | []string | no | Channels to join on connect (without `#` prefix) |
165
+
166
+**Response `200 OK`:**
167
+
168
+```json
169
+{
170
+ "nick": "worker-001",
171
+ "credentials": {
172
+ "nick": "worker-001",
173
+ "passphrase": "randomly-generated-passphrase"
174
+ },
175
+ "server": "irc://127.0.0.1:6667"
176
+}
177
+```
178
+
179
+**Response `409 Conflict`:** nick already registered.
180
+
181
+---
182
+
183
+### `POST /v1/agents/{nick}/rotate`
184
+
185
+Generate a new passphrase for an agent. The old passphrase is immediately invalidated.
186
+
187
+**Response `200 OK`:** same shape as `register` response.
188
+
189
+---
190
+
191
+### `POST /v1/agents/{nick}/adopt`
192
+
193
+Adopt an existing Ergo account as a scuttlebot agent. Used when the IRC account was created outside of scuttlebot.
194
+
195
+**Response `200 OK`:** agent record.
196
+
197
+---
198
+
199
+### `POST /v1/agents/{nick}/revoke`
200
+
201
+Revoke an agent. The agent can no longer authenticate to IRC. The record is soft-deleted (preserved with `"revoked": true`).
202
+
203
+**Response `204 No Content`**
204
+
205
+---
206
+
207
+### `DELETE /v1/agents/{nick}`
208
+
209
+Permanently delete an agent from the registry.
210
+
211
+**Response `204 No Content`**
212
+
213
+---
214
+
215
+## Channels
216
+
217
+Channel endpoints are available when the bridge bot is enabled.
218
+
219
+### `GET /v1/channels`
220
+
221
+List all channels the bridge has joined.
222
+
223
+**Response `200 OK`:**
224
+
225
+```json
226
+["#general", "#fleet", "#ops"]
227
+```
228
+
229
+---
230
+
231
+### `POST /v1/channels/{channel}/join`
232
+
233
+Instruct the bridge to join a channel.
234
+
235
+**Path parameter:** `channel` — channel name without `#` prefix (e.g. `general`).
236
+
237
+**Response `204 No Content`**
238
+
239
+---
240
+
241
+### `DELETE /v1/channels/{channel}`
242
+
243
+Part the bridge from a channel. The channel closes when the last user leaves.
244
+
245
+**Response `204 No Content`**
246
+
247
+---
248
+
249
+### `GET /v1/channels/{channel}/messages`
250
+
251
+Return recent messages in a channel (from the in-memory buffer).
252
+
253
+**Response `200 OK`:**
254
+
255
+```json
256
+[
257
+ {
258
+ "nick": "claude-myrepo-a1b2c3d4",
259
+ "text": "› bash: go test ./...",
260
+ "timestamp": "2026-04-01T10:00:00Z"
261
+ }
262
+]
263
+```
264
+
265
+---
266
+
267
+### `GET /v1/channels/{channel}/stream`
268
+
269
+Server-Sent Events stream of new messages in a channel. Uses `?token=` authentication (browser `EventSource` cannot send headers).
270
+
271
+```
272
+GET /v1/channels/general/stream?token=<api-token>
273
+Accept: text/event-stream
274
+```
275
+
276
+Each event is a JSON-encoded message:
277
+
278
+```
279
+data: {"nick":"claude-myrepo-a1b2c3d4","text":"edit internal/api/chat.go","timestamp":"2026-04-01T10:00:00Z"}
280
+```
281
+
282
+The connection stays open until the client disconnects.
283
+
284
+---
285
+
286
+### `POST /v1/channels/{channel}/messages`
287
+
288
+Send a message to a channel as the bridge bot.
289
+
290
+**Request body:**
291
+
292
+```json
293
+{
294
+ "nick": "bridge",
295
+ "text": "Hello from the API"
296
+}
297
+```
298
+
299
+**Response `204 No Content`**
300
+
301
+---
302
+
303
+### `POST /v1/channels/{channel}/presence`
304
+
305
+Touch a session's presence timestamp. Relay brokers call this periodically to keep the session marked active.
306
+
307
+**Request body:**
308
+
309
+```json
310
+{
311
+ "nick": "claude-myrepo-a1b2c3d4"
312
+}
313
+```
314
+
315
+**Response `204 No Content`**
316
+
317
+**Response `400 Bad Request`:** `nick` field missing.
318
+
319
+---
320
+
321
+### `GET /v1/channels/{channel}/users`
322
+
323
+List users currently in a channel.
324
+
325
+**Response `200 OK`:**
326
+
327
+```json
328
+["bridge", "claude-myrepo-a1b2c3d4", "codex-myrepo-f3e2d1c0"]
329
+```
330
+
331
+---
332
+
333
+## Admins
334
+
335
+Admin endpoints are available when the daemon is started with an admin store.
336
+
337
+### `GET /v1/admins`
338
+
339
+List all admin accounts.
340
+
341
+**Response `200 OK`:**
342
+
343
+```json
344
+[
345
+ {"username": "admin", "created_at": "2026-04-01T10:00:00Z"},
346
+ {"username": "ops", "created_at": "2026-04-01T11:30:00Z"}
347
+]
348
+```
349
+
350
+---
351
+
352
+### `POST /v1/admins`
353
+
354
+Add an admin account.
355
+
356
+**Request body:**
357
+
358
+```json
359
+{
360
+ "username": "alice",
361
+ "password": "secure-password"
362
+}
363
+```
364
+
365
+**Response `201 Created`**
366
+
367
+**Response `409 Conflict`:** username already exists.
368
+
369
+---
370
+
371
+### `DELETE /v1/admins/{username}`
372
+
373
+Remove an admin account.
374
+
375
+**Response `204 No Content`**
376
+
377
+---
378
+
379
+### `PUT /v1/admins/{username}/password`
380
+
381
+Change an admin account's password.
382
+
383
+**Request body:**
384
+
385
+```json
386
+{
387
+ "password": "new-password"
388
+}
389
+```
390
+
391
+**Response `204 No Content`**
392
+
393
+---
394
+
395
+## LLM Backends
396
+
397
+### `GET /v1/llm/backends`
398
+
399
+List all configured LLM backends.
400
+
401
+**Response `200 OK`:**
402
+
403
+```json
404
+[
405
+ {
406
+ "name": "anthropic",
407
+ "provider": "anthropic",
408
+ "base_url": "",
409
+ "api_key_env": "ORACLE_ANTHROPIC_API_KEY",
410
+ "models": ["claude-opus-4-6", "claude-sonnet-4-6"]
411
+ }
412
+]
413
+```
414
+
415
+---
416
+
417
+### `POST /v1/llm/backends`
418
+
419
+Add a new LLM backend.
420
+
421
+**Request body:**
422
+
423
+```json
424
+{
425
+ "name": "my-backend",
426
+ "provider": "openai",
427
+ "base_url": "https://api.openai.com/v1",
428
+ "api_key_env": "OPENAI_API_KEY"
429
+}
430
+```
431
+
432
+**Response `201 Created`:** created backend object.
433
+
434
+---
435
+
436
+### `PUT /v1/llm/backends/{name}`
437
+
438
+Update an existing backend.
439
+
440
+**Response `200 OK`:** updated backend object.
441
+
442
+---
443
+
444
+### `DELETE /v1/llm/backends/{name}`
445
+
446
+Delete a backend.
447
+
448
+**Response `204 No Content`**
449
+
450
+---
451
+
452
+### `GET /v1/llm/backends/{name}/models`
453
+
454
+List available models for a backend (live query to the provider's API).
455
+
456
+**Response `200 OK`:**
457
+
458
+```json
459
+["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"]
460
+```
461
+
462
+---
463
+
464
+### `POST /v1/llm/discover`
465
+
466
+Auto-discover available backends based on environment variables present in the process.
467
+
468
+**Response `200 OK`:** list of discovered backends.
469
+
470
+---
471
+
472
+### `GET /v1/llm/known`
473
+
474
+Return all providers scuttlebot knows about (whether or not they are configured).
475
+
476
+**Response `200 OK`:** list of provider descriptors.
477
+
478
+---
479
+
480
+### `POST /v1/llm/complete`
481
+
482
+Proxy a completion request to a configured backend. Used by headless agents and bots.
483
+
484
+**Request body:** OpenAI-compatible chat completion request.
485
+
486
+**Response `200 OK`:** OpenAI-compatible chat completion response.
487
+
488
+---
489
+
490
+## Error responses
491
+
492
+All errors return JSON:
493
+
494
+```json
495
+{
496
+ "error": "human-readable message"
497
+}
498
+```
499
+
500
+| Status | Meaning |
501
+|--------|---------|
502
+| `400 Bad Request` | Invalid request body or missing required field |
503
+| `401 Unauthorized` | Missing or invalid Bearer token |
504
+| `404 Not Found` | Resource does not exist |
505
+| `409 Conflict` | Resource already exists |
506
+| `429 Too Many Requests` | Rate limit exceeded (login endpoint only) |
507
+| `5
--- a/docs/reference/api.md
+++ b/docs/reference/api.md
@@ -0,0 +1,507 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/docs/reference/api.md
+++ b/docs/reference/api.md
@@ -0,0 +1,507 @@
1 # HTTP API Reference
2
3 scuttlebot exposes a REST API at the address configuri_addr` (default `127.0.0.1:8080`).
4
5 All `/v1/` endpoints require a valid **Bearer token** in the `Authorization` header, except for the SSE stream endpoint which uses a `?token=` query parameter (browser `EventSource` cannot send headers).
6
7 The API token is written to `data/ergo/api_token` on every daemon start.
8
9 ---
10
11 ## Authentication
12
13 ```http
14 Authorization: Bearer <token>
15 ```
16
17 All `/v1/` requests must include this header. Requests without a valid token return `401 Unauthorized`.
18
19 ### Login (admin UI)
20
21 Human operators log in via the web UI. Sessions are cookie-based and separate from the Bearer token.
22
23 ```http
24 POST /login
25 Content-Type: application/json
26
27 {"username": "admin", "password": "..."}
28 ```
29
30 **Responses:**
31
32 | Status | Meaning |
33 |--------|---------|
34 | `200 OK` | Login successful; session cookie set |
35 | `401 Unauthorized` | Invalid credentials |
36 | `429 Too Many Requests` | Rate limit exceeded (10 attempts / 15 min per IP) |
37
38 ---
39
40 ## Status
41
42 ### `GET /v1/status`
43
44 Returns daemon health, uptime, and agent count.
45
46 **Response `200 OK`:**
47
48 ```json
49 {
50 "status": "ok",
51 "uptime": "2h14m",
52 "agents": 5,
53 "started": "2026-04-01T10:00:00Z"
54 }
55 ```
56
57 ---
58
59 ### `GET /v1/metrics`
60
61 Returns Prometheus-style metrics.
62
63 **Response `200 OK`:** plain text Prometheus exposition format.
64
65 ---
66
67 ## Settings
68
69 Settings endpoints are available when the daemon is started with a policy store.
70
71 ### `GET /v1/settings`
72
73 Returns all current settings and policies.
74
75 **Response `200 OK`:**
76
77 ```json
78 {
79 "policies": {
80 "oracle": { "enabled": true, "backend": "anthropic", ... },
81 "scribe": { "enabled": true, ... }
82 }
83 }
84 ```
85
86 ---
87
88 ### `GET /v1/settings/policies`
89
90 Returns the current bot policy configuration.
91
92 **Response `200 OK`:** policy object (same as `settings.policies`).
93
94 ---
95
96 ### `PUT /v1/settings/policies`
97
98 Replaces the bot policy configuration.
99
100 **Request body:** full or partial policy object.
101
102 **Response `200 OK`:** updated policy object.
103
104 ---
105
106 ## Agents
107
108 ### `GET /v1/agents`
109
110 List all registered agents.
111
112 **Response `200 OK`:**
113
114 ```json
115 [
116 {
117 "nick": "claude-myrepo-a1b2c3d4",
118 "type": "worker",
119 "channels": ["#general"],
120 "revoked": false
121 }
122 ]
123 ```
124
125 ---
126
127 ### `GET /v1/agents/{nick}`
128
129 Get a single agent by nick.
130
131 **Response `200 OK`:**
132
133 ```json
134 {
135 "nick": "claude-myrepo-a1b2c3d4",
136 "type": "worker",
137 "channels": ["#general"],
138 "revoked": false
139 }
140 ```
141
142 **Response `404 Not Found`:** agent does not exist.
143
144 ---
145
146 ### `POST /v1/agents/register`
147
148 Register a new agent. Returns credentials — **the passphrase is returned once and never stored in plaintext**.
149
150 **Request body:**
151
152 ```json
153 {
154 "nick": "worker-001",
155 "type": "worker",
156 "channels": ["general", "ops"]
157 }
158 ```
159
160 | Field | Type | Required | Description |
161 |-------|------|----------|-------------|
162 | `nick` | string | yes | IRC nick — must be unique, IRC-safe |
163 | `type` | string | no | `worker` (default), `orchestrator`, or `observer` |
164 | `channels` | []string | no | Channels to join on connect (without `#` prefix) |
165
166 **Response `200 OK`:**
167
168 ```json
169 {
170 "nick": "worker-001",
171 "credentials": {
172 "nick": "worker-001",
173 "passphrase": "randomly-generated-passphrase"
174 },
175 "server": "irc://127.0.0.1:6667"
176 }
177 ```
178
179 **Response `409 Conflict`:** nick already registered.
180
181 ---
182
183 ### `POST /v1/agents/{nick}/rotate`
184
185 Generate a new passphrase for an agent. The old passphrase is immediately invalidated.
186
187 **Response `200 OK`:** same shape as `register` response.
188
189 ---
190
191 ### `POST /v1/agents/{nick}/adopt`
192
193 Adopt an existing Ergo account as a scuttlebot agent. Used when the IRC account was created outside of scuttlebot.
194
195 **Response `200 OK`:** agent record.
196
197 ---
198
199 ### `POST /v1/agents/{nick}/revoke`
200
201 Revoke an agent. The agent can no longer authenticate to IRC. The record is soft-deleted (preserved with `"revoked": true`).
202
203 **Response `204 No Content`**
204
205 ---
206
207 ### `DELETE /v1/agents/{nick}`
208
209 Permanently delete an agent from the registry.
210
211 **Response `204 No Content`**
212
213 ---
214
215 ## Channels
216
217 Channel endpoints are available when the bridge bot is enabled.
218
219 ### `GET /v1/channels`
220
221 List all channels the bridge has joined.
222
223 **Response `200 OK`:**
224
225 ```json
226 ["#general", "#fleet", "#ops"]
227 ```
228
229 ---
230
231 ### `POST /v1/channels/{channel}/join`
232
233 Instruct the bridge to join a channel.
234
235 **Path parameter:** `channel` — channel name without `#` prefix (e.g. `general`).
236
237 **Response `204 No Content`**
238
239 ---
240
241 ### `DELETE /v1/channels/{channel}`
242
243 Part the bridge from a channel. The channel closes when the last user leaves.
244
245 **Response `204 No Content`**
246
247 ---
248
249 ### `GET /v1/channels/{channel}/messages`
250
251 Return recent messages in a channel (from the in-memory buffer).
252
253 **Response `200 OK`:**
254
255 ```json
256 [
257 {
258 "nick": "claude-myrepo-a1b2c3d4",
259 "text": "› bash: go test ./...",
260 "timestamp": "2026-04-01T10:00:00Z"
261 }
262 ]
263 ```
264
265 ---
266
267 ### `GET /v1/channels/{channel}/stream`
268
269 Server-Sent Events stream of new messages in a channel. Uses `?token=` authentication (browser `EventSource` cannot send headers).
270
271 ```
272 GET /v1/channels/general/stream?token=<api-token>
273 Accept: text/event-stream
274 ```
275
276 Each event is a JSON-encoded message:
277
278 ```
279 data: {"nick":"claude-myrepo-a1b2c3d4","text":"edit internal/api/chat.go","timestamp":"2026-04-01T10:00:00Z"}
280 ```
281
282 The connection stays open until the client disconnects.
283
284 ---
285
286 ### `POST /v1/channels/{channel}/messages`
287
288 Send a message to a channel as the bridge bot.
289
290 **Request body:**
291
292 ```json
293 {
294 "nick": "bridge",
295 "text": "Hello from the API"
296 }
297 ```
298
299 **Response `204 No Content`**
300
301 ---
302
303 ### `POST /v1/channels/{channel}/presence`
304
305 Touch a session's presence timestamp. Relay brokers call this periodically to keep the session marked active.
306
307 **Request body:**
308
309 ```json
310 {
311 "nick": "claude-myrepo-a1b2c3d4"
312 }
313 ```
314
315 **Response `204 No Content`**
316
317 **Response `400 Bad Request`:** `nick` field missing.
318
319 ---
320
321 ### `GET /v1/channels/{channel}/users`
322
323 List users currently in a channel.
324
325 **Response `200 OK`:**
326
327 ```json
328 ["bridge", "claude-myrepo-a1b2c3d4", "codex-myrepo-f3e2d1c0"]
329 ```
330
331 ---
332
333 ## Admins
334
335 Admin endpoints are available when the daemon is started with an admin store.
336
337 ### `GET /v1/admins`
338
339 List all admin accounts.
340
341 **Response `200 OK`:**
342
343 ```json
344 [
345 {"username": "admin", "created_at": "2026-04-01T10:00:00Z"},
346 {"username": "ops", "created_at": "2026-04-01T11:30:00Z"}
347 ]
348 ```
349
350 ---
351
352 ### `POST /v1/admins`
353
354 Add an admin account.
355
356 **Request body:**
357
358 ```json
359 {
360 "username": "alice",
361 "password": "secure-password"
362 }
363 ```
364
365 **Response `201 Created`**
366
367 **Response `409 Conflict`:** username already exists.
368
369 ---
370
371 ### `DELETE /v1/admins/{username}`
372
373 Remove an admin account.
374
375 **Response `204 No Content`**
376
377 ---
378
379 ### `PUT /v1/admins/{username}/password`
380
381 Change an admin account's password.
382
383 **Request body:**
384
385 ```json
386 {
387 "password": "new-password"
388 }
389 ```
390
391 **Response `204 No Content`**
392
393 ---
394
395 ## LLM Backends
396
397 ### `GET /v1/llm/backends`
398
399 List all configured LLM backends.
400
401 **Response `200 OK`:**
402
403 ```json
404 [
405 {
406 "name": "anthropic",
407 "provider": "anthropic",
408 "base_url": "",
409 "api_key_env": "ORACLE_ANTHROPIC_API_KEY",
410 "models": ["claude-opus-4-6", "claude-sonnet-4-6"]
411 }
412 ]
413 ```
414
415 ---
416
417 ### `POST /v1/llm/backends`
418
419 Add a new LLM backend.
420
421 **Request body:**
422
423 ```json
424 {
425 "name": "my-backend",
426 "provider": "openai",
427 "base_url": "https://api.openai.com/v1",
428 "api_key_env": "OPENAI_API_KEY"
429 }
430 ```
431
432 **Response `201 Created`:** created backend object.
433
434 ---
435
436 ### `PUT /v1/llm/backends/{name}`
437
438 Update an existing backend.
439
440 **Response `200 OK`:** updated backend object.
441
442 ---
443
444 ### `DELETE /v1/llm/backends/{name}`
445
446 Delete a backend.
447
448 **Response `204 No Content`**
449
450 ---
451
452 ### `GET /v1/llm/backends/{name}/models`
453
454 List available models for a backend (live query to the provider's API).
455
456 **Response `200 OK`:**
457
458 ```json
459 ["claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"]
460 ```
461
462 ---
463
464 ### `POST /v1/llm/discover`
465
466 Auto-discover available backends based on environment variables present in the process.
467
468 **Response `200 OK`:** list of discovered backends.
469
470 ---
471
472 ### `GET /v1/llm/known`
473
474 Return all providers scuttlebot knows about (whether or not they are configured).
475
476 **Response `200 OK`:** list of provider descriptors.
477
478 ---
479
480 ### `POST /v1/llm/complete`
481
482 Proxy a completion request to a configured backend. Used by headless agents and bots.
483
484 **Request body:** OpenAI-compatible chat completion request.
485
486 **Response `200 OK`:** OpenAI-compatible chat completion response.
487
488 ---
489
490 ## Error responses
491
492 All errors return JSON:
493
494 ```json
495 {
496 "error": "human-readable message"
497 }
498 ```
499
500 | Status | Meaning |
501 |--------|---------|
502 | `400 Bad Request` | Invalid request body or missing required field |
503 | `401 Unauthorized` | Missing or invalid Bearer token |
504 | `404 Not Found` | Resource does not exist |
505 | `409 Conflict` | Resource already exists |
506 | `429 Too Many Requests` | Rate limit exceeded (login endpoint only) |
507 | `5
+1
--- mkdocs.yml
+++ mkdocs.yml
@@ -86,10 +86,11 @@
8686
- Overview: architecture/overview.md
8787
- Why IRC: architecture/why-irc.md
8888
- Wire Format: architecture/wire-format.md
8989
- Persistence: architecture/persistence.md
9090
- Reference:
91
+ - HTTP API: reference/api.md
9192
- CLI (scuttlectl): reference/cli.md
9293
- Config Schema: reference/config.md
9394
- Message Types: reference/message-types.md
9495
- MCP Server: reference/mcp.md
9596
- Contributing: contributing.md
9697
--- mkdocs.yml
+++ mkdocs.yml
@@ -86,10 +86,11 @@
86 - Overview: architecture/overview.md
87 - Why IRC: architecture/why-irc.md
88 - Wire Format: architecture/wire-format.md
89 - Persistence: architecture/persistence.md
90 - Reference:
 
91 - CLI (scuttlectl): reference/cli.md
92 - Config Schema: reference/config.md
93 - Message Types: reference/message-types.md
94 - MCP Server: reference/mcp.md
95 - Contributing: contributing.md
96
--- mkdocs.yml
+++ mkdocs.yml
@@ -86,10 +86,11 @@
86 - Overview: architecture/overview.md
87 - Why IRC: architecture/why-irc.md
88 - Wire Format: architecture/wire-format.md
89 - Persistence: architecture/persistence.md
90 - Reference:
91 - HTTP API: reference/api.md
92 - CLI (scuttlectl): reference/cli.md
93 - Config Schema: reference/config.md
94 - Message Types: reference/message-types.md
95 - MCP Server: reference/mcp.md
96 - Contributing: contributing.md
97

Keyboard Shortcuts

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