Skip to content
Automation
Skill

/mention-gate

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.

From plugin
sutando
41087 skills20 hooks

Claude Code

$ npx -y skills add sonichi/sutando --skill mention-gate --agent claude-code

SKILL.md

mention-gate.SKILL.md
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.

Mention Gate

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:

  • **ON** — an owner-tagged message from anyone but the owner counts as a bot

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.

  • **OFF (default)** — today's behavior, unchanged.

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.

Usage

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

State + audit

Scope: PER-HOST, not fleet-wide

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.

  • Gate state: `<workspace>/state/mention-gate.json` —

`{"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.

  • Audit log: `<workspace>/state/mention-gate-ingested.jsonl` — one fsync'd

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).

Architecture

  • **Policy owner (core):** `src/mention_gate.py` — `read_state` / `write_state`

/ `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.

  • **Discord adapter (wired):** `src/discord-bridge.py` —

`_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.

  • **ag2space/Matrix adapter (NOT wired — documented instead):** verified by

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

`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

Read more
@sonichi
Ships withsutando

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.

Stars on GitHub

Momentum

stars in total
410
Star history of sonichi/sutando on GitHub, a chart by star-history.com

Other skills on sutando.

ag2-space-mcp

ag2-space-mcp

Connect this Sutando install to AG2 Space's hosted MCP as its own agent, without the desktop app, and know which room and Commons…

@sonichi@sonichiInstall Skill
ag2space-voice

ag2space-voice

s.space voice surface — binds the room the s.space client announces to the voice session's origin, so work delegated by voice in…

@sonichi@sonichiInstall Skill
agent-activity

agent-activity

Streams what the agent is doing into the room, as rows the desktop client renders in an **events drawer** above the composer…

@sonichi@sonichiInstall Skill
agent-registry

agent-registry

Local Agent Registry — a standalone, dependency-free service that tracks running Claude Code (and other) agent instances. Agents…

@sonichi@sonichiInstall Skill
agent-room-ops

agent-room-ops

For an all-room analysis sweep, use the tested window collector and coverage contract in…

@sonichi@sonichiInstall Skill
answer-format

answer-format

Deterministic final-answer normalizer — a last-step pass for any task that ends in a *precise* answer (a number, a short string,…

@sonichi@sonichiInstall Skill

More skills from other plugins.

agent-builder

agent-builder

Load immediately after an Agent intent, before the first agent_builder_* call. Governs how you create, configure, test, and…

n8n2w209k
@n8n-io@n8n-ioInstall Skill
browser-use

browser-use

Direct browser control via CDP for web interaction: automation, scraping, testing, screenshots, and site/app work. Also covers…

@browser-use@browser-useInstall Skill
add-anydoc

add-anydoc

Add local office-document-to-Markdown conversion to NanoClaw agent containers with the pinned Firecrawl AnyDoc CLI. Use when…

@nanocoai@nanocoaiInstall Skill

Questions about mention-gate.

Which coding agents can use mention-gate?
mention-gate installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.