`!rotate` is unreachable from the Desktop composer — mention text breaks the exact-match gate
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Summary
`buzz-acp` supports an owner-only `!rotate` control message that drops an agent's session for one channel. The gate requires the event content to equal `!rotate` exactly *and* to carry a `p` tag for the agent. The Desktop composer leaves the `@Name` text in the event body, so the only message that can produce the required `p` tag also fails the content equality check. The command is effectively unreachable from the app.
## The gate
```rust
fn is_owner_control_command(
event: &nostr::Event,
kind_u32: u32,
command: &str,
agent_pubkey_hex: &str,
) -> bool {
kind_u32 == KIND_STREAM_MESSAGE
&& event.content.trim() == command
&& event_mentions_agent(event, agent_pubkey_hex)
}
```
`crates/buzz-acp/src/lib.rs:3080-3089`
`event_mentions_agent` requires a `p` tag matching the agent pubkey (`crates/buzz-acp/src/lib.rs:3073-3078`).
## Why the two conditions can't both hold from Desktop
The composer resolves `@Name` into a `p` tag but keeps the literal text in `content` (`desktop/src/features/messages/lib/extractMentionPubkeys.ts`). Observed on a live relay: a message typed as `@Top Clear this thread…` arrives with
```
content: "@Top Clear this thread. I think context is getting crazy. …"
tags: [["h", …], ["e", …, "reply"], ["p", "1219c751…"]]
```
So:
| Typed | `content.trim()` | has `p` tag | matches |
|---|---|---|---|
| `!rotate` | `!rotate` | no | no |
| `@Top !rotate` | `@Top !rotate` | yes | no |
Same reasoning applies to `!shutdown` and `!cancel` (`crates/buzz-acp/src/lib.rs:2338`, `:2369`).
There is also no UI affordance — a search of `desktop/src` for `rotate` returns only CSS transform classes.
## Impact
`--max-turns-per-session` defaults to `0`, i.e. proactive rotation disabled (`crates/buzz-acp/src/config.rs:370-374`), and Buzz Desktop does not set it (verified with `ps eww` on a running `buzz-acp`: no `BUZZ_ACP_MAX_TURNS_PER_SESSION` in the process environment). A channel session therefore grows until it hits the model's token ceiling. With `!rotate` unreachable, the only user-facing way to clear a heavy session is Stop/Start from the members sidebar, which drops that agent's context in **every** channel, not just the noisy one.
## Suggested fixes (any one is sufficient)
1. **Relax the gate** — strip resolved `@Name` mention spans from `content` before the equality check, or match on the first non-mention token.
2. **Add a UI affordance** — a "Clear context in this channel" item on the agent's entry in the members sidebar, emitting a well-formed `!rotate`.
3. **Ship a safe default** — set `max_turns_per_session` to a non-zero default so sessions rotate before they hit the wall.
Version: `main`, local build at `target/debug/buzz-acp`.
Contributor guide
Research direction
Start with is_owner_control_command and event_mentions_agent in crates/buzz-acp/src/lib.rs:3073-3089, then inspect desktop/src/features/messages/lib/extractMentionPubkeys.ts and the related !shutdown and !cancel checks. Reproduce the Desktop message shape and trace the command path before choosing a fix. Done means an owner can invoke the channel-scoped control command from Desktop without breaking mention tagging, with the existing behavior preserved for other messages.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, desktop
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100