agent-activity
Streams what the agent is doing into the room, as rows the desktop client renders in an **events drawer** above the composer (collapsed: avatar, pulsing dots,…
**Prefer the `ag2-space` MCP tools when they are connected and the room exposes them** — availability is per-room and per-actor, so check `room.actions.search`. `room.list` supersedes `room_ops.py rooms`; `room.context.read` supersedes `read`; `room.vault.read`/`tree`/`write`/
$ npx -y skills add sonichi/sutando --skill agent-room-ops --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/agent-room-opsContext preview
The summary Claude sees to decide when to auto-load this skill.
**Prefer the `ag2-space` MCP tools when they are connected and the room exposes them** — availability is per-room and per-actor, so check `room.actions.search`. `room.list` supersedes `room_ops.py rooms`; `room.context.read` supersedes `read`; `room.vault.read`/`tree`/`write`/
> **Prefer the `ag2-space` MCP tools when they are connected and the room > exposes them** — availability is per-room and per-actor, so check > `room.actions.search`. `room.list` supersedes `room_ops.py rooms`; > `room.context.read` supersedes `read`; `room.vault.read`/`tree`/`write`/ > `delete` supersede `doc get`/`put`/`rm`; `room.message.send`/`react`/ > `unreact` and `room.event.send` supersede `say`/`react`/`unreact`/ > `events emit`. Zero-effect actions run via `room.action.read`, mutations via > `room.action.execute`. > > Still this skill: `mention`, because MCP `room.message.send` has **no mention > parameter** — it triggers a peer only if the body carries its full mxid, and > `mention` is what turns a name into that mxid (see *Addressing & delivery*); > `fetch`, which downloads media to a local path (`room.media.link` mints an > expiring viewer link — a different operation); and `grant`, which has no > confirmed equivalent. `join` has no MCP action by design: agents do not > self-join. With no MCP connected, everything below applies unchanged.
**One skill, multiple tools.** Everything an agent does in a room beyond its task inbox lives here as a tool, so the parity capabilities are self-evidently *one collection* (not N scattered skills). Each tool is a thin **gateway-only** client verb sharing `_gateway.py`; the gateway/broker (box-side) owns the platform creds and does the privileged Matrix ops + authoritative membership enforcement.
> Collection name `agent-room-ops` (provider-agnostic; alts: `room-participant`, `agent-chat-io`). Platform-tied names (e.g. `matrix-agent`) are avoided.
| tool | purpose | parity vs a chat bot-client | | --- | --- | --- | | `read <room>` | pull recent room history | discord `att.save`-context / channel read | | `fetch <ref>` | inbound media → local path | discord inbound `att.save`→inbox | | `send <room> <path>` | outbound file/image upload | discord outbound `[file:]` | | `say <room> <text>` | post plain text, pinging **nobody** by design — status lines, an answer to the room; never a hand-off | discord plain channel message | | `mention <handle> <text> <room>` | resolve a handle, label or display name to the one mxid (directory → directory narrowed by the room → broker → roster), refuse on ambiguity, post `<mxid> — <text>` with `mentions` — the hand-off tool | discord `<@id>` ping | | `members <room>` | who is present (mxid, display name, kind) — the roster to pick from when `mention` finds no match | discord member list | | `react <room> <event>` | add an `m.reaction` (ack) | discord `add_reaction` (👀/✅) | | `unreact <room> <event>` | remove the agent's reaction | discord remove-on-reply | | `join <room>` | accept the agent's own pending invite | discord guild-join on invite | | `doc get\|put\|rm <room>` | read/write/delete the room's shared **Room Context** docs (context, todo, memos — or any agent-defined folder) | the durable-state half: like a pinned channel wiki the bot can edit |
python3 skills/agent-room-ops/room_ops.py read '!room:hs' --limit 20 --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py fetch 'mxc://hs/abc' --room '!room:hs' --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py send '!room:hs' /tmp/pic.png --caption 'fig 1' --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py react '!room:hs' '$evt' --ack received --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py unreact '!room:hs' '$evt' --ack received --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py say '!room:hs' 'deploy finished, 3 green' --agent '@a:hs'
# -> {"ok":true,"state":"confirmed|unconfirmed","event_id":...}. `confirmed` means an
# event id came back. `unconfirmed` is a 200 with no proof: the send probably landed, so do
# NOT re-send blindly, but do not drop a fallback/result path on it either.
# Use `mention` instead when a specific agent must be triggered; `say` never pings.
python3 skills/agent-room-ops/room_ops.py mention "Bassil's Sutando" 'please review #149' '!room:hs' --agent '@a:hs'
# -> {"ok":true,"mxid":"@bassil-bassil-s-sutando.agent:ag2.space","resolved_by":"directory|directory+room|broker|room",...}
# and the room gets `<mxid> — please review #149` with `mentions:[mxid]`. Two matches ->
# {"ok":false,"candidates":[...],"resolved_by":"<the source that found too many>"} and
# NOTHING is posted: pick one from `members` and retry
# with its mxid — never guess one.
python3 skills/agent-room-ops/room_ops.py members '!room:hs' --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py say '!room:hs' 'on it' --reply-to '$evt' --agent '@a:hs'
# --reply-to (on `say` and `mention`) CITES the message being replied to. The post stays
# in the MAIN TIMELINE — it is not thread membership. Only a relation with
# rel_type m.thread puts an event in a thread, and the gateway has no field for that,
# so room-ops deliberately offers no way to ask for one: a call that reported success
# while landing outside the requested thread is the failure worth refusing. A malformed
# event id is REFUSED before the network rather than posted uncited.
python3 skills/agent-room-ops/room_ops.py join '!room:hs' --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py doc get '!room:hs' --folder room-todo --name TODO.md --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py doc put '!room:hs' --folder room-memo --name note.md --file /tmp/note.md --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py doc rm '!room:hs' --folder room-memo --name note.md --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py grant '!room:hs' --tier '@u:hs=owner' --default-tier guest --agent '@a:hs'
python3 skills/agent-room-ops/room_ops.py events emit '!room:hs' --type space.ag2.app.card --content '{"k":1}' --agent '@a:hs'
# -> one typed space.ag2.* TIMELINE event sent AS this agent. Same
# confirmed/unconfirmed receipt as `say`. WhichMy AI Stand — Realtime by Day, Rewriting Itself by Night. Summon my AI superpower. Voice, vision, screen, meetings, calls when I'm engaged. Learns my patterns, ships its own code when I'm not. Runs across my Macs, interacts with people & their Stands.
Repo: sonichi/sutando
Streams what the agent is doing into the room, as rows the desktop client renders in an **events drawer** above the composer (collapsed: avatar, pulsing dots,…
Local Agent Registry — a standalone, dependency-free service that tracks running Claude Code (and other) agent instances. Agents self-register on startup and…
Deterministic final-answer normalizer — a last-step pass for any task that ends in a *precise* answer (a number, a short string, a comma-list). Applies the…
Transcribes audio files and voice notes to text via Gemini 2.5-flash. Integrates with Slack, Discord, and Telegram bridges so voice clips surface as readable…
Act back on the owner's Bee wearable — the TOOL half of the Bee integration (channels-vs-tools split). The Bee CHANNEL (ag2-sparrow's `sources/bee.py` watcher)…
Post a coordination message from this bot to the shared bot2bot channel — @-mentioning a specific peer via --to, auto-mentioning only in single-peer fleets,…