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,…
Turn on/off whether a message that @-tags the OWNER counts as a mention of the bot. Off (default) is today's behavior — in requireMention channels such messages never reach the fleet. On, they are ingested as tasks and audit-logged. Free-listen channels are unaffected either way.
$ npx -y skills add sonichi/sutando --skill mention-gate --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/mention-gateContext preview
The summary Claude sees to decide when to auto-load this skill.
Turn on/off whether a message that @-tags the OWNER counts as a mention of the bot. Off (default) is today's behavior — in requireMention channels such messages never reach the fleet. On, they are ingested as tasks and audit-logged. Free-listen channels are unaffected either way.
name: mention-gate description: Turn on/off whether a message that @-tags the OWNER counts as a mention of the bot. Off (default) is today's behavior — in requireMention channels such messages never reach the fleet. On, they are ingested as tasks and audit-logged. Free-listen channels are unaffected either way.
Today, in every requireMention channel, a message @-tagging the owner (but not the bot) is never ingested — it stays invisible to the fleet. This skill adds the missing ON side:
mention: it passes the requireMention check and becomes a task. Every message pulled in this way is appended to a durable audit log so the owner can review exactly what the toggle admitted.
Never affected: messages from the owner himself (they follow the existing rules), messages that actually mention the bot (ingested in both states, as always), and `requireMention:false` channels (everything there already ingests, gate on or off). Later access gates (channel allowFrom, tier resolution) still apply to an admitted message — the gate substitutes only the missing bot-mention, nothing else.
**Fail-closed:** the feature ADDS ingestion, so every failure reads as OFF — missing or malformed state, an unparseable `until`, or any exception inside the bridge's gate check leaves the ordinary requireMention rejection standing. A broken state file must never surprise-ingest.
python3 skills/mention-gate/scripts/mention-gate.py on # owner tags trigger ingestion python3 skills/mention-gate/scripts/mention-gate.py on --for 2h # with auto-expiry back to off (30m/2h/1d) python3 skills/mention-gate/scripts/mention-gate.py off # today's behavior (default) python3 skills/mention-gate/scripts/mention-gate.py status # state + how many messages pulled in
The gate is stored under `<workspace>/state/`, which `vault.sync.exclude` lists explicitly — the vault runs in whitelist mode and carries only `notes/`, `talks/`, `hosts/` and the memory tree. `git ls-files state/mention-gate.json` returns nothing on a live host. So **toggling the gate changes only the host it was run on**; every other host keeps its own setting. Run the command once per host. There is currently no synced fleet-policy surface to store it on.
`{"mentions_enabled": bool, "until": "<ISO-8601>"|null}` (`mentions_enabled` = this gate is on), written atomically (temp sibling + `os.replace`). `until` auto-expiry needs no follow-up write: once passed, the gate reads OFF.
JSON line per admitted message `{ts, channel_id, author_id, message_id, body (first 120 chars)}`. `status` reports the count. The row is appended only AFTER the admitted task file is durably written — a sender the later authorization gates (channel allowFrom, global allowlist) reject leaves no audit row, so an unauthorized sender can never inflate the audit (#3473).
/ `owner_tag_triggers_ingest` (fail-closed) / `message_tags_owner(mention_ids, text, owner_ids)` / `log_gated_ingest` / `gated_ingest_count`. Owner ids are parameters; the module hardcodes none.
`_mention_gate_triggers_ingest(message)`, consulted inside `_handle_discord_message` at the requireMention rejection site (the `require_mention and not bot_mentioned and not role_mentioned` branch): when it returns True the rejection is bypassed and the message continues down the existing pipeline; otherwise (including on any error) the ordinary skip stands. The helper returns a verdict only; the audit row is written by `_mention_gate_log_admission` right after `_write_task_file` succeeds. Owner-tagging is detected from the platform `message.mentions` array plus a `<@ID>`/`<@!ID>` text fallback. Owner ids come from `access.json`: a PRESENT `tierMap` is authoritative — only its explicit `owner` entries count, and an empty map means no owners (the gate never triggers); `allowFrom` is consulted only when the `tierMap` key is absent (legacy file), so read-only members are never promoted to owner for this gate.
reading the code: gateway messages become task files inside `_write_task` in `packages/ag2-sparrow/ag2_sparrow/remote_gateway_bridge.py`, which is package-canonical (PyPI-published, intentionally divergent from `src/`; the `src/remote-gateway-bridge.py` loader only injects dirs/seams and execs it — no per-message ingest passes through repo-level code first). The broker also makes the mention-match decision (`is_mention`) server-side, so wiring here would fork the vendored contract. Where the trigger belongs: an injectable ingest-trigger seam in the package (mirroring `local_task_protocol.set_task_stamper`), consulted where `_write_task`'s callers decide whether a room message is for this agent; the loader would bind it to `mention_gate.owner_tag_triggers_ingest` + `message_tags_owner` with the workspace it already resolves and the owner mxid from its channel config. Until that package change lands, the gate has no effect on ag2space/Matrix rooms.
`tests/mention-gate.test.py` — fail-closed state contract (default/missing and malformed state read OFF, unparseable `until` reads OFF, atomic write), tagging detection (mentions array + text fallback), injected-now expiry flipping ON→OFF, audit-log order + count, owner-id resolution controls (an explicitly empty tierMap yields no owners and the gate never triggers; a present tierMap beats all
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
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…
**Prefer the `ag2-space` MCP tools when they are connected and the room exposes them** — availability is per-room and per-actor, so check…
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)…