You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: crates/buzz-acp/README.md
+64-7Lines changed: 64 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -142,10 +142,19 @@ The gate applies to **all** inbound events — @mentions, DMs, thread replies, a
142
142
| Command | Effect |
143
143
|---------|--------|
144
144
|`!shutdown`| Gracefully exits the harness. |
145
-
|`!cancel`| Cancels the current in-flight turn for that channel, if any. |
146
-
|`!rotate`| Rotates the ACP session for that channel. If a turn is in-flight, it is cancelled and the channel session is invalidated when the task returns; otherwise the cached idle session is invalidated immediately. The next queued/received event starts a fresh session. |
145
+
|`!cancel`| Cancels the current in-flight turn for the conversation the command targets, if any. |
146
+
|`!rotate`| Rotates the ACP session for the conversation the command targets. If a turn is in-flight for that conversation, it is cancelled and the session is invalidated when the task returns; otherwise the cached idle session is invalidated immediately. The next queued/received event in that conversation starts a fresh session. |
147
147
148
-
Use `!cancel` to stop only the current turn; it is a no-op when the channel is idle. Use `!rotate` when you want the next turn in the channel to start from a fresh ACP session, even if the channel is currently idle.
148
+
`!cancel` and `!rotate` are **conversation-scoped** (see [Session Scope](#session-scope)):
149
+
send the command **as a reply inside a thread** to target that thread's session,
150
+
or as a **bare (unthreaded) channel message** to target the channel-level
151
+
conversation. A thread-scoped command never cancels or rotates sibling threads
152
+
or the channel conversation, and a channel-level command never destroys thread
153
+
sessions.
154
+
155
+
Use `!cancel` to stop only the current turn; it is a no-op when the targeted
156
+
conversation is idle. Use `!rotate` when you want the next turn in that
157
+
conversation to start from a fresh ACP session, even if it is currently idle.
149
158
150
159
Owner control commands must be kind:9 stream messages from the owner, must mention this agent with a `p` tag, and are consumed by the harness instead of being forwarded to the agent.
All N agents authenticate as the **same Nostr bot identity** — users see one bot regardless of how many agents are running. The same channel is never processed by two agents simultaneously (the queue enforces this). Cross-channel message ordering is not guaranteed when N>1.
205
+
All N agents authenticate as the **same Nostr bot identity** — users see one bot regardless of how many agents are running. The same conversation (see [Session Scope](#session-scope)) is never processed by two agents simultaneously (the queue enforces this); different conversations — including different threads in one channel — can run concurrently when N>1. Cross-conversation message ordering is not guaranteed when N>1.
206
+
207
+
### Session Scope
208
+
209
+
The harness keys ACP sessions (and queueing, steering, turn counters, and
210
+
`!cancel`/`!rotate` targeting) by **conversation**, not just by channel:
211
+
212
+
-**Unthreaded channel messages** share one channel-level conversation — one
213
+
continuous ACP session per channel, as before.
214
+
-**Thread replies** in a regular channel are scoped by `(channel, thread
215
+
root)`: every thread gets its own isolated ACP session. Replies in the same
216
+
thread reuse that thread's session; separate threads in the same channel
217
+
never share or pollute each other's sessions, and can be in-flight
218
+
simultaneously.
219
+
-**Forum posts** (kind 45001) are thread roots: a post scopes to its own
220
+
event ID, and comments on it (kind 45003) resolve to the same
221
+
conversation, so a forum post and its comment thread share one session
222
+
while separate posts in the same channel stay isolated.
223
+
-**DMs** always use channel-level continuity — one session per DM
224
+
conversation, even for replies with thread tags.
225
+
-**Channels joined after startup** resolve and cache their metadata before
226
+
the harness opens event delivery. Failed lookups retry while the membership
227
+
remains active. The first delivered event therefore scopes normally — DMs
228
+
channel-level, regular/forum channels per-thread — without an
229
+
event-before-metadata fallback that could split one conversation.
230
+
231
+
For stream messages the thread root is the canonical NIP-10 `root` marker
232
+
from the reply's `e` tags. Note a stream thread's root message is itself an
233
+
unthreaded channel message — it runs in the channel-level conversation; the
234
+
thread's own session begins with the first reply.
235
+
236
+
**Stable agent ownership (N > 1):** a conversation's session history lives in
237
+
exactly one agent process, so each conversation is pinned to the agent that
238
+
serves it. If that agent is busy on other work when new events arrive, the
239
+
conversation waits for it (fairness position preserved) instead of being
240
+
forked onto another agent. Ownership is released when the session is rotated
241
+
or invalidated, or when the owning agent process dies — the next turn then
242
+
starts a fresh session on any agent.
243
+
244
+
**Desktop model switching** is channel-level desired state: a `switch_model`
245
+
control frame updates every idle agent holding sessions under the channel,
246
+
signals every in-flight conversation under it, and is inherited by any agent
247
+
that later picks up a conversation in that channel.
248
+
249
+
When the agent is removed from a channel, every conversation under that
250
+
channel — channel-level and all threads — is drained and its sessions are
251
+
invalidated. This is agent conversation routing only: channel identity,
252
+
subscriptions, and NIP-29 authorization remain keyed by the `h`-tag channel
253
+
UUID.
197
254
198
255
### Heartbeat Semantics
199
256
@@ -242,12 +299,12 @@ Forum event kinds:
242
299
243
300
1.**Startup** — Spawns N agent subprocesses (default 1), sends ACP `initialize` to each, connects to the relay with NIP-42 auth.
244
301
2.**Channel discovery** — Queries the relay REST API for accessible channels, subscribes to each.
245
-
3.**Event loop** — Listens for @mention events (kind 9 with the agent's pubkey in a `#p` tag). Events queue per channel.
246
-
4.**Prompting** — When events are pending and no prompt is in flight for that channel, drains all queued events for the oldest channel into a single batched prompt via ACP `session/prompt`.
302
+
3.**Event loop** — Listens for @mention events (kind 9 with the agent's pubkey in a `#p` tag). Events queue per conversation (channel-level or thread — see [Session Scope](#session-scope)).
303
+
4.**Prompting** — When events are pending and no prompt is in flight for that conversation, drains all queued events for the oldest conversation into a single batched prompt via ACP `session/prompt`. Events from different conversations are never batched together.
247
304
5.**Agent response** — The agent processes the prompt and uses the Buzz CLI (`send_message`, `get_messages`, etc.) to interact with Buzz.
248
305
6.**Recovery** — If the agent crashes, the harness respawns it. If the relay disconnects, the harness reconnects with a `since` filter to avoid missing events.
249
306
250
-
Each channel has at most one prompt in flight. Multiple channels can be processed concurrently when agents > 1.
307
+
Each conversation has at most one prompt in flight. Multiple conversations — including multiple threads within one channel — can be processed concurrently when agents > 1.
251
308
252
309
> **Note:** On startup, the harness replays all unprocessed @mentions since the last run. Expect a burst of activity if there are stale events in the channel.
0 commit comments