Zvessa docs

Moderation and safety (the Safety engine)

What the app stores ask for wherever people post: a way to report content and people, a way to block people, a filter for objectionable words, and someone who acts on reports. In Zvessa all of it is general pieces (settings, blocks and tools) that people and any AI combine.

Always on, in every space and direct chat #

Settings: blueprint.safety #

KeyWhatDefault
wordsWords and phrases to catch. word = whole word, word* = any word starting with it, f*ck = any letter in the starnone
presetsReady lists: basic (strong swearing), insultsnone
links, contactsCatch links; catch phone numbers and emailsoff
actionmask (f•••), hold (waits in the review queue), refusemask
reasonsWhat people pick when reportingSpam, Harassment or bullying, Hate, Sexual content, Violence or threats, Self-harm, Scam or fraud, Someone's private info, Something else
escalateReasons that also reach Zvessa's adminsSexual content, Violence or threats, Self-harm
modRolesRoles that moderateroles with manage
autoHideHide a post or record once this many people reported it (0 never)0
notifyPush to moderators when a new case openson
whomembers or anyone may reportmembers

The filter undoes look-alikes (sh1t, $hit), squeezes repeats (fuuuck), ignores accents, and only matches whole words (so "Scunthorpe" and "class" pass). It runs on the server on chat posts and edits, feed posts, titles and edits, and records' text fields (records can't wait, so held words are refused there). Direct chats have no moderator: nothing is filtered unless a kid is in it, and then held words are refused.

Kids spaces never go below: basic + insults, links and contacts caught, hold, autoHide 1, every reason escalated, only members report.

People who can't post #

Blocks #

safety.queue (moderators' review queue; quiet: true shows nothing while empty, used in HQ), safety.filters (settings editor with a try-it box), safety.blocked (my blocked people), safety.report (a Report button for the space, a person, a post or a record), safety.block (a Block button for a person), safety.admin (Zvessa's admins only; pair with miniapps.review). Words: words["safety.<key>"] (convex/lib/safety/words.ts).

The Moderation kit (moderation) adds a Safety page (queue, filter, blocked list) and turns on presets: ["basic"], action: "mask", autoHide: 3.

Moderator actions #

dismiss, hide, show (also lets a held post through), remove (records), warn (push with a note), mute, ban, unban, escalate (to admins); admins also suspend, unsuspend, lock, unlock. Every action closes the target's open reports and is written to the space's log.

Functions (api.kits.safety.safety) #

Anyone: report, block, unblock, blocked, isBlocked, me (suspended, locked, reasons, isMod, isAdmin, recent warnings), tryFilter. Moderators: queue, waiting (a count for a badge), act. Managers: settings, setSettings (saves a version; undo from History). Admins: admin, act with asAdmin.

MCP and the in-app AI #

ToolScopeWhat
list_reportsreadThe review queue (moderators). Members' words come back marked as data
check_textreadWhat the filter would do to some words
act_on_reportmoderate (new)Any action above, as the token's person
reportdata.writeReport as the token's person
block_persondata.writeBlock or unblock as the token's person
list_blockedreadThe token's person's blocked list
safety_adminmoderateThe admin view (admins only)

The in-app AI can read the queue and try the filter, and proposes /safety changes like any other change. Moderating is always a person's decision: in the app, or with their own MCP token.

Tables (convex/kits/safety/tables.ts) #

reports (one per person per thing; the filter files held posts as reports by their writer with the reason "Caught by the filter"), userBlocks, safetyHolds (mute, ban, suspend, lock; optional until), safetyLog.

Adding a new kind of reportable thing: one entry in TARGET_KINDS/ACTIONS_FOR (convex/lib/safety/model.ts) and one loader in convex/kits/safety/targets.ts.