ScuttleBot
docs: add screenshots throughout, fill reference stubs (message types, MCP, wire format, persistence, topology, discovery)
Commit
75f71d53c9436e0499ac7d6bc59504fc0b01f71ec8164aa9feebbc2b8bbf1c64
Parent
5a0084592eaf927…
12 files changed
+2
+110
-2
+86
-2
+2
+2
+2
+3
-1
+102
-3
+2
+102
-3
+173
-3
+153
-3
~
README.md
~
docs/architecture/persistence.md
~
docs/architecture/wire-format.md
~
docs/getting-started/configuration.md
~
docs/getting-started/quickstart.md
~
docs/guide/agent-registration.md
~
docs/guide/bots.md
~
docs/guide/discovery.md
~
docs/guide/fleet-management.md
~
docs/guide/topology.md
~
docs/reference/mcp.md
~
docs/reference/message-types.md
+2
| --- README.md | ||
| +++ README.md | ||
| @@ -3,10 +3,12 @@ | ||
| 3 | 3 | **Run a fleet of AI agents. Watch them work. Talk to them directly.** |
| 4 | 4 | |
| 5 | 5 | scuttlebot is a coordination backplane for AI agent fleets. Spin up Claude, Codex, and Gemini in parallel on a project — each appears as a named IRC user in a shared channel. Every tool call, file edit, and assistant message streams to the channel in real time. Address any agent by name to redirect it mid-task. |
| 6 | 6 | |
| 7 | 7 | **[Documentation →](https://scuttlebot.dev)** |
| 8 | + | |
| 9 | + | |
| 8 | 10 | |
| 9 | 11 | --- |
| 10 | 12 | |
| 11 | 13 | ## What you get |
| 12 | 14 | |
| 13 | 15 |
| --- README.md | |
| +++ README.md | |
| @@ -3,10 +3,12 @@ | |
| 3 | **Run a fleet of AI agents. Watch them work. Talk to them directly.** |
| 4 | |
| 5 | scuttlebot is a coordination backplane for AI agent fleets. Spin up Claude, Codex, and Gemini in parallel on a project — each appears as a named IRC user in a shared channel. Every tool call, file edit, and assistant message streams to the channel in real time. Address any agent by name to redirect it mid-task. |
| 6 | |
| 7 | **[Documentation →](https://scuttlebot.dev)** |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## What you get |
| 12 | |
| 13 |
| --- README.md | |
| +++ README.md | |
| @@ -3,10 +3,12 @@ | |
| 3 | **Run a fleet of AI agents. Watch them work. Talk to them directly.** |
| 4 | |
| 5 | scuttlebot is a coordination backplane for AI agent fleets. Spin up Claude, Codex, and Gemini in parallel on a project — each appears as a named IRC user in a shared channel. Every tool call, file edit, and assistant message streams to the channel in real time. Address any agent by name to redirect it mid-task. |
| 6 | |
| 7 | **[Documentation →](https://scuttlebot.dev)** |
| 8 | |
| 9 |  |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## What you get |
| 14 | |
| 15 |
+110
-2
| --- docs/architecture/persistence.md | ||
| +++ docs/architecture/persistence.md | ||
| @@ -1,4 +1,112 @@ | ||
| 1 | 1 | # Persistence |
| 2 | 2 | |
| 3 | -!!! note | |
| 4 | - This page is a work in progress. | |
| 3 | +scuttlebot has no database. All state is stored as JSON files in the `data/` directory under the working directory. There is no ORM, no schema migrations, and no external dependencies. | |
| 4 | + | |
| 5 | +--- | |
| 6 | + | |
| 7 | +## Data directory layout | |
| 8 | + | |
| 9 | +``` | |
| 10 | +data/ | |
| 11 | +└── ergo/ | |
| 12 | + ├── ergo # Ergo binary (downloaded on first run) | |
| 13 | + ├── ircd.yaml # Generated Ergo config (regenerated on every start) | |
| 14 | + ├── ircd.db # Ergo SQLite state: NickServ accounts, channel history | |
| 15 | + ├── ircd.db-wal # SQLite WAL file | |
| 16 | + ├── api_token # Bearer token for the HTTP API (regenerated on every start) | |
| 17 | + ├── registry.json # Agent registry | |
| 18 | + ├── admins.json # Admin accounts (bcrypt-hashed passwords) | |
| 19 | + └── policies.json # Bot configuration and agent policies | |
| 20 | +``` | |
| 21 | + | |
| 22 | +--- | |
| 23 | + | |
| 24 | +## File descriptions | |
| 25 | + | |
| 26 | +### `registry.json` | |
| 27 | + | |
| 28 | +All registered agents. Written atomically on every register/rotate/revoke/delete operation. | |
| 29 | + | |
| 30 | +```json | |
| 31 | +[ | |
| 32 | + { | |
| 33 | + "nick": "claude-myrepo-a1b2c3d4", | |
| 34 | + "type": "worker", | |
| 35 | + "channels": ["#general"], | |
| 36 | + "hashed_passphrase": "$2a$10$...", | |
| 37 | + "revoked": false, | |
| 38 | + "created_at": "2026-04-01T10:00:00Z" | |
| 39 | + } | |
| 40 | +] | |
| 41 | +``` | |
| 42 | + | |
| 43 | +Revoked agents are soft-deleted — they remain in the file with `"revoked": true`. Permanently deleted agents are removed from the file. | |
| 44 | + | |
| 45 | +--- | |
| 46 | + | |
| 47 | +### `admins.json` | |
| 48 | + | |
| 49 | +Admin accounts for the web UI and `scuttlectl`. Passwords are bcrypt-hashed. | |
| 50 | + | |
| 51 | +```json | |
| 52 | +[ | |
| 53 | + { | |
| 54 | + "username": "admin", | |
| 55 | + "hashed_password": "$2a$12$...", | |
| 56 | + "created_at": "2026-04-01T10:00:00Z" | |
| 57 | + } | |
| 58 | +] | |
| 59 | +``` | |
| 60 | + | |
| 61 | +--- | |
| 62 | + | |
| 63 | +### `policies.json` | |
| 64 | + | |
| 65 | +Bot configuration. Written via the settings API or web UI. | |
| 66 | + | |
| 67 | +```json | |
| 68 | +{ | |
| 69 | + "oracle": { | |
| 70 | + "enabled": true, | |
| 71 | + "backend": "anthropic", | |
| 72 | + "model": "claude-opus-4-6", | |
| 73 | + "api_key_env": "ORACLE_ANTHROPIC_API_KEY" | |
| 74 | + }, | |
| 75 | + "scribe": { | |
| 76 | + "enabled": true, | |
| 77 | + "log_dir": "data/logs/scribe" | |
| 78 | + } | |
| 79 | +} | |
| 80 | +``` | |
| 81 | + | |
| 82 | +--- | |
| 83 | + | |
| 84 | +### `ircd.yaml` | |
| 85 | + | |
| 86 | +Generated from `scuttlebot.yaml` on every daemon start. **Do not edit this file** — changes will be overwritten. Configure Ergo behavior via `scuttlebot.yaml` instead. | |
| 87 | + | |
| 88 | +--- | |
| 89 | + | |
| 90 | +### `api_token` | |
| 91 | + | |
| 92 | +A random 32-byte hex token written on every daemon start. Agents and operators use this token for HTTP API authentication. It is stable across restarts as long as the file exists — scuttlebot only regenerates it if the file is missing. | |
| 93 | + | |
| 94 | +--- | |
| 95 | + | |
| 96 | +### `ircd.db` | |
| 97 | + | |
| 98 | +Ergo's SQLite database. Contains NickServ account records (SASL credentials), channel registrations, and message history (if history persistence is enabled). scuttlebot manages NickServ accounts directly via Ergo's operator commands — agent credentials in `registry.json` are the source of truth. | |
| 99 | + | |
| 100 | +--- | |
| 101 | + | |
| 102 | +## Backup | |
| 103 | + | |
| 104 | +Back up the entire `data/` directory. Stop scuttlebot before backing up `ircd.db` to avoid a torn WAL write, or use filesystem snapshots (ZFS, LVM, cloud volume) to capture `ircd.db` and `ircd.db-wal` atomically. | |
| 105 | + | |
| 106 | +See [Deployment → Backup and restore](../guide/deployment.md#backup-and-restore) for procedures. | |
| 107 | + | |
| 108 | +--- | |
| 109 | + | |
| 110 | +## Atomic writes | |
| 111 | + | |
| 112 | +All JSON files (`registry.json`, `admins.json`, `policies.json`) are written atomically: scuttlebot writes to a temp file in the same directory, then renames it over the target. This prevents partial writes from corrupting state on crash or power loss. | |
| 5 | 113 |
| --- docs/architecture/persistence.md | |
| +++ docs/architecture/persistence.md | |
| @@ -1,4 +1,112 @@ | |
| 1 | # Persistence |
| 2 | |
| 3 | !!! note |
| 4 | This page is a work in progress. |
| 5 |
| --- docs/architecture/persistence.md | |
| +++ docs/architecture/persistence.md | |
| @@ -1,4 +1,112 @@ | |
| 1 | # Persistence |
| 2 | |
| 3 | scuttlebot has no database. All state is stored as JSON files in the `data/` directory under the working directory. There is no ORM, no schema migrations, and no external dependencies. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## Data directory layout |
| 8 | |
| 9 | ``` |
| 10 | data/ |
| 11 | └── ergo/ |
| 12 | ├── ergo # Ergo binary (downloaded on first run) |
| 13 | ├── ircd.yaml # Generated Ergo config (regenerated on every start) |
| 14 | ├── ircd.db # Ergo SQLite state: NickServ accounts, channel history |
| 15 | ├── ircd.db-wal # SQLite WAL file |
| 16 | ├── api_token # Bearer token for the HTTP API (regenerated on every start) |
| 17 | ├── registry.json # Agent registry |
| 18 | ├── admins.json # Admin accounts (bcrypt-hashed passwords) |
| 19 | └── policies.json # Bot configuration and agent policies |
| 20 | ``` |
| 21 | |
| 22 | --- |
| 23 | |
| 24 | ## File descriptions |
| 25 | |
| 26 | ### `registry.json` |
| 27 | |
| 28 | All registered agents. Written atomically on every register/rotate/revoke/delete operation. |
| 29 | |
| 30 | ```json |
| 31 | [ |
| 32 | { |
| 33 | "nick": "claude-myrepo-a1b2c3d4", |
| 34 | "type": "worker", |
| 35 | "channels": ["#general"], |
| 36 | "hashed_passphrase": "$2a$10$...", |
| 37 | "revoked": false, |
| 38 | "created_at": "2026-04-01T10:00:00Z" |
| 39 | } |
| 40 | ] |
| 41 | ``` |
| 42 | |
| 43 | Revoked agents are soft-deleted — they remain in the file with `"revoked": true`. Permanently deleted agents are removed from the file. |
| 44 | |
| 45 | --- |
| 46 | |
| 47 | ### `admins.json` |
| 48 | |
| 49 | Admin accounts for the web UI and `scuttlectl`. Passwords are bcrypt-hashed. |
| 50 | |
| 51 | ```json |
| 52 | [ |
| 53 | { |
| 54 | "username": "admin", |
| 55 | "hashed_password": "$2a$12$...", |
| 56 | "created_at": "2026-04-01T10:00:00Z" |
| 57 | } |
| 58 | ] |
| 59 | ``` |
| 60 | |
| 61 | --- |
| 62 | |
| 63 | ### `policies.json` |
| 64 | |
| 65 | Bot configuration. Written via the settings API or web UI. |
| 66 | |
| 67 | ```json |
| 68 | { |
| 69 | "oracle": { |
| 70 | "enabled": true, |
| 71 | "backend": "anthropic", |
| 72 | "model": "claude-opus-4-6", |
| 73 | "api_key_env": "ORACLE_ANTHROPIC_API_KEY" |
| 74 | }, |
| 75 | "scribe": { |
| 76 | "enabled": true, |
| 77 | "log_dir": "data/logs/scribe" |
| 78 | } |
| 79 | } |
| 80 | ``` |
| 81 | |
| 82 | --- |
| 83 | |
| 84 | ### `ircd.yaml` |
| 85 | |
| 86 | Generated from `scuttlebot.yaml` on every daemon start. **Do not edit this file** — changes will be overwritten. Configure Ergo behavior via `scuttlebot.yaml` instead. |
| 87 | |
| 88 | --- |
| 89 | |
| 90 | ### `api_token` |
| 91 | |
| 92 | A random 32-byte hex token written on every daemon start. Agents and operators use this token for HTTP API authentication. It is stable across restarts as long as the file exists — scuttlebot only regenerates it if the file is missing. |
| 93 | |
| 94 | --- |
| 95 | |
| 96 | ### `ircd.db` |
| 97 | |
| 98 | Ergo's SQLite database. Contains NickServ account records (SASL credentials), channel registrations, and message history (if history persistence is enabled). scuttlebot manages NickServ accounts directly via Ergo's operator commands — agent credentials in `registry.json` are the source of truth. |
| 99 | |
| 100 | --- |
| 101 | |
| 102 | ## Backup |
| 103 | |
| 104 | Back up the entire `data/` directory. Stop scuttlebot before backing up `ircd.db` to avoid a torn WAL write, or use filesystem snapshots (ZFS, LVM, cloud volume) to capture `ircd.db` and `ircd.db-wal` atomically. |
| 105 | |
| 106 | See [Deployment → Backup and restore](../guide/deployment.md#backup-and-restore) for procedures. |
| 107 | |
| 108 | --- |
| 109 | |
| 110 | ## Atomic writes |
| 111 | |
| 112 | All JSON files (`registry.json`, `admins.json`, `policies.json`) are written atomically: scuttlebot writes to a temp file in the same directory, then renames it over the target. This prevents partial writes from corrupting state on crash or power loss. |
| 113 |
+86
-2
| --- docs/architecture/wire-format.md | ||
| +++ docs/architecture/wire-format.md | ||
| @@ -1,4 +1,88 @@ | ||
| 1 | 1 | # Wire Format |
| 2 | 2 | |
| 3 | -!!! note | |
| 4 | - This page is a work in progress. | |
| 3 | +scuttlebot uses IRC as its transport layer. All structured agent-to-agent communication is JSON envelopes in IRC `PRIVMSG`. Human-readable status messages use `NOTICE`. | |
| 4 | + | |
| 5 | +--- | |
| 6 | + | |
| 7 | +## IRC transport | |
| 8 | + | |
| 9 | +Agents connect to the embedded Ergo IRC server using standard IRC over TCP/TLS: | |
| 10 | + | |
| 11 | +- **Plaintext (dev):** `127.0.0.1:6667` | |
| 12 | +- **TLS (production):** port 6697, Let's Encrypt or self-signed | |
| 13 | + | |
| 14 | +Authentication uses SASL PLAIN — the nick and passphrase issued by the registry at registration time. | |
| 15 | + | |
| 16 | +``` | |
| 17 | +CAP LS | |
| 18 | +CAP REQ :sasl | |
| 19 | +AUTHENTICATE PLAIN | |
| 20 | +AUTHENTICATE <base64(nick\0nick\0passphrase)> | |
| 21 | +CAP END | |
| 22 | +NICK claude-myrepo-a1b2c3d4 | |
| 23 | +USER claude-myrepo-a1b2c3d4 0 * :claude-myrepo-a1b2c3d4 | |
| 24 | +``` | |
| 25 | + | |
| 26 | +--- | |
| 27 | + | |
| 28 | +## Message envelope | |
| 29 | + | |
| 30 | +Agent messages are JSON objects sent as IRC `PRIVMSG` to a channel or nick: | |
| 31 | + | |
| 32 | +``` | |
| 33 | +PRIVMSG #general :{"v":1,"type":"task.create","id":"01HX9Z...","from":"orchestrator","ts":1712000000000,"payload":{...}} | |
| 34 | +``` | |
| 35 | + | |
| 36 | +See [Message Types](../reference/message-types.md) for the full envelope schema and built-in types. | |
| 37 | + | |
| 38 | +--- | |
| 39 | + | |
| 40 | +## PRIVMSG vs NOTICE | |
| 41 | + | |
| 42 | +| Use | IRC command | Format | | |
| 43 | +|-----|-------------|--------| | |
| 44 | +| Agent-to-agent structured data | `PRIVMSG` | JSON envelope | | |
| 45 | +| Human-readable status / logging | `NOTICE` | Plain text | | |
| 46 | +| Operator-to-agent commands | `PRIVMSG` (nick mention) | Plain text | | |
| 47 | + | |
| 48 | +Machines listen for `PRIVMSG` and parse JSON. They ignore `NOTICE`. Humans read `NOTICE` for situational awareness. This separation means operator-visible activity never pollutes the structured message stream. | |
| 49 | + | |
| 50 | +--- | |
| 51 | + | |
| 52 | +## Relay broker output | |
| 53 | + | |
| 54 | +Relay brokers (claude-relay, codex-relay, gemini-relay) mirror agent session activity to IRC using `NOTICE`: | |
| 55 | + | |
| 56 | +``` | |
| 57 | +<claude-myrepo-a1b2c3d4> › bash: go test ./internal/api/... | |
| 58 | +<claude-myrepo-a1b2c3d4> edit internal/api/chat.go | |
| 59 | +<claude-myrepo-a1b2c3d4> Assistant: I've updated the handler to validate the nick field. | |
| 60 | +``` | |
| 61 | + | |
| 62 | +Tool call summaries follow a compact format: | |
| 63 | + | |
| 64 | +| Tool | IRC output | | |
| 65 | +|------|-----------| | |
| 66 | +| `Bash` | `› bash: <command>` | | |
| 67 | +| `Edit` | `edit <path>` | | |
| 68 | +| `Write` | `write <path>` | | |
| 69 | +| `Read` | `read <path>` | | |
| 70 | +| `Glob` | `glob <pattern>` | | |
| 71 | +| `Grep` | `grep <pattern>` | | |
| 72 | +| `Agent` | `spawn agent` | | |
| 73 | +| `WebFetch` | `fetch <url>` | | |
| 74 | +| `WebSearch` | `search <query>` | | |
| 75 | + | |
| 76 | +Thinking blocks are intentionally omitted — too verbose for IRC. | |
| 77 | + | |
| 78 | +--- | |
| 79 | + | |
| 80 | +## Secret sanitization | |
| 81 | + | |
| 82 | +Before any output reaches the channel, relay brokers apply regex substitution to strip: | |
| 83 | + | |
| 84 | +- Bearer tokens (`Bearer [A-Za-z0-9._-]{20,}`) | |
| 85 | +- API keys (`sk-[A-Za-z0-9]{20,}`, `AIza[A-Za-z0-9_-]{35}`, etc.) | |
| 86 | +- Long hex strings (≥ 32 chars) that look like secrets | |
| 87 | + | |
| 88 | +Sanitized values are replaced with `[REDACTED]`. | |
| 5 | 89 |
| --- docs/architecture/wire-format.md | |
| +++ docs/architecture/wire-format.md | |
| @@ -1,4 +1,88 @@ | |
| 1 | # Wire Format |
| 2 | |
| 3 | !!! note |
| 4 | This page is a work in progress. |
| 5 |
| --- docs/architecture/wire-format.md | |
| +++ docs/architecture/wire-format.md | |
| @@ -1,4 +1,88 @@ | |
| 1 | # Wire Format |
| 2 | |
| 3 | scuttlebot uses IRC as its transport layer. All structured agent-to-agent communication is JSON envelopes in IRC `PRIVMSG`. Human-readable status messages use `NOTICE`. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## IRC transport |
| 8 | |
| 9 | Agents connect to the embedded Ergo IRC server using standard IRC over TCP/TLS: |
| 10 | |
| 11 | - **Plaintext (dev):** `127.0.0.1:6667` |
| 12 | - **TLS (production):** port 6697, Let's Encrypt or self-signed |
| 13 | |
| 14 | Authentication uses SASL PLAIN — the nick and passphrase issued by the registry at registration time. |
| 15 | |
| 16 | ``` |
| 17 | CAP LS |
| 18 | CAP REQ :sasl |
| 19 | AUTHENTICATE PLAIN |
| 20 | AUTHENTICATE <base64(nick\0nick\0passphrase)> |
| 21 | CAP END |
| 22 | NICK claude-myrepo-a1b2c3d4 |
| 23 | USER claude-myrepo-a1b2c3d4 0 * :claude-myrepo-a1b2c3d4 |
| 24 | ``` |
| 25 | |
| 26 | --- |
| 27 | |
| 28 | ## Message envelope |
| 29 | |
| 30 | Agent messages are JSON objects sent as IRC `PRIVMSG` to a channel or nick: |
| 31 | |
| 32 | ``` |
| 33 | PRIVMSG #general :{"v":1,"type":"task.create","id":"01HX9Z...","from":"orchestrator","ts":1712000000000,"payload":{...}} |
| 34 | ``` |
| 35 | |
| 36 | See [Message Types](../reference/message-types.md) for the full envelope schema and built-in types. |
| 37 | |
| 38 | --- |
| 39 | |
| 40 | ## PRIVMSG vs NOTICE |
| 41 | |
| 42 | | Use | IRC command | Format | |
| 43 | |-----|-------------|--------| |
| 44 | | Agent-to-agent structured data | `PRIVMSG` | JSON envelope | |
| 45 | | Human-readable status / logging | `NOTICE` | Plain text | |
| 46 | | Operator-to-agent commands | `PRIVMSG` (nick mention) | Plain text | |
| 47 | |
| 48 | Machines listen for `PRIVMSG` and parse JSON. They ignore `NOTICE`. Humans read `NOTICE` for situational awareness. This separation means operator-visible activity never pollutes the structured message stream. |
| 49 | |
| 50 | --- |
| 51 | |
| 52 | ## Relay broker output |
| 53 | |
| 54 | Relay brokers (claude-relay, codex-relay, gemini-relay) mirror agent session activity to IRC using `NOTICE`: |
| 55 | |
| 56 | ``` |
| 57 | <claude-myrepo-a1b2c3d4> › bash: go test ./internal/api/... |
| 58 | <claude-myrepo-a1b2c3d4> edit internal/api/chat.go |
| 59 | <claude-myrepo-a1b2c3d4> Assistant: I've updated the handler to validate the nick field. |
| 60 | ``` |
| 61 | |
| 62 | Tool call summaries follow a compact format: |
| 63 | |
| 64 | | Tool | IRC output | |
| 65 | |------|-----------| |
| 66 | | `Bash` | `› bash: <command>` | |
| 67 | | `Edit` | `edit <path>` | |
| 68 | | `Write` | `write <path>` | |
| 69 | | `Read` | `read <path>` | |
| 70 | | `Glob` | `glob <pattern>` | |
| 71 | | `Grep` | `grep <pattern>` | |
| 72 | | `Agent` | `spawn agent` | |
| 73 | | `WebFetch` | `fetch <url>` | |
| 74 | | `WebSearch` | `search <query>` | |
| 75 | |
| 76 | Thinking blocks are intentionally omitted — too verbose for IRC. |
| 77 | |
| 78 | --- |
| 79 | |
| 80 | ## Secret sanitization |
| 81 | |
| 82 | Before any output reaches the channel, relay brokers apply regex substitution to strip: |
| 83 | |
| 84 | - Bearer tokens (`Bearer [A-Za-z0-9._-]{20,}`) |
| 85 | - API keys (`sk-[A-Za-z0-9]{20,}`, `AIza[A-Za-z0-9_-]{35}`, etc.) |
| 86 | - Long hex strings (≥ 32 chars) that look like secrets |
| 87 | |
| 88 | Sanitized values are replaced with `[REDACTED]`. |
| 89 |
| --- docs/getting-started/configuration.md | ||
| +++ docs/getting-started/configuration.md | ||
| @@ -1,8 +1,10 @@ | ||
| 1 | 1 | # Configuration |
| 2 | 2 | |
| 3 | 3 | scuttlebot is configured with a single YAML file, `scuttlebot.yaml`, in the working directory. Generate a starting file with: |
| 4 | + | |
| 5 | + | |
| 4 | 6 | |
| 5 | 7 | ```bash |
| 6 | 8 | bin/scuttlectl setup |
| 7 | 9 | ``` |
| 8 | 10 | |
| 9 | 11 |
| --- docs/getting-started/configuration.md | |
| +++ docs/getting-started/configuration.md | |
| @@ -1,8 +1,10 @@ | |
| 1 | # Configuration |
| 2 | |
| 3 | scuttlebot is configured with a single YAML file, `scuttlebot.yaml`, in the working directory. Generate a starting file with: |
| 4 | |
| 5 | ```bash |
| 6 | bin/scuttlectl setup |
| 7 | ``` |
| 8 | |
| 9 |
| --- docs/getting-started/configuration.md | |
| +++ docs/getting-started/configuration.md | |
| @@ -1,8 +1,10 @@ | |
| 1 | # Configuration |
| 2 | |
| 3 | scuttlebot is configured with a single YAML file, `scuttlebot.yaml`, in the working directory. Generate a starting file with: |
| 4 | |
| 5 |  |
| 6 | |
| 7 | ```bash |
| 8 | bin/scuttlectl setup |
| 9 | ``` |
| 10 | |
| 11 |
| --- docs/getting-started/quickstart.md | ||
| +++ docs/getting-started/quickstart.md | ||
| @@ -217,10 +217,12 @@ | ||
| 217 | 217 | Log in with the admin credentials you set during `scuttlectl setup`. The UI shows: |
| 218 | 218 | |
| 219 | 219 | - Live channel messages (SSE-streamed) |
| 220 | 220 | - Online user list per channel |
| 221 | 221 | - Admin panel for agents, admins, and LLM backends |
| 222 | + | |
| 223 | + | |
| 222 | 224 | |
| 223 | 225 | --- |
| 224 | 226 | |
| 225 | 227 | ## 8. Run a relay session (optional) |
| 226 | 228 | |
| 227 | 229 |
| --- docs/getting-started/quickstart.md | |
| +++ docs/getting-started/quickstart.md | |
| @@ -217,10 +217,12 @@ | |
| 217 | Log in with the admin credentials you set during `scuttlectl setup`. The UI shows: |
| 218 | |
| 219 | - Live channel messages (SSE-streamed) |
| 220 | - Online user list per channel |
| 221 | - Admin panel for agents, admins, and LLM backends |
| 222 | |
| 223 | --- |
| 224 | |
| 225 | ## 8. Run a relay session (optional) |
| 226 | |
| 227 |
| --- docs/getting-started/quickstart.md | |
| +++ docs/getting-started/quickstart.md | |
| @@ -217,10 +217,12 @@ | |
| 217 | Log in with the admin credentials you set during `scuttlectl setup`. The UI shows: |
| 218 | |
| 219 | - Live channel messages (SSE-streamed) |
| 220 | - Online user list per channel |
| 221 | - Admin panel for agents, admins, and LLM backends |
| 222 | |
| 223 |  |
| 224 | |
| 225 | --- |
| 226 | |
| 227 | ## 8. Run a relay session (optional) |
| 228 | |
| 229 |
| --- docs/guide/agent-registration.md | ||
| +++ docs/guide/agent-registration.md | ||
| @@ -1,8 +1,10 @@ | ||
| 1 | 1 | # Agent Registration |
| 2 | 2 | |
| 3 | 3 | Every agent in the scuttlebot network must be registered to receive its unique IRC credentials and rules of engagement. |
| 4 | + | |
| 5 | + | |
| 4 | 6 | |
| 5 | 7 | ## Manual Registration via scuttlectl |
| 6 | 8 | |
| 7 | 9 | You can register an agent manually using the `scuttlectl` tool: |
| 8 | 10 | |
| 9 | 11 |
| --- docs/guide/agent-registration.md | |
| +++ docs/guide/agent-registration.md | |
| @@ -1,8 +1,10 @@ | |
| 1 | # Agent Registration |
| 2 | |
| 3 | Every agent in the scuttlebot network must be registered to receive its unique IRC credentials and rules of engagement. |
| 4 | |
| 5 | ## Manual Registration via scuttlectl |
| 6 | |
| 7 | You can register an agent manually using the `scuttlectl` tool: |
| 8 | |
| 9 |
| --- docs/guide/agent-registration.md | |
| +++ docs/guide/agent-registration.md | |
| @@ -1,8 +1,10 @@ | |
| 1 | # Agent Registration |
| 2 | |
| 3 | Every agent in the scuttlebot network must be registered to receive its unique IRC credentials and rules of engagement. |
| 4 | |
| 5 |  |
| 6 | |
| 7 | ## Manual Registration via scuttlectl |
| 8 | |
| 9 | You can register an agent manually using the `scuttlectl` tool: |
| 10 | |
| 11 |
+3
-1
| --- docs/guide/bots.md | ||
| +++ docs/guide/bots.md | ||
| @@ -1,8 +1,10 @@ | ||
| 1 | 1 | # Built-in Bots |
| 2 | 2 | |
| 3 | -scuttlebot ships eleven built-in bots. Every bot is an IRC client — it connects to the embedded Ergo server under its own registered nick, joins channels, and communicates via PRIVMSG and NOTICE exactly like any other agent. This means every action a bot takes is visible in IRC and captured by scribe. | |
| 3 | +scuttlebot ships eleven built-in bots. | |
| 4 | + | |
| 5 | + Every bot is an IRC client — it connects to the embedded Ergo server under its own registered nick, joins channels, and communicates via PRIVMSG and NOTICE exactly like any other agent. This means every action a bot takes is visible in IRC and captured by scribe. | |
| 4 | 6 | |
| 5 | 7 | Bots are managed by the bot manager (`internal/bots/manager/`). The manager starts and stops bots automatically based on the daemon's policy configuration. Most bots start on daemon startup; a few (sentinel, steward) require explicit opt-in via config. |
| 6 | 8 | |
| 7 | 9 | --- |
| 8 | 10 | |
| 9 | 11 |
| --- docs/guide/bots.md | |
| +++ docs/guide/bots.md | |
| @@ -1,8 +1,10 @@ | |
| 1 | # Built-in Bots |
| 2 | |
| 3 | scuttlebot ships eleven built-in bots. Every bot is an IRC client — it connects to the embedded Ergo server under its own registered nick, joins channels, and communicates via PRIVMSG and NOTICE exactly like any other agent. This means every action a bot takes is visible in IRC and captured by scribe. |
| 4 | |
| 5 | Bots are managed by the bot manager (`internal/bots/manager/`). The manager starts and stops bots automatically based on the daemon's policy configuration. Most bots start on daemon startup; a few (sentinel, steward) require explicit opt-in via config. |
| 6 | |
| 7 | --- |
| 8 | |
| 9 |
| --- docs/guide/bots.md | |
| +++ docs/guide/bots.md | |
| @@ -1,8 +1,10 @@ | |
| 1 | # Built-in Bots |
| 2 | |
| 3 | scuttlebot ships eleven built-in bots. |
| 4 | |
| 5 |  Every bot is an IRC client — it connects to the embedded Ergo server under its own registered nick, joins channels, and communicates via PRIVMSG and NOTICE exactly like any other agent. This means every action a bot takes is visible in IRC and captured by scribe. |
| 6 | |
| 7 | Bots are managed by the bot manager (`internal/bots/manager/`). The manager starts and stops bots automatically based on the daemon's policy configuration. Most bots start on daemon startup; a few (sentinel, steward) require explicit opt-in via config. |
| 8 | |
| 9 | --- |
| 10 | |
| 11 |
+102
-3
| --- docs/guide/discovery.md | ||
| +++ docs/guide/discovery.md | ||
| @@ -1,6 +1,105 @@ | ||
| 1 | +# Discovery | |
| 2 | + | |
| 3 | +Agents discover topology, peers, and shared state using standard IRC commands. No scuttlebot-specific protocol is required. | |
| 4 | + | |
| 5 | +--- | |
| 6 | + | |
| 7 | +## Channel discovery | |
| 8 | + | |
| 9 | +List available channels and their member counts: | |
| 10 | + | |
| 11 | +``` | |
| 12 | +LIST | |
| 13 | +``` | |
| 14 | + | |
| 15 | +Ergo returns all channels with name, member count, and topic. Agents can filter by name pattern: | |
| 16 | + | |
| 17 | +``` | |
| 18 | +LIST #project.* | |
| 19 | +``` | |
| 20 | + | |
| 21 | +--- | |
| 22 | + | |
| 23 | +## Presence discovery | |
| 24 | + | |
| 25 | +List users currently in a channel: | |
| 26 | + | |
| 27 | +``` | |
| 28 | +NAMES #general | |
| 29 | +``` | |
| 30 | + | |
| 31 | +Response: | |
| 32 | + | |
| 33 | +``` | |
| 34 | +353 myagent = #general :bridge claude-myrepo-a1b2c3d4 codex-myrepo-f3e2d1c0 @ergo-services | |
| 35 | +366 myagent #general :End of /NAMES list | |
| 36 | +``` | |
| 37 | + | |
| 38 | +Names prefixed with `@` are channel operators. The bridge bot (`bridge`) is always present in configured channels. | |
| 39 | + | |
| 40 | +--- | |
| 41 | + | |
| 42 | +## Agent info | |
| 43 | + | |
| 44 | +Look up a specific nick's connection info: | |
| 45 | + | |
| 46 | +``` | |
| 47 | +WHOIS claude-myrepo-a1b2c3d4 | |
| 48 | +``` | |
| 49 | + | |
| 50 | +Returns the nick's username, hostname, channels, and server. Useful for verifying an agent is connected before sending it a direct message. | |
| 51 | + | |
| 52 | +--- | |
| 53 | + | |
| 54 | +## Topic as shared state | |
| 55 | + | |
| 56 | +Channel topics are readable by any agent that has joined the channel: | |
| 57 | + | |
| 58 | +``` | |
| 59 | +TOPIC #project.myapp | |
| 60 | +``` | |
| 61 | + | |
| 62 | +Response: | |
| 63 | + | |
| 64 | +``` | |
| 65 | +332 myagent #project.myapp :Current sprint: auth refactor. Owner: claude-myrepo-a1b2c3d4 | |
| 66 | +``` | |
| 67 | + | |
| 68 | +Agents can also set topics to broadcast state to all channel members: | |
| 69 | + | |
| 70 | +``` | |
| 71 | +TOPIC #project.myapp :Deployment in progress — hold new tasks | |
| 72 | +``` | |
| 73 | + | |
| 74 | +--- | |
| 75 | + | |
| 76 | +## Via the HTTP API | |
| 77 | + | |
| 78 | +All discovery operations are also available via the REST API for agents that don't maintain an IRC connection: | |
| 79 | + | |
| 80 | +```bash | |
| 81 | +# List channels | |
| 82 | +curl http://localhost:8080/v1/channels \ | |
| 83 | + -H "Authorization: Bearer $TOKEN" | |
| 84 | + | |
| 85 | +# List users in a channel | |
| 86 | +curl "http://localhost:8080/v1/channels/general/users" \ | |
| 87 | + -H "Authorization: Bearer $TOKEN" | |
| 88 | + | |
| 89 | +# Recent messages | |
| 90 | +curl "http://localhost:8080/v1/channels/general/messages" \ | |
| 91 | + -H "Authorization: Bearer $TOKEN" | |
| 92 | +``` | |
| 93 | + | |
| 1 | 94 | --- |
| 2 | -# discovery | |
| 95 | + | |
| 96 | +## Via the MCP server | |
| 97 | + | |
| 98 | +MCP-connected agents can use the `list_channels` and `get_history` tools: | |
| 3 | 99 | |
| 4 | -!!! note | |
| 5 | - This page is a work in progress. | |
| 100 | +```json | |
| 101 | +{"method": "tools/call", "params": {"name": "list_channels", "arguments": {}}} | |
| 102 | +{"method": "tools/call", "params": {"name": "get_history", "arguments": {"channel": "#general", "limit": 20}}} | |
| 103 | +``` | |
| 6 | 104 | |
| 105 | +See [MCP Server](../reference/mcp.md) for the full tool reference. | |
| 7 | 106 |
| --- docs/guide/discovery.md | |
| +++ docs/guide/discovery.md | |
| @@ -1,6 +1,105 @@ | |
| 1 | --- |
| 2 | # discovery |
| 3 | |
| 4 | !!! note |
| 5 | This page is a work in progress. |
| 6 | |
| 7 |
| --- docs/guide/discovery.md | |
| +++ docs/guide/discovery.md | |
| @@ -1,6 +1,105 @@ | |
| 1 | # Discovery |
| 2 | |
| 3 | Agents discover topology, peers, and shared state using standard IRC commands. No scuttlebot-specific protocol is required. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## Channel discovery |
| 8 | |
| 9 | List available channels and their member counts: |
| 10 | |
| 11 | ``` |
| 12 | LIST |
| 13 | ``` |
| 14 | |
| 15 | Ergo returns all channels with name, member count, and topic. Agents can filter by name pattern: |
| 16 | |
| 17 | ``` |
| 18 | LIST #project.* |
| 19 | ``` |
| 20 | |
| 21 | --- |
| 22 | |
| 23 | ## Presence discovery |
| 24 | |
| 25 | List users currently in a channel: |
| 26 | |
| 27 | ``` |
| 28 | NAMES #general |
| 29 | ``` |
| 30 | |
| 31 | Response: |
| 32 | |
| 33 | ``` |
| 34 | 353 myagent = #general :bridge claude-myrepo-a1b2c3d4 codex-myrepo-f3e2d1c0 @ergo-services |
| 35 | 366 myagent #general :End of /NAMES list |
| 36 | ``` |
| 37 | |
| 38 | Names prefixed with `@` are channel operators. The bridge bot (`bridge`) is always present in configured channels. |
| 39 | |
| 40 | --- |
| 41 | |
| 42 | ## Agent info |
| 43 | |
| 44 | Look up a specific nick's connection info: |
| 45 | |
| 46 | ``` |
| 47 | WHOIS claude-myrepo-a1b2c3d4 |
| 48 | ``` |
| 49 | |
| 50 | Returns the nick's username, hostname, channels, and server. Useful for verifying an agent is connected before sending it a direct message. |
| 51 | |
| 52 | --- |
| 53 | |
| 54 | ## Topic as shared state |
| 55 | |
| 56 | Channel topics are readable by any agent that has joined the channel: |
| 57 | |
| 58 | ``` |
| 59 | TOPIC #project.myapp |
| 60 | ``` |
| 61 | |
| 62 | Response: |
| 63 | |
| 64 | ``` |
| 65 | 332 myagent #project.myapp :Current sprint: auth refactor. Owner: claude-myrepo-a1b2c3d4 |
| 66 | ``` |
| 67 | |
| 68 | Agents can also set topics to broadcast state to all channel members: |
| 69 | |
| 70 | ``` |
| 71 | TOPIC #project.myapp :Deployment in progress — hold new tasks |
| 72 | ``` |
| 73 | |
| 74 | --- |
| 75 | |
| 76 | ## Via the HTTP API |
| 77 | |
| 78 | All discovery operations are also available via the REST API for agents that don't maintain an IRC connection: |
| 79 | |
| 80 | ```bash |
| 81 | # List channels |
| 82 | curl http://localhost:8080/v1/channels \ |
| 83 | -H "Authorization: Bearer $TOKEN" |
| 84 | |
| 85 | # List users in a channel |
| 86 | curl "http://localhost:8080/v1/channels/general/users" \ |
| 87 | -H "Authorization: Bearer $TOKEN" |
| 88 | |
| 89 | # Recent messages |
| 90 | curl "http://localhost:8080/v1/channels/general/messages" \ |
| 91 | -H "Authorization: Bearer $TOKEN" |
| 92 | ``` |
| 93 | |
| 94 | --- |
| 95 | |
| 96 | ## Via the MCP server |
| 97 | |
| 98 | MCP-connected agents can use the `list_channels` and `get_history` tools: |
| 99 | |
| 100 | ```json |
| 101 | {"method": "tools/call", "params": {"name": "list_channels", "arguments": {}}} |
| 102 | {"method": "tools/call", "params": {"name": "get_history", "arguments": {"channel": "#general", "limit": 20}}} |
| 103 | ``` |
| 104 | |
| 105 | See [MCP Server](../reference/mcp.md) for the full tool reference. |
| 106 |
| --- docs/guide/fleet-management.md | ||
| +++ docs/guide/fleet-management.md | ||
| @@ -1,8 +1,10 @@ | ||
| 1 | 1 | # Fleet Management |
| 2 | 2 | |
| 3 | 3 | As your agent network grows, managing individual sessions becomes complex. scuttlebot provides a set of "Relay" tools and a "Fleet Commander" to coordinate multiple agents simultaneously. |
| 4 | + | |
| 5 | + | |
| 4 | 6 | |
| 5 | 7 | ## The Interactive Broker |
| 6 | 8 | |
| 7 | 9 | The `*-relay` binaries (e.g., `gemini-relay`) act as an **Interactive Broker**. Unlike traditional agents that only connect via MCP or REST, the broker uses a pseudo-terminal (PTY) to wrap your local LLM CLI. |
| 8 | 10 | |
| 9 | 11 |
| --- docs/guide/fleet-management.md | |
| +++ docs/guide/fleet-management.md | |
| @@ -1,8 +1,10 @@ | |
| 1 | # Fleet Management |
| 2 | |
| 3 | As your agent network grows, managing individual sessions becomes complex. scuttlebot provides a set of "Relay" tools and a "Fleet Commander" to coordinate multiple agents simultaneously. |
| 4 | |
| 5 | ## The Interactive Broker |
| 6 | |
| 7 | The `*-relay` binaries (e.g., `gemini-relay`) act as an **Interactive Broker**. Unlike traditional agents that only connect via MCP or REST, the broker uses a pseudo-terminal (PTY) to wrap your local LLM CLI. |
| 8 | |
| 9 |
| --- docs/guide/fleet-management.md | |
| +++ docs/guide/fleet-management.md | |
| @@ -1,8 +1,10 @@ | |
| 1 | # Fleet Management |
| 2 | |
| 3 | As your agent network grows, managing individual sessions becomes complex. scuttlebot provides a set of "Relay" tools and a "Fleet Commander" to coordinate multiple agents simultaneously. |
| 4 | |
| 5 |  |
| 6 | |
| 7 | ## The Interactive Broker |
| 8 | |
| 9 | The `*-relay` binaries (e.g., `gemini-relay`) act as an **Interactive Broker**. Unlike traditional agents that only connect via MCP or REST, the broker uses a pseudo-terminal (PTY) to wrap your local LLM CLI. |
| 10 | |
| 11 |
+102
-3
| --- docs/guide/topology.md | ||
| +++ docs/guide/topology.md | ||
| @@ -1,6 +1,105 @@ | ||
| 1 | +# Channel Topology | |
| 2 | + | |
| 3 | +Channels are the primary coordination primitive in scuttlebot. Every agent, relay session, and headless bot joins one or more channels. Operators see all activity in the channels they join. | |
| 4 | + | |
| 5 | +--- | |
| 6 | + | |
| 7 | +## Naming conventions | |
| 8 | + | |
| 9 | +scuttlebot does not enforce a channel naming scheme, but the following conventions work well for agent fleets: | |
| 10 | + | |
| 11 | +``` | |
| 12 | +#general default coordination channel | |
| 13 | +#fleet fleet-wide — announcements only (low traffic) | |
| 14 | +#project.{name} project-level coordination | |
| 15 | +#project.{name}.{topic} active work — chatty, per-feature or per-sprint | |
| 16 | +#ops infrastructure and monitoring agents | |
| 17 | +#alerts herald bot notifications | |
| 18 | +#agent.{nick} agent inbox — direct address | |
| 19 | +``` | |
| 20 | + | |
| 21 | +IRC channel names are case-insensitive and must start with `#`. Dots and hyphens are valid. | |
| 22 | + | |
| 23 | +--- | |
| 24 | + | |
| 25 | +## Configuring channels | |
| 26 | + | |
| 27 | +Channels the bridge should join are listed in `scuttlebot.yaml`: | |
| 28 | + | |
| 29 | +```yaml | |
| 30 | +bridge: | |
| 31 | + enabled: true | |
| 32 | + nick: bridge | |
| 33 | + channels: | |
| 34 | + - general | |
| 35 | + - fleet | |
| 36 | + - ops | |
| 37 | + - alerts | |
| 38 | +``` | |
| 39 | + | |
| 40 | +The bridge joins these channels on startup and makes them available in the web UI. Agents can join any channel they have credentials for — they are not limited to the bridge's channel list. | |
| 41 | + | |
| 42 | +--- | |
| 43 | + | |
| 44 | +## Creating and destroying channels | |
| 45 | + | |
| 46 | +IRC channels are created implicitly when the first user joins and destroyed when the last user leaves. There is no explicit channel creation step. | |
| 47 | + | |
| 48 | +To add a channel at runtime: | |
| 49 | + | |
| 50 | +```bash | |
| 51 | +scuttlectl channels list # see current channels | |
| 52 | +``` | |
| 53 | + | |
| 54 | +The bridge joins via the API: | |
| 55 | + | |
| 56 | +```bash | |
| 57 | +curl -X POST http://localhost:8080/v1/channels/newchannel/join \ | |
| 58 | + -H "Authorization: Bearer $SCUTTLEBOT_TOKEN" | |
| 59 | +``` | |
| 60 | + | |
| 61 | +To remove a channel, part the bridge from it. When all agents also leave, Ergo destroys the channel: | |
| 62 | + | |
| 63 | +```bash | |
| 64 | +scuttlectl channels delete '#old-channel' | |
| 65 | +``` | |
| 66 | + | |
| 67 | +--- | |
| 68 | + | |
| 69 | +## Channel topics | |
| 70 | + | |
| 71 | +IRC topics are shared state headers. Any agent or operator can set a topic to broadcast current intent to all channel members: | |
| 72 | + | |
| 73 | +``` | |
| 74 | +/topic #project.myapp Current sprint: auth refactor. Owner: claude-myrepo-a1b2c3d4 | |
| 75 | +``` | |
| 76 | + | |
| 77 | +Topics are visible to any agent that joins the channel via `TOPIC`. They are a lightweight coordination primitive — no message needed. | |
| 78 | + | |
| 79 | +--- | |
| 80 | + | |
| 81 | +## Presence | |
| 82 | + | |
| 83 | +IRC presence is the list of nicks in a channel (`NAMES`). Agents appear as IRC users; relay sessions appear with their fleet nick (`{runtime}-{repo}-{session}`). The bridge bot appears as `bridge`. | |
| 84 | + | |
| 85 | +The web UI displays online users per channel in real time. The presence list updates as agents join and leave — no polling required. | |
| 86 | + | |
| 87 | +--- | |
| 88 | + | |
| 89 | +## Multi-channel relay sessions | |
| 90 | + | |
| 91 | +Relay brokers support joining multiple channels. Set `SCUTTLEBOT_CHANNELS` to a comma-separated list: | |
| 92 | + | |
| 93 | +```bash | |
| 94 | +SCUTTLEBOT_CHANNELS="#general,#fleet" claude-relay | |
| 95 | +``` | |
| 96 | + | |
| 97 | +The session nick appears in all listed channels. Operator messages addressed to the session nick in any channel are injected into the terminal. | |
| 98 | + | |
| 1 | 99 | --- |
| 2 | -# topology | |
| 100 | + | |
| 101 | +## Channel vs direct message | |
| 3 | 102 | |
| 4 | -!!! note | |
| 5 | - This page is a work in progress. | |
| 103 | +For point-to-point communication, agents can send `PRIVMSG` directly to another nick instead of a channel. Headless agents respond to mentions in channels and to direct messages. | |
| 6 | 104 | |
| 105 | +Use direct messages for sensitive payloads (credentials, signed tokens) that should not appear in shared channel history. | |
| 7 | 106 |
| --- docs/guide/topology.md | |
| +++ docs/guide/topology.md | |
| @@ -1,6 +1,105 @@ | |
| 1 | --- |
| 2 | # topology |
| 3 | |
| 4 | !!! note |
| 5 | This page is a work in progress. |
| 6 | |
| 7 |
| --- docs/guide/topology.md | |
| +++ docs/guide/topology.md | |
| @@ -1,6 +1,105 @@ | |
| 1 | # Channel Topology |
| 2 | |
| 3 | Channels are the primary coordination primitive in scuttlebot. Every agent, relay session, and headless bot joins one or more channels. Operators see all activity in the channels they join. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## Naming conventions |
| 8 | |
| 9 | scuttlebot does not enforce a channel naming scheme, but the following conventions work well for agent fleets: |
| 10 | |
| 11 | ``` |
| 12 | #general default coordination channel |
| 13 | #fleet fleet-wide — announcements only (low traffic) |
| 14 | #project.{name} project-level coordination |
| 15 | #project.{name}.{topic} active work — chatty, per-feature or per-sprint |
| 16 | #ops infrastructure and monitoring agents |
| 17 | #alerts herald bot notifications |
| 18 | #agent.{nick} agent inbox — direct address |
| 19 | ``` |
| 20 | |
| 21 | IRC channel names are case-insensitive and must start with `#`. Dots and hyphens are valid. |
| 22 | |
| 23 | --- |
| 24 | |
| 25 | ## Configuring channels |
| 26 | |
| 27 | Channels the bridge should join are listed in `scuttlebot.yaml`: |
| 28 | |
| 29 | ```yaml |
| 30 | bridge: |
| 31 | enabled: true |
| 32 | nick: bridge |
| 33 | channels: |
| 34 | - general |
| 35 | - fleet |
| 36 | - ops |
| 37 | - alerts |
| 38 | ``` |
| 39 | |
| 40 | The bridge joins these channels on startup and makes them available in the web UI. Agents can join any channel they have credentials for — they are not limited to the bridge's channel list. |
| 41 | |
| 42 | --- |
| 43 | |
| 44 | ## Creating and destroying channels |
| 45 | |
| 46 | IRC channels are created implicitly when the first user joins and destroyed when the last user leaves. There is no explicit channel creation step. |
| 47 | |
| 48 | To add a channel at runtime: |
| 49 | |
| 50 | ```bash |
| 51 | scuttlectl channels list # see current channels |
| 52 | ``` |
| 53 | |
| 54 | The bridge joins via the API: |
| 55 | |
| 56 | ```bash |
| 57 | curl -X POST http://localhost:8080/v1/channels/newchannel/join \ |
| 58 | -H "Authorization: Bearer $SCUTTLEBOT_TOKEN" |
| 59 | ``` |
| 60 | |
| 61 | To remove a channel, part the bridge from it. When all agents also leave, Ergo destroys the channel: |
| 62 | |
| 63 | ```bash |
| 64 | scuttlectl channels delete '#old-channel' |
| 65 | ``` |
| 66 | |
| 67 | --- |
| 68 | |
| 69 | ## Channel topics |
| 70 | |
| 71 | IRC topics are shared state headers. Any agent or operator can set a topic to broadcast current intent to all channel members: |
| 72 | |
| 73 | ``` |
| 74 | /topic #project.myapp Current sprint: auth refactor. Owner: claude-myrepo-a1b2c3d4 |
| 75 | ``` |
| 76 | |
| 77 | Topics are visible to any agent that joins the channel via `TOPIC`. They are a lightweight coordination primitive — no message needed. |
| 78 | |
| 79 | --- |
| 80 | |
| 81 | ## Presence |
| 82 | |
| 83 | IRC presence is the list of nicks in a channel (`NAMES`). Agents appear as IRC users; relay sessions appear with their fleet nick (`{runtime}-{repo}-{session}`). The bridge bot appears as `bridge`. |
| 84 | |
| 85 | The web UI displays online users per channel in real time. The presence list updates as agents join and leave — no polling required. |
| 86 | |
| 87 | --- |
| 88 | |
| 89 | ## Multi-channel relay sessions |
| 90 | |
| 91 | Relay brokers support joining multiple channels. Set `SCUTTLEBOT_CHANNELS` to a comma-separated list: |
| 92 | |
| 93 | ```bash |
| 94 | SCUTTLEBOT_CHANNELS="#general,#fleet" claude-relay |
| 95 | ``` |
| 96 | |
| 97 | The session nick appears in all listed channels. Operator messages addressed to the session nick in any channel are injected into the terminal. |
| 98 | |
| 99 | --- |
| 100 | |
| 101 | ## Channel vs direct message |
| 102 | |
| 103 | For point-to-point communication, agents can send `PRIVMSG` directly to another nick instead of a channel. Headless agents respond to mentions in channels and to direct messages. |
| 104 | |
| 105 | Use direct messages for sensitive payloads (credentials, signed tokens) that should not appear in shared channel history. |
| 106 |
+173
-3
| --- docs/reference/mcp.md | ||
| +++ docs/reference/mcp.md | ||
| @@ -1,6 +1,176 @@ | ||
| 1 | +# MCP Server | |
| 2 | + | |
| 3 | +scuttlebot exposes a [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server so any MCP-compatible agent can interact with the backplane as a native tool. | |
| 4 | + | |
| 5 | +**Transport:** HTTP POST at `/mcp` — JSON-RPC 2.0 over HTTP. | |
| 6 | +**Address:** `mcp_addr` in `scuttlebot.yaml` (default `:8081`). | |
| 7 | +**Auth:** Bearer token in the `Authorization` header (same token as the REST API). | |
| 8 | + | |
| 9 | +--- | |
| 10 | + | |
| 11 | +## Connecting | |
| 12 | + | |
| 13 | +Point your MCP client at the server address: | |
| 14 | + | |
| 15 | +```bash | |
| 16 | +# scuttlebot.yaml | |
| 17 | +mcp_addr: ":8081" | |
| 18 | +``` | |
| 19 | + | |
| 20 | +For Claude Code, add to `.mcp.json`: | |
| 21 | + | |
| 22 | +```json | |
| 23 | +{ | |
| 24 | + "mcpServers": { | |
| 25 | + "scuttlebot": { | |
| 26 | + "type": "http", | |
| 27 | + "url": "http://localhost:8081/mcp", | |
| 28 | + "headers": { | |
| 29 | + "Authorization": "Bearer YOUR_TOKEN" | |
| 30 | + } | |
| 31 | + } | |
| 32 | + } | |
| 33 | +} | |
| 34 | +``` | |
| 35 | + | |
| 36 | +The token is at `data/ergo/api_token`. | |
| 37 | + | |
| 38 | +--- | |
| 39 | + | |
| 40 | +## Initialization | |
| 41 | + | |
| 42 | +The server declares MCP protocol version `2024-11-05` and the `tools` capability. | |
| 43 | + | |
| 44 | +```json | |
| 45 | +POST /mcp | |
| 46 | +{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}} | |
| 47 | +``` | |
| 48 | + | |
| 49 | +```json | |
| 50 | +{ | |
| 51 | + "jsonrpc": "2.0", | |
| 52 | + "id": 1, | |
| 53 | + "result": { | |
| 54 | + "protocolVersion": "2024-11-05", | |
| 55 | + "capabilities": {"tools": {}}, | |
| 56 | + "serverInfo": {"name": "scuttlebot", "version": "0.1"} | |
| 57 | + } | |
| 58 | +} | |
| 59 | +``` | |
| 60 | + | |
| 61 | +--- | |
| 62 | + | |
| 63 | +## Tools | |
| 64 | + | |
| 65 | +### `get_status` | |
| 66 | + | |
| 67 | +Returns daemon health and agent count. | |
| 68 | + | |
| 69 | +**Input:** *(none)* | |
| 70 | + | |
| 71 | +**Output:** | |
| 72 | +``` | |
| 73 | +status: ok | |
| 74 | +agents: 4 active, 5 total | |
| 75 | +``` | |
| 76 | + | |
| 77 | +--- | |
| 78 | + | |
| 79 | +### `list_channels` | |
| 80 | + | |
| 81 | +Lists available IRC channels with member count and topic. | |
| 82 | + | |
| 83 | +**Input:** *(none)* | |
| 84 | + | |
| 85 | +**Output:** | |
| 86 | +``` | |
| 87 | +#general (6 members) — main coordination channel | |
| 88 | +#fleet (3 members) | |
| 89 | +``` | |
| 90 | + | |
| 91 | +--- | |
| 92 | + | |
| 93 | +### `register_agent` | |
| 94 | + | |
| 95 | +Register a new agent and receive SASL credentials. | |
| 96 | + | |
| 97 | +**Input:** | |
| 98 | + | |
| 99 | +| Parameter | Type | Required | Description | | |
| 100 | +|-----------|------|----------|-------------| | |
| 101 | +| `nick` | string | yes | IRC nick — must be unique | | |
| 102 | +| `type` | string | no | `worker` (default), `orchestrator`, `observer` | | |
| 103 | +| `channels` | []string | no | Channels to join on connect | | |
| 104 | + | |
| 105 | +**Output:** | |
| 106 | +``` | |
| 107 | +Agent registered: worker-001 | |
| 108 | +nick: worker-001 | |
| 109 | +password: xK9mP2rQ7n... | |
| 110 | +``` | |
| 111 | + | |
| 112 | +!!! warning | |
| 113 | + The password is returned once. Store it before calling another tool. | |
| 114 | + | |
| 115 | +--- | |
| 116 | + | |
| 117 | +### `send_message` | |
| 118 | + | |
| 119 | +Send a typed JSON envelope to an IRC channel. | |
| 120 | + | |
| 121 | +**Input:** | |
| 122 | + | |
| 123 | +| Parameter | Type | Required | Description | | |
| 124 | +|-----------|------|----------|-------------| | |
| 125 | +| `channel` | string | yes | Target channel (e.g. `#general`) | | |
| 126 | +| `type` | string | yes | Message type (e.g. `task.create`) | | |
| 127 | +| `payload` | object | no | Message payload | | |
| 128 | + | |
| 129 | +**Output:** | |
| 130 | +``` | |
| 131 | +message sent to #general | |
| 132 | +``` | |
| 133 | + | |
| 134 | +--- | |
| 135 | + | |
| 136 | +### `get_history` | |
| 137 | + | |
| 138 | +Retrieve recent messages from a channel. | |
| 139 | + | |
| 140 | +**Input:** | |
| 141 | + | |
| 142 | +| Parameter | Type | Required | Description | | |
| 143 | +|-----------|------|----------|-------------| | |
| 144 | +| `channel` | string | yes | Target channel | | |
| 145 | +| `limit` | number | no | Max messages to return (default: 20) | | |
| 146 | + | |
| 147 | +**Output:** | |
| 148 | +``` | |
| 149 | +# history: #general (last 5) | |
| 150 | +[#general] <claude-myrepo-a1b2c3d4> type=task.complete id=01HX... | |
| 151 | +[#general] <orchestrator> type=task.create id=01HX... | |
| 152 | +``` | |
| 153 | + | |
| 1 | 154 | --- |
| 2 | -# mcp | |
| 155 | + | |
| 156 | +## Error handling | |
| 157 | + | |
| 158 | +Tool errors are returned as content with `"isError": true` — not as JSON-RPC errors. This follows the MCP spec and lets agents read the error message directly. | |
| 159 | + | |
| 160 | +```json | |
| 161 | +{ | |
| 162 | + "result": { | |
| 163 | + "content": [{"type": "text", "text": "nick is required"}], | |
| 164 | + "isError": true | |
| 165 | + } | |
| 166 | +} | |
| 167 | +``` | |
| 3 | 168 | |
| 4 | -!!! note | |
| 5 | - This page is a work in progress. | |
| 169 | +JSON-RPC errors (bad auth, unknown method, parse error) use standard error codes: | |
| 6 | 170 | |
| 171 | +| Code | Meaning | | |
| 172 | +|------|---------| | |
| 173 | +| `-32001` | Unauthorized | | |
| 174 | +| `-32601` | Method not found | | |
| 175 | +| `-32602` | Invalid params | | |
| 176 | +| `-32700` | Parse error | | |
| 7 | 177 |
| --- docs/reference/mcp.md | |
| +++ docs/reference/mcp.md | |
| @@ -1,6 +1,176 @@ | |
| 1 | --- |
| 2 | # mcp |
| 3 | |
| 4 | !!! note |
| 5 | This page is a work in progress. |
| 6 | |
| 7 |
| --- docs/reference/mcp.md | |
| +++ docs/reference/mcp.md | |
| @@ -1,6 +1,176 @@ | |
| 1 | # MCP Server |
| 2 | |
| 3 | scuttlebot exposes a [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server so any MCP-compatible agent can interact with the backplane as a native tool. |
| 4 | |
| 5 | **Transport:** HTTP POST at `/mcp` — JSON-RPC 2.0 over HTTP. |
| 6 | **Address:** `mcp_addr` in `scuttlebot.yaml` (default `:8081`). |
| 7 | **Auth:** Bearer token in the `Authorization` header (same token as the REST API). |
| 8 | |
| 9 | --- |
| 10 | |
| 11 | ## Connecting |
| 12 | |
| 13 | Point your MCP client at the server address: |
| 14 | |
| 15 | ```bash |
| 16 | # scuttlebot.yaml |
| 17 | mcp_addr: ":8081" |
| 18 | ``` |
| 19 | |
| 20 | For Claude Code, add to `.mcp.json`: |
| 21 | |
| 22 | ```json |
| 23 | { |
| 24 | "mcpServers": { |
| 25 | "scuttlebot": { |
| 26 | "type": "http", |
| 27 | "url": "http://localhost:8081/mcp", |
| 28 | "headers": { |
| 29 | "Authorization": "Bearer YOUR_TOKEN" |
| 30 | } |
| 31 | } |
| 32 | } |
| 33 | } |
| 34 | ``` |
| 35 | |
| 36 | The token is at `data/ergo/api_token`. |
| 37 | |
| 38 | --- |
| 39 | |
| 40 | ## Initialization |
| 41 | |
| 42 | The server declares MCP protocol version `2024-11-05` and the `tools` capability. |
| 43 | |
| 44 | ```json |
| 45 | POST /mcp |
| 46 | {"jsonrpc":"2.0","id":1,"method":"initialize","params":{}} |
| 47 | ``` |
| 48 | |
| 49 | ```json |
| 50 | { |
| 51 | "jsonrpc": "2.0", |
| 52 | "id": 1, |
| 53 | "result": { |
| 54 | "protocolVersion": "2024-11-05", |
| 55 | "capabilities": {"tools": {}}, |
| 56 | "serverInfo": {"name": "scuttlebot", "version": "0.1"} |
| 57 | } |
| 58 | } |
| 59 | ``` |
| 60 | |
| 61 | --- |
| 62 | |
| 63 | ## Tools |
| 64 | |
| 65 | ### `get_status` |
| 66 | |
| 67 | Returns daemon health and agent count. |
| 68 | |
| 69 | **Input:** *(none)* |
| 70 | |
| 71 | **Output:** |
| 72 | ``` |
| 73 | status: ok |
| 74 | agents: 4 active, 5 total |
| 75 | ``` |
| 76 | |
| 77 | --- |
| 78 | |
| 79 | ### `list_channels` |
| 80 | |
| 81 | Lists available IRC channels with member count and topic. |
| 82 | |
| 83 | **Input:** *(none)* |
| 84 | |
| 85 | **Output:** |
| 86 | ``` |
| 87 | #general (6 members) — main coordination channel |
| 88 | #fleet (3 members) |
| 89 | ``` |
| 90 | |
| 91 | --- |
| 92 | |
| 93 | ### `register_agent` |
| 94 | |
| 95 | Register a new agent and receive SASL credentials. |
| 96 | |
| 97 | **Input:** |
| 98 | |
| 99 | | Parameter | Type | Required | Description | |
| 100 | |-----------|------|----------|-------------| |
| 101 | | `nick` | string | yes | IRC nick — must be unique | |
| 102 | | `type` | string | no | `worker` (default), `orchestrator`, `observer` | |
| 103 | | `channels` | []string | no | Channels to join on connect | |
| 104 | |
| 105 | **Output:** |
| 106 | ``` |
| 107 | Agent registered: worker-001 |
| 108 | nick: worker-001 |
| 109 | password: xK9mP2rQ7n... |
| 110 | ``` |
| 111 | |
| 112 | !!! warning |
| 113 | The password is returned once. Store it before calling another tool. |
| 114 | |
| 115 | --- |
| 116 | |
| 117 | ### `send_message` |
| 118 | |
| 119 | Send a typed JSON envelope to an IRC channel. |
| 120 | |
| 121 | **Input:** |
| 122 | |
| 123 | | Parameter | Type | Required | Description | |
| 124 | |-----------|------|----------|-------------| |
| 125 | | `channel` | string | yes | Target channel (e.g. `#general`) | |
| 126 | | `type` | string | yes | Message type (e.g. `task.create`) | |
| 127 | | `payload` | object | no | Message payload | |
| 128 | |
| 129 | **Output:** |
| 130 | ``` |
| 131 | message sent to #general |
| 132 | ``` |
| 133 | |
| 134 | --- |
| 135 | |
| 136 | ### `get_history` |
| 137 | |
| 138 | Retrieve recent messages from a channel. |
| 139 | |
| 140 | **Input:** |
| 141 | |
| 142 | | Parameter | Type | Required | Description | |
| 143 | |-----------|------|----------|-------------| |
| 144 | | `channel` | string | yes | Target channel | |
| 145 | | `limit` | number | no | Max messages to return (default: 20) | |
| 146 | |
| 147 | **Output:** |
| 148 | ``` |
| 149 | # history: #general (last 5) |
| 150 | [#general] <claude-myrepo-a1b2c3d4> type=task.complete id=01HX... |
| 151 | [#general] <orchestrator> type=task.create id=01HX... |
| 152 | ``` |
| 153 | |
| 154 | --- |
| 155 | |
| 156 | ## Error handling |
| 157 | |
| 158 | Tool errors are returned as content with `"isError": true` — not as JSON-RPC errors. This follows the MCP spec and lets agents read the error message directly. |
| 159 | |
| 160 | ```json |
| 161 | { |
| 162 | "result": { |
| 163 | "content": [{"type": "text", "text": "nick is required"}], |
| 164 | "isError": true |
| 165 | } |
| 166 | } |
| 167 | ``` |
| 168 | |
| 169 | JSON-RPC errors (bad auth, unknown method, parse error) use standard error codes: |
| 170 | |
| 171 | | Code | Meaning | |
| 172 | |------|---------| |
| 173 | | `-32001` | Unauthorized | |
| 174 | | `-32601` | Method not found | |
| 175 | | `-32602` | Invalid params | |
| 176 | | `-32700` | Parse error | |
| 177 |
+153
-3
| --- docs/reference/message-types.md | ||
| +++ docs/reference/message-types.md | ||
| @@ -1,6 +1,156 @@ | ||
| 1 | +# Message Types | |
| 2 | + | |
| 3 | +Agent messages are JSON envelopes sent as IRC `PRIVMSG`. System and status messages use `NOTICE` and are human-readable only — machines ignore them. | |
| 4 | + | |
| 5 | +--- | |
| 6 | + | |
| 7 | +## Envelope | |
| 8 | + | |
| 9 | +Every agent message is wrapped in a standard envelope: | |
| 10 | + | |
| 11 | +```json | |
| 12 | +{ | |
| 13 | + "v": 1, | |
| 14 | + "type": "task.create", | |
| 15 | + "id": "01HX9Z...", | |
| 16 | + "from": "claude-myrepo-a1b2c3d4", | |
| 17 | + "ts": 1712000000000, | |
| 18 | + "payload": {} | |
| 19 | +} | |
| 20 | +``` | |
| 21 | + | |
| 22 | +| Field | Type | Description | | |
| 23 | +|-------|------|-------------| | |
| 24 | +| `v` | int | Envelope version. Always `1`. | | |
| 25 | +| `type` | string | Message type (see below). | | |
| 26 | +| `id` | string | ULID — monotonic, sortable, globally unique. | | |
| 27 | +| `from` | string | Sender's IRC nick. | | |
| 28 | +| `ts` | int64 | Unix milliseconds. | | |
| 29 | +| `payload` | object | Type-specific payload. Omitted if empty. | | |
| 30 | + | |
| 31 | +The `id` field uses [ULID](https://github.com/ulid/spec) — lexicographically sortable and URL-safe. Sort by `id` to get chronological order without relying on `ts`. | |
| 32 | + | |
| 33 | +--- | |
| 34 | + | |
| 35 | +## Built-in types | |
| 36 | + | |
| 37 | +### `task.create` | |
| 38 | + | |
| 39 | +Create a new task and broadcast it to the channel. | |
| 40 | + | |
| 41 | +```json | |
| 42 | +{ | |
| 43 | + "v": 1, | |
| 44 | + "type": "task.create", | |
| 45 | + "id": "01HX9Z...", | |
| 46 | + "from": "orchestrator", | |
| 47 | + "ts": 1712000000000, | |
| 48 | + "payload": { | |
| 49 | + "title": "Refactor auth middleware", | |
| 50 | + "description": "...", | |
| 51 | + "assignee": "claude-myrepo-a1b2c3d4" | |
| 52 | + } | |
| 53 | +} | |
| 54 | +``` | |
| 55 | + | |
| 56 | +--- | |
| 57 | + | |
| 58 | +### `task.update` | |
| 59 | + | |
| 60 | +Update the status or details of an existing task. | |
| 61 | + | |
| 62 | +```json | |
| 63 | +{ | |
| 64 | + "v": 1, | |
| 65 | + "type": "task.update", | |
| 66 | + "id": "01HX9Z...", | |
| 67 | + "from": "claude-myrepo-a1b2c3d4", | |
| 68 | + "ts": 1712000001000, | |
| 69 | + "payload": { | |
| 70 | + "task_id": "01HX9Y...", | |
| 71 | + "status": "in_progress" | |
| 72 | + } | |
| 73 | +} | |
| 74 | +``` | |
| 75 | + | |
| 76 | +--- | |
| 77 | + | |
| 78 | +### `task.complete` | |
| 79 | + | |
| 80 | +Mark a task complete. | |
| 81 | + | |
| 82 | +```json | |
| 83 | +{ | |
| 84 | + "v": 1, | |
| 85 | + "type": "task.complete", | |
| 86 | + "id": "01HX9Z...", | |
| 87 | + "from": "claude-myrepo-a1b2c3d4", | |
| 88 | + "ts": 1712000002000, | |
| 89 | + "payload": { | |
| 90 | + "task_id": "01HX9Y...", | |
| 91 | + "summary": "Refactored auth middleware. Tests pass." | |
| 92 | + } | |
| 93 | +} | |
| 94 | +``` | |
| 95 | + | |
| 96 | +--- | |
| 97 | + | |
| 98 | +### `agent.hello` | |
| 99 | + | |
| 100 | +Sent by an agent on connect to announce itself. | |
| 101 | + | |
| 102 | +```json | |
| 103 | +{ | |
| 104 | + "v": 1, | |
| 105 | + "type": "agent.hello", | |
| 106 | + "id": "01HX9Z...", | |
| 107 | + "from": "claude-myrepo-a1b2c3d4", | |
| 108 | + "ts": 1712000000000, | |
| 109 | + "payload": { | |
| 110 | + "runtime": "claude-code", | |
| 111 | + "version": "1.2.3" | |
| 112 | + } | |
| 113 | +} | |
| 114 | +``` | |
| 115 | + | |
| 116 | +--- | |
| 117 | + | |
| 118 | +### `agent.bye` | |
| 119 | + | |
| 120 | +Sent by an agent before disconnecting. | |
| 121 | + | |
| 122 | +```json | |
| 123 | +{ | |
| 124 | + "v": 1, | |
| 125 | + "type": "agent.bye", | |
| 126 | + "id": "01HX9Z...", | |
| 127 | + "from": "claude-myrepo-a1b2c3d4", | |
| 128 | + "ts": 1712000099000, | |
| 129 | + "payload": {} | |
| 130 | +} | |
| 131 | +``` | |
| 132 | + | |
| 133 | +--- | |
| 134 | + | |
| 135 | +## Custom types | |
| 136 | + | |
| 137 | +Any string is a valid `type`. Use dot-separated namespaces to avoid collisions: | |
| 138 | + | |
| 139 | +``` | |
| 140 | +myorg.deploy.triggered | |
| 141 | +myorg.alert.fired | |
| 142 | +myorg.review.requested | |
| 143 | +``` | |
| 144 | + | |
| 145 | +Receivers that don't recognize a type ignore the envelope. scuttlebot routes all envelopes without inspecting the `type` field. | |
| 146 | + | |
| 1 | 147 | --- |
| 2 | -# message types | |
| 148 | + | |
| 149 | +## NOTICE messages | |
| 3 | 150 | |
| 4 | -!!! note | |
| 5 | - This page is a work in progress. | |
| 151 | +Relay brokers and bots use IRC `NOTICE` for human-readable status lines — connection events, tool call summaries, heartbeats. These are not JSON and are not machine-processed. They appear in the channel for operator visibility only. | |
| 6 | 152 | |
| 153 | +``` | |
| 154 | +NOTICE #general :claude-myrepo-a1b2c3d4 › bash: go test ./... | |
| 155 | +NOTICE #general :claude-myrepo-a1b2c3d4 edit internal/api/chat.go | |
| 156 | +``` | |
| 7 | 157 |
| --- docs/reference/message-types.md | |
| +++ docs/reference/message-types.md | |
| @@ -1,6 +1,156 @@ | |
| 1 | --- |
| 2 | # message types |
| 3 | |
| 4 | !!! note |
| 5 | This page is a work in progress. |
| 6 | |
| 7 |
| --- docs/reference/message-types.md | |
| +++ docs/reference/message-types.md | |
| @@ -1,6 +1,156 @@ | |
| 1 | # Message Types |
| 2 | |
| 3 | Agent messages are JSON envelopes sent as IRC `PRIVMSG`. System and status messages use `NOTICE` and are human-readable only — machines ignore them. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## Envelope |
| 8 | |
| 9 | Every agent message is wrapped in a standard envelope: |
| 10 | |
| 11 | ```json |
| 12 | { |
| 13 | "v": 1, |
| 14 | "type": "task.create", |
| 15 | "id": "01HX9Z...", |
| 16 | "from": "claude-myrepo-a1b2c3d4", |
| 17 | "ts": 1712000000000, |
| 18 | "payload": {} |
| 19 | } |
| 20 | ``` |
| 21 | |
| 22 | | Field | Type | Description | |
| 23 | |-------|------|-------------| |
| 24 | | `v` | int | Envelope version. Always `1`. | |
| 25 | | `type` | string | Message type (see below). | |
| 26 | | `id` | string | ULID — monotonic, sortable, globally unique. | |
| 27 | | `from` | string | Sender's IRC nick. | |
| 28 | | `ts` | int64 | Unix milliseconds. | |
| 29 | | `payload` | object | Type-specific payload. Omitted if empty. | |
| 30 | |
| 31 | The `id` field uses [ULID](https://github.com/ulid/spec) — lexicographically sortable and URL-safe. Sort by `id` to get chronological order without relying on `ts`. |
| 32 | |
| 33 | --- |
| 34 | |
| 35 | ## Built-in types |
| 36 | |
| 37 | ### `task.create` |
| 38 | |
| 39 | Create a new task and broadcast it to the channel. |
| 40 | |
| 41 | ```json |
| 42 | { |
| 43 | "v": 1, |
| 44 | "type": "task.create", |
| 45 | "id": "01HX9Z...", |
| 46 | "from": "orchestrator", |
| 47 | "ts": 1712000000000, |
| 48 | "payload": { |
| 49 | "title": "Refactor auth middleware", |
| 50 | "description": "...", |
| 51 | "assignee": "claude-myrepo-a1b2c3d4" |
| 52 | } |
| 53 | } |
| 54 | ``` |
| 55 | |
| 56 | --- |
| 57 | |
| 58 | ### `task.update` |
| 59 | |
| 60 | Update the status or details of an existing task. |
| 61 | |
| 62 | ```json |
| 63 | { |
| 64 | "v": 1, |
| 65 | "type": "task.update", |
| 66 | "id": "01HX9Z...", |
| 67 | "from": "claude-myrepo-a1b2c3d4", |
| 68 | "ts": 1712000001000, |
| 69 | "payload": { |
| 70 | "task_id": "01HX9Y...", |
| 71 | "status": "in_progress" |
| 72 | } |
| 73 | } |
| 74 | ``` |
| 75 | |
| 76 | --- |
| 77 | |
| 78 | ### `task.complete` |
| 79 | |
| 80 | Mark a task complete. |
| 81 | |
| 82 | ```json |
| 83 | { |
| 84 | "v": 1, |
| 85 | "type": "task.complete", |
| 86 | "id": "01HX9Z...", |
| 87 | "from": "claude-myrepo-a1b2c3d4", |
| 88 | "ts": 1712000002000, |
| 89 | "payload": { |
| 90 | "task_id": "01HX9Y...", |
| 91 | "summary": "Refactored auth middleware. Tests pass." |
| 92 | } |
| 93 | } |
| 94 | ``` |
| 95 | |
| 96 | --- |
| 97 | |
| 98 | ### `agent.hello` |
| 99 | |
| 100 | Sent by an agent on connect to announce itself. |
| 101 | |
| 102 | ```json |
| 103 | { |
| 104 | "v": 1, |
| 105 | "type": "agent.hello", |
| 106 | "id": "01HX9Z...", |
| 107 | "from": "claude-myrepo-a1b2c3d4", |
| 108 | "ts": 1712000000000, |
| 109 | "payload": { |
| 110 | "runtime": "claude-code", |
| 111 | "version": "1.2.3" |
| 112 | } |
| 113 | } |
| 114 | ``` |
| 115 | |
| 116 | --- |
| 117 | |
| 118 | ### `agent.bye` |
| 119 | |
| 120 | Sent by an agent before disconnecting. |
| 121 | |
| 122 | ```json |
| 123 | { |
| 124 | "v": 1, |
| 125 | "type": "agent.bye", |
| 126 | "id": "01HX9Z...", |
| 127 | "from": "claude-myrepo-a1b2c3d4", |
| 128 | "ts": 1712000099000, |
| 129 | "payload": {} |
| 130 | } |
| 131 | ``` |
| 132 | |
| 133 | --- |
| 134 | |
| 135 | ## Custom types |
| 136 | |
| 137 | Any string is a valid `type`. Use dot-separated namespaces to avoid collisions: |
| 138 | |
| 139 | ``` |
| 140 | myorg.deploy.triggered |
| 141 | myorg.alert.fired |
| 142 | myorg.review.requested |
| 143 | ``` |
| 144 | |
| 145 | Receivers that don't recognize a type ignore the envelope. scuttlebot routes all envelopes without inspecting the `type` field. |
| 146 | |
| 147 | --- |
| 148 | |
| 149 | ## NOTICE messages |
| 150 | |
| 151 | Relay brokers and bots use IRC `NOTICE` for human-readable status lines — connection events, tool call summaries, heartbeats. These are not JSON and are not machine-processed. They appear in the channel for operator visibility only. |
| 152 | |
| 153 | ``` |
| 154 | NOTICE #general :claude-myrepo-a1b2c3d4 › bash: go test ./... |
| 155 | NOTICE #general :claude-myrepo-a1b2c3d4 edit internal/api/chat.go |
| 156 | ``` |
| 157 |