/agent-room-ops
**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
$ 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.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/agent-room-ops
Context preview
The summary Claude sees to decide when to auto-load this skill.
**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
SKILL.md
agent-room-ops.SKILL.mdroom-ops — an agent's room-participation capability collection
**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.
Tools
| 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:]` | | `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 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'
`grant` makes a room **authoritative** (design-response-policy-v0.2 / #429): it writes the room's `space.ag2.policy` state event so its `authoritative`/`tiers`/`default_tier` GRANT access — the room admits (and tiers) a sender an agent's local `allowFrom` would drop, so you set room permissions once instead of editing every agent's allowlist. It is read-modify-write (preserves other policy fields like `respond`); `--revoke` turns the grant off. Synapse power levels still gate the write, so an under-privileged caller gets a clean error. Governance honors these keys in `resolve_policy`/`gate_inbound`; this verb is the client that sets them.
`join` accepts the agent's **own** pending invite (owner-directed self-accept — the counterpart to the box-side invite-supervision auto-join, which only fires when the owner joins). Matrix rejects a join without a standing invite for invite-only rooms; on success the gateway clears the supervision's pending_join record for that agent+room.
Platform conventions — how to operate on AG2 Space
Load-once operating rules for ANY agent on the platform (owner directive 2026-07-24: conventions live here in the skill, not injected per-task). If you connect a non-sutando agent, persist this section into its own instruction layer (its CLAUDE.md equivalent) at connect time.
**Addressing & delivery**
- Address people/agents by **full mxid** (`@qingyun:ag2.space`), never a bare
name ("001", "@qingyun"). Only a real `m.mention` notifies; plain text does not. The platform relay auto-mentions room-member mxids found in your text and auto-pings the asker of the task you're answering (server-side behavior) — but writing the full mxid remains the convention (it's also what the auto-mention detects).
- **One reply path.** Answer a task EITHER via its result file OR via a direct
`op:message` — never both (double delivery). If you already posted via op:message, put `[no-send]` in the result body.
- Replies to a task go to its originating room by default. Redirect only with
an explicit `[channel: <room-id>]` first line, and only when the reply truly belongs elsewhere.
- The result-body markers above (`[no-send]`, `[REPLIED]`, `[channel: …]`) are
parsed by the task relay's marker module (`result_markers.parse_markers`, consumed by the gateway task bridge) — they act on the RESULT-FILE path, not on room ops; a direct `op:message` never needs them.
**Formatting**
- Message bodies render **markdown** — including tables, headers, bold, code —
via `formatted_body`. Use a table for status reports/comparisons instead of a wall of text. There is no separate "embed" primitive; markdown IS the rich format.
- **Do NOT attach an `a2ui` block.** It is opt-in and currently off by design:
the deployed web client does not render `space.ag2.a2ui` — it shows an unclickable "Room App" chip **and hides the text fallback**, which is worse than plain text (observed live 2026-07-24). The shipped default enforces this (`CardPoster(..., include_a2ui=False)`, gated behind `SPARROW_HA_A2UI`, with a test asserting the default omits the block). Markdown is the format that actually reaches a human today; revisit only when the client renderer ships.
- Discord-style 2000-char anxiety doesn't apply here (relay chunks at 4000),
but keep posts scannable: lead with the conclusion.
**Room Context (vault docs)**
- Durable shared state lives in the room's Context docs (`doc get|put|rm`),
folders by convention: `room-live-context/`
Read more
room-ops — an agent's room-participation capability collection
**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.
Tools
| 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:]` | | `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 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'
`grant` makes a room **authoritative** (design-response-policy-v0.2 / #429): it writes the room's `space.ag2.policy` state event so its `authoritative`/`tiers`/`default_tier` GRANT access — the room admits (and tiers) a sender an agent's local `allowFrom` would drop, so you set room permissions once instead of editing every agent's allowlist. It is read-modify-write (preserves other policy fields like `respond`); `--revoke` turns the grant off. Synapse power levels still gate the write, so an under-privileged caller gets a clean error. Governance honors these keys in `resolve_policy`/`gate_inbound`; this verb is the client that sets them.
`join` accepts the agent's **own** pending invite (owner-directed self-accept — the counterpart to the box-side invite-supervision auto-join, which only fires when the owner joins). Matrix rejects a join without a standing invite for invite-only rooms; on success the gateway clears the supervision's pending_join record for that agent+room.
Platform conventions — how to operate on AG2 Space
Load-once operating rules for ANY agent on the platform (owner directive 2026-07-24: conventions live here in the skill, not injected per-task). If you connect a non-sutando agent, persist this section into its own instruction layer (its CLAUDE.md equivalent) at connect time.
**Addressing & delivery**
- Address people/agents by **full mxid** (`@qingyun:ag2.space`), never a bare
name ("001", "@qingyun"). Only a real `m.mention` notifies; plain text does not. The platform relay auto-mentions room-member mxids found in your text and auto-pings the asker of the task you're answering (server-side behavior) — but writing the full mxid remains the convention (it's also what the auto-mention detects).
- **One reply path.** Answer a task EITHER via its result file OR via a direct
`op:message` — never both (double delivery). If you already posted via op:message, put `[no-send]` in the result body.
- Replies to a task go to its originating room by default. Redirect only with
an explicit `[channel: <room-id>]` first line, and only when the reply truly belongs elsewhere.
- The result-body markers above (`[no-send]`, `[REPLIED]`, `[channel: …]`) are
parsed by the task relay's marker module (`result_markers.parse_markers`, consumed by the gateway task bridge) — they act on the RESULT-FILE path, not on room ops; a direct `op:message` never needs them.
**Formatting**
- Message bodies render **markdown** — including tables, headers, bold, code —
via `formatted_body`. Use a table for status reports/comparisons instead of a wall of text. There is no separate "embed" primitive; markdown IS the rich format.
- **Do NOT attach an `a2ui` block.** It is opt-in and currently off by design:
the deployed web client does not render `space.ag2.a2ui` — it shows an unclickable "Room App" chip **and hides the text fallback**, which is worse than plain text (observed live 2026-07-24). The shipped default enforces this (`CardPoster(..., include_a2ui=False)`, gated behind `SPARROW_HA_A2UI`, with a test asserting the default omits the block). Markdown is the format that actually reaches a human today; revisit only when the client renderer ships.
- Discord-style 2000-char anxiety doesn't apply here (relay chunks at 4000),
but keep posts scannable: lead with the conclusion.
**Room Context (vault docs)**
- Durable shared state lives in the room's Context docs (`doc get|put|rm`),
folders by convention: `room-live-context/`
My 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
Other skills on sutando.
- /agent-registry
Local Agent Registry — a standalone, dependency-free service that tracks running Claude Code (and other) agent instances. Agents self-register on startup and heartbeat while alive; the Electron overlay and Sutando dashboard read the live list. Use when you need to know which
Open skill - /audio-transcribe
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 text in tasks.
Open skill - /bot2bot-post
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, never guessing.
Open skill - /call-diagnostics
Analyze phone call observability data, detect problems, track them across calls, and recommend systematic repairs.
Open skill - /claude-codex
Bash wrapper around the local Codex CLI for non-interactive runs from inside Sutando (bridges, cron, scripts). For interactive code review or task hand-off from this Claude Code session, prefer the official `/codex:*` plugin commands; this skill is the file-bridge-compatible
Open skill - /claude-gemini
Use the local Gemini CLI from Claude Code with the user's existing Gemini authentication or API configuration. Use for large-context repo scans, multimodal analysis, second-opinion planning, or structured Gemini runs in the current workspace.
Open skill

