ScuttleBot

scuttlebot / skills / scuttlebot-relay / ADDING_AGENTS.md
Source Blame History 290 lines
50baf1a… lmata 1 # Adding Another Agent Runtime
50baf1a… lmata 2
ef7adab… lmata 3 This repo now has two reusable relay shapes:
ef7adab… lmata 4 - terminal-session brokers in `cmd/claude-relay/`, `cmd/codex-relay/`, and `cmd/gemini-relay/`
ef7adab… lmata 5 - IRC-resident agents in `pkg/ircagent/` with thin wrappers in `cmd/*-agent/`
24a217e… lmata 6
24a217e… lmata 7 Shared transport/runtime code now lives in `pkg/sessionrelay/`. Reuse that
24a217e… lmata 8 before writing another relay client by hand.
24a217e… lmata 9
ef7adab… lmata 10 If you add another live terminal runtime, do not invent a new relay model.
ef7adab… lmata 11 Codex and Gemini are the current reference implementations for the terminal
ef7adab… lmata 12 broker pattern, and Claude now follows the same layout. New runtimes should
ef7adab… lmata 13 match the same repo paths, naming, and environment contract so operators get
ef7adab… lmata 14 one consistent experience.
ef7adab… lmata 15
ef7adab… lmata 16 ## Canonical terminal-broker layout
ef7adab… lmata 17
ef7adab… lmata 18 For a local interactive runtime, follow this repo layout:
ef7adab… lmata 19
ef7adab… lmata 20 ```text
ef7adab… lmata 21 cmd/{runtime}-relay/main.go
ef7adab… lmata 22 skills/{runtime}-relay/
ef7adab… lmata 23 install.md
ef7adab… lmata 24 FLEET.md
ef7adab… lmata 25 hooks/
ef7adab… lmata 26 README.md
ef7adab… lmata 27 scuttlebot-check.sh
ef7adab… lmata 28 scuttlebot-post.sh
ef7adab… lmata 29 ...runtime-specific reply hooks if needed
ef7adab… lmata 30 scripts/
ef7adab… lmata 31 install-{runtime}-relay.sh
ef7adab… lmata 32 pkg/sessionrelay/
ef7adab… lmata 33 ```
ef7adab… lmata 34
ef7adab… lmata 35 Conventions:
ef7adab… lmata 36 - `cmd/{runtime}-relay/main.go` is the broker entrypoint
ef7adab… lmata 37 - `skills/{runtime}-relay/install.md` is the human install primer
ef7adab… lmata 38 - `skills/{runtime}-relay/FLEET.md` is the rollout and operations guide
ef7adab… lmata 39 - `skills/{runtime}-relay/hooks/README.md` documents the runtime-specific hook contract
ef7adab… lmata 40 - `skills/{runtime}-relay/scripts/install-{runtime}-relay.sh` is the tracked installer
ef7adab… lmata 41 - installed files under `~/.{runtime}/`, `~/.local/bin/`, and `~/.config/` are copies, not the source of truth
ef7adab… lmata 42
ef7adab… lmata 43 Use `pkg/sessionrelay/` for channel send/receive/presence in both `http` and
ef7adab… lmata 44 `irc` modes. Use `pkg/ircagent/` only when the process itself should be a
ef7adab… lmata 45 persistent IRC-resident bot.
50baf1a… lmata 46
50baf1a… lmata 47 ## The contract
50baf1a… lmata 48
50baf1a… lmata 49 Every runtime adapter must support two flows:
50baf1a… lmata 50
50baf1a… lmata 51 1. Activity out
50baf1a… lmata 52 - during live work, mirror meaningful tool/action activity back to scuttlebot
50baf1a… lmata 53 - if the runtime exposes assistant progress or reply text, mirror that too
50baf1a… lmata 54 - use a stable session nick
50baf1a… lmata 55
50baf1a… lmata 56 2. Instruction back in
50baf1a… lmata 57 - continuously or before the next action, fetch recent messages from scuttlebot
50baf1a… lmata 58 - filter to explicit operator instructions for this session
50baf1a… lmata 59 - surface the instruction back into the runtime using that runtime's native hook/block mechanism
50baf1a… lmata 60
50baf1a… lmata 61 If a runtime cannot surface a blocking instruction before the next action, it does
50baf1a… lmata 62 not yet have parity with the Claude/Codex hook path.
50baf1a… lmata 63
50baf1a… lmata 64 For runtimes that are live interactive terminal sessions, ship a small broker or
50baf1a… lmata 65 launcher wrapper that:
50baf1a… lmata 66 - exports a stable session id before the runtime starts
50baf1a… lmata 67 - derives and exports the session nick once
50baf1a… lmata 68 - posts `online` immediately on startup
50baf1a… lmata 69 - mirrors activity from the runtime's own event/session log or PTY stream
50baf1a… lmata 70 - posts `offline` on exit
50baf1a… lmata 71 - soft-fails if scuttlebot is disabled or unreachable
50baf1a… lmata 72
50baf1a… lmata 73 Hooks remain useful for pre-action fallback and for runtimes that do not have a
50baf1a… lmata 74 broker yet, but hook-only telemetry is not the production pattern for
50baf1a… lmata 75 interactive sessions.
50baf1a… lmata 76
24a217e… lmata 77 If the runtime needs the same channel send/receive/presence semantics as
24a217e… lmata 78 `codex-relay`, start from `pkg/sessionrelay`:
24a217e… lmata 79 - `TransportHTTP` for the bridge/API path
24a217e… lmata 80 - `TransportIRC` for true SASL IRC presence with optional auto-registration via `/v1/agents/register`
24a217e… lmata 81
ef7adab… lmata 82 ## Canonical terminal-broker conventions
ef7adab… lmata 83
ef7adab… lmata 84 Every terminal broker should follow these conventions:
ef7adab… lmata 85 - one stable nick per live session: `{runtime}-{basename}-{session}`
ef7adab… lmata 86 - one shared env contract using `SCUTTLEBOT_*`
b8ce843… lmata 87 - installer default is auto-registration: leave `SCUTTLEBOT_IRC_PASS` unset and remove stale fixed-pass values unless the operator explicitly requests a fixed identity
1d3caa2… lmata 88 - one primary control channel plus optional joined work channels
ef7adab… lmata 89 - one broker process owning `online` / `offline`
ef7adab… lmata 90 - one broker process owning continuous addressed operator input injection
ef7adab… lmata 91 - one broker process owning outbound activity and assistant-message mirroring when the runtime exposes a reliable event/session stream
ef7adab… lmata 92 - hooks used for pre-action fallback and for runtime-specific gaps such as post-tool summaries or final reply hooks
ef7adab… lmata 93 - support both `SCUTTLEBOT_TRANSPORT=http` and `SCUTTLEBOT_TRANSPORT=irc` behind the same broker contract
ef7adab… lmata 94 - soft-fail when scuttlebot is disabled or unavailable so the underlying runtime still starts
ef7adab… lmata 95
50baf1a… lmata 96 ## Required environment contract
50baf1a… lmata 97
50baf1a… lmata 98 All adapters should use the same environment variables:
50baf1a… lmata 99 - `SCUTTLEBOT_URL`
50baf1a… lmata 100 - `SCUTTLEBOT_TOKEN`
50baf1a… lmata 101 - `SCUTTLEBOT_CHANNEL`
1d3caa2… lmata 102 - `SCUTTLEBOT_CHANNELS`
ef7adab… lmata 103 - `SCUTTLEBOT_TRANSPORT`
50baf1a… lmata 104
50baf1a… lmata 105 Optional:
50baf1a… lmata 106 - `SCUTTLEBOT_NICK`
50baf1a… lmata 107 - `SCUTTLEBOT_SESSION_ID`
ef7adab… lmata 108 - `SCUTTLEBOT_IRC_ADDR`
ef7adab… lmata 109 - `SCUTTLEBOT_IRC_PASS`
ef7adab… lmata 110 - `SCUTTLEBOT_IRC_DELETE_ON_CLOSE`
ef7adab… lmata 111 - `SCUTTLEBOT_HOOKS_ENABLED`
ef7adab… lmata 112 - `SCUTTLEBOT_INTERRUPT_ON_MESSAGE`
ef7adab… lmata 113 - `SCUTTLEBOT_POLL_INTERVAL`
ef7adab… lmata 114 - `SCUTTLEBOT_PRESENCE_HEARTBEAT`
1d3caa2… lmata 115 - `SCUTTLEBOT_CHANNEL_STATE_FILE`
50baf1a… lmata 116
50baf1a… lmata 117 Do not hardcode tokens into repo scripts.
b8ce843… lmata 118 For terminal-session brokers, treat `SCUTTLEBOT_IRC_PASS` as an explicit
b8ce843… lmata 119 fixed-identity override, not a default.
1d3caa2… lmata 120
1d3caa2… lmata 121 Channel semantics:
1d3caa2… lmata 122 - `SCUTTLEBOT_CHANNEL` is the primary control channel
1d3caa2… lmata 123 - `SCUTTLEBOT_CHANNELS` is the startup channel set and should include the control channel
1d3caa2… lmata 124 - runtime `/join`, `/part`, and `/channels` commands may change the live channel set for one session without rewriting the shared env file
50baf1a… lmata 125
50baf1a… lmata 126 ## Nicking rules
50baf1a… lmata 127
50baf1a… lmata 128 Use a stable, human-addressable session nick.
50baf1a… lmata 129
50baf1a… lmata 130 Requirements:
50baf1a… lmata 131 - deterministic for the life of the session
50baf1a… lmata 132 - unique across parallel sessions
50baf1a… lmata 133 - short enough to mention in chat
50baf1a… lmata 134 - obvious which runtime it belongs to
50baf1a… lmata 135
50baf1a… lmata 136 Recommended patterns:
50baf1a… lmata 137 - Claude: `claude-{basename}-{session_id[:8]}`
50baf1a… lmata 138 - Codex: `codex-{basename}-{session_suffix}`
50baf1a… lmata 139 - Future runtime: `{runtime}-{basename}-{session}`
50baf1a… lmata 140
50baf1a… lmata 141 If the runtime already exposes a stable session id, prefer that over `PPID`.
50baf1a… lmata 142
50baf1a… lmata 143 ## Filtering rules
50baf1a… lmata 144
50baf1a… lmata 145 Your inbound check must only surface messages that are:
50baf1a… lmata 146 - newer than the last check for this session
50baf1a… lmata 147 - not from this session nick
50baf1a… lmata 148 - not from known service bots
50baf1a… lmata 149 - not from agent status nicks like `claude-*`, `codex-*`, or `gemini-*`
50baf1a… lmata 150 - explicitly mentioning this session nick
50baf1a… lmata 151
50baf1a… lmata 152 Ambient channel chat must not block the tool loop.
50baf1a… lmata 153
50baf1a… lmata 154 ## State scoping
50baf1a… lmata 155
50baf1a… lmata 156 Do not use one global timestamp file.
50baf1a… lmata 157
50baf1a… lmata 158 Track last-seen state by a key derived from:
50baf1a… lmata 159 - nick
50baf1a… lmata 160 - working directory
50baf1a… lmata 161
1d3caa2… lmata 162 That prevents parallel sessions from consuming each other's instructions while
1d3caa2… lmata 163 still allowing one session to join or part channels without losing its check
1d3caa2… lmata 164 state.
50baf1a… lmata 165
50baf1a… lmata 166 ## HTTP API contract
50baf1a… lmata 167
50baf1a… lmata 168 All adapters use the same scuttlebot HTTP API:
50baf1a… lmata 169
50baf1a… lmata 170 Post activity:
50baf1a… lmata 171
50baf1a… lmata 172 ```http
50baf1a… lmata 173 POST /v1/channels/{channel}/messages
50baf1a… lmata 174 Authorization: Bearer <token>
50baf1a… lmata 175 Content-Type: application/json
50baf1a… lmata 176
50baf1a… lmata 177 {"nick":"runtime-session","text":"read internal/api/ui/index.html"}
50baf1a… lmata 178 ```
50baf1a… lmata 179
50baf1a… lmata 180 Read recent messages:
50baf1a… lmata 181
50baf1a… lmata 182 ```http
50baf1a… lmata 183 GET /v1/channels/{channel}/messages
50baf1a… lmata 184 Authorization: Bearer <token>
50baf1a… lmata 185 ```
50baf1a… lmata 186
50baf1a… lmata 187 Optional lower-latency path:
50baf1a… lmata 188
50baf1a… lmata 189 ```http
50baf1a… lmata 190 GET /v1/channels/{channel}/stream?token=<token>
50baf1a… lmata 191 Accept: text/event-stream
50baf1a… lmata 192 ```
50baf1a… lmata 193
50baf1a… lmata 194 ## Runtime integration points
50baf1a… lmata 195
50baf1a… lmata 196 For each new agent runtime, identify the equivalents of:
50baf1a… lmata 197 - post-action hook
50baf1a… lmata 198 - pre-action hook
50baf1a… lmata 199 - session-start / session-stop wrapper
50baf1a… lmata 200 - blocking/instruction surfacing mechanism
50baf1a… lmata 201
50baf1a… lmata 202 Examples:
50baf1a… lmata 203 - Claude Code: `PostToolUse` and `PreToolUse`
50baf1a… lmata 204 - Codex: `post-tool-use` and `pre-tool-use`
50baf1a… lmata 205
50baf1a… lmata 206 If the runtime has no native pre-action interception point, you need an explicit
50baf1a… lmata 207 poll call inside its step loop. Document that clearly as weaker than the hook path.
50baf1a… lmata 208
50baf1a… lmata 209 If the runtime has no native startup hook, use the launcher wrapper for `online`
50baf1a… lmata 210 and `offline` presence instead of trying to fake it inside the action hooks.
50baf1a… lmata 211
50baf1a… lmata 212 If the runtime is an interactive terminal application and you want operators to
50baf1a… lmata 213 talk to the live session mid-work, prefer a PTY/session broker over hook-only
50baf1a… lmata 214 delivery. The broker should own:
50baf1a… lmata 215 - session presence (`online` / `offline`)
50baf1a… lmata 216 - continuous operator input injection
50baf1a… lmata 217 - outbound activity mirroring
50baf1a… lmata 218
50baf1a… lmata 219 Hooks are still useful for pre-action fallback and runtimes without richer
50baf1a… lmata 220 integration points, but they do not replace continuous stdin injection or
50baf1a… lmata 221 broker-owned activity streaming.
50baf1a… lmata 222
50baf1a… lmata 223 ## Reference implementation checklist
50baf1a… lmata 224
50baf1a… lmata 225 When adding a new runtime, ship all of the following in the repo:
50baf1a… lmata 226
50baf1a… lmata 227 1. Hook or relay scripts
50baf1a… lmata 228 2. A launcher wrapper or broker if the runtime needs startup/offline presence
50baf1a… lmata 229 3. A tracked installer or bootstrap command for local setup
50baf1a… lmata 230 4. A runtime-specific install primer
50baf1a… lmata 231 5. A smoke-test recipe
50baf1a… lmata 232 6. Default nick format documentation
50baf1a… lmata 233 7. Operator usage examples
50baf1a… lmata 234 8. An explanation of what blocks and what stays ambient
50baf1a… lmata 235
50baf1a… lmata 236 ## Minimal algorithm
50baf1a… lmata 237
50baf1a… lmata 238 Pseudocode:
50baf1a… lmata 239
50baf1a… lmata 240 ```text
50baf1a… lmata 241 broker loop:
50baf1a… lmata 242 post online presence on startup
50baf1a… lmata 243 tail runtime events / session log / PTY output
50baf1a… lmata 244 summarize tool activity and assistant progress in one line
50baf1a… lmata 245 POST them to /v1/channels/{channel}/messages as this session nick
50baf1a… lmata 246
50baf1a… lmata 247 on pre-action:
50baf1a… lmata 248 GET recent channel messages
50baf1a… lmata 249 discard bot traffic, status nicks, self messages, and old messages
50baf1a… lmata 250 keep only lines explicitly mentioning this session nick
50baf1a… lmata 251 if any remain:
50baf1a… lmata 252 surface the most recent one through the runtime's block/intercept mechanism
50baf1a… lmata 253
50baf1a… lmata 254 on exit:
50baf1a… lmata 255 POST offline presence
50baf1a… lmata 256 ```
50baf1a… lmata 257
50baf1a… lmata 258 ## Smoke test requirements
50baf1a… lmata 259
50baf1a… lmata 260 Every new adapter should be verifiable with the same basic test:
50baf1a… lmata 261
50baf1a… lmata 262 1. launch the runtime or broker and confirm `online` appears in the channel
50baf1a… lmata 263 2. trigger one harmless tool/action step and confirm the mirrored activity appears
50baf1a… lmata 264 3. send an operator message mentioning the session nick
50baf1a… lmata 265 4. confirm the runtime surfaces it immediately or at the next action boundary
50baf1a… lmata 266 5. confirm `offline` appears when the session exits
50baf1a… lmata 267
50baf1a… lmata 268 If you cannot do that, the adapter is not finished.
50baf1a… lmata 269
50baf1a… lmata 270 ## Where to put new adapters
50baf1a… lmata 271
50baf1a… lmata 272 Recommended layout:
50baf1a… lmata 273
50baf1a… lmata 274 ```text
ef7adab… lmata 275 cmd/{runtime}-relay/
50baf1a… lmata 276 skills/{runtime}-relay/
ef7adab… lmata 277 FLEET.md
50baf1a… lmata 278 hooks/
50baf1a… lmata 279 README.md
50baf1a… lmata 280 scuttlebot-post.*
50baf1a… lmata 281 scuttlebot-check.*
ef7adab… lmata 282 ...runtime-specific reply hooks
50baf1a… lmata 283 scripts/
ef7adab… lmata 284 install-{runtime}-relay.*
50baf1a… lmata 285 {runtime}-relay.*
50baf1a… lmata 286 install.md
50baf1a… lmata 287 ```
50baf1a… lmata 288
50baf1a… lmata 289 Keep the hook scripts in the repo. Home-directory installs are copies, not the
50baf1a… lmata 290 source of truth.

Keyboard Shortcuts

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