Moderation and auto-moderation
Node admins run the node from its administration page; flood detection, reports and content rules help rooms and the node against spam and abuse.
Node administration
Section titled “Node administration”The first account registered on a node becomes node admin (plus anyone listed in TAVRN_ADMIN_USERS). Node admins
get a “Node administration” page in the client: overview and effective configuration, users (disable, promote,
room-creation grants, delete all content, reset a locked-out user’s second factor), account invites for
TAVRN_REGISTRATION=invite, node-wide bans, other nodes with their conformance results (block, unblock, check),
entitlements, legal pages and notices, and the node audit log. Room moderation (kicks, bans, timeouts, roles and
permissions) is done by each room’s owners and moderators.
Room permissions are layered (protocol permissions.md): roles give the base, a category’s overrides apply to all
of its channels, and a channel’s own overrides win over the category’s. Overrides only hold channel-scoped
permissions; at start the node removes room-wide permissions from overrides created by older versions and records
each change in the room’s audit log (role.override_restricted). Nothing needs to be done by the operator.
Channel visibility
Section titled “Channel visibility”A channel that a member may not view (View channel after roles and overrides) does not exist for that member, and the node enforces this everywhere it sends data, not only in the client (protocol: PROTOCOL.md §6). Such a member does not get:
- the channel itself:
GET /api/v1/rooms/{id}leaves it and its overrides out, and a category without a visible channel is left out too (unless the member may manage channels); - its realtime events: messages, edits, reactions, pins, typing, threads, voice participants (
voice.state, also inGET /users/me/voice), whiteboard sessions and the channel’s own changes; - notifications about it: no unread or mention badges, no web push, and no
notifyhint to the member’s home node when the member is a user of another node; - its history, search results, files and encryption group.
When a change of roles, overrides or membership shows or hides a channel, the member’s clients get the channel (or its removal, marked as “hidden”, not deleted) with the next event, so nothing has to reload. A channel above a member’s age gate stays listed but locked (Age gates); a moderator’s move into a voice channel shows it for the time of the move (Moved members). Room moderators still see reports about hidden channels (Reports). With several instances each instance applies changes as their events arrive over the bus (Audit of the in-memory state).
Spam bursts
Section titled “Spam bursts”TAVRN_AUTOMOD_BURST_LIMIT (default 10): more than this many messages of one user in one room channel within 5
seconds count as a flood. The node deletes the burst (with its attachments), gives the user a room timeout of
TAVRN_AUTOMOD_TIMEOUT_MINUTES (default 10), alerts the room’s moderators and writes automod.spam to the room’s
audit log. Room owners, moderators (permission to moderate members) and node admins are exempt. 0 switches the
detection off. It works on message metadata only, so it applies to encrypted channels too.
Reports
Section titled “Reports”What the node does is specified in MODERATION.md.
Members report messages, members and rooms from the context menus. Reports about room content land in the room’s
“Reports” settings tab (moderators with moderate_members); reports about direct messages, about users without a
room, about rooms and about a room’s owner land in Admin → Reports, where node admins also see every room report.
Reporters are visible to moderators; the reported user is never told. For end-to-end encrypted messages the reporter
can release the plaintext of the reported message and up to ten messages before it: the inbox shows it labelled
“released by the reporter”, the node cannot verify it. Plaintext messages are linked and snapshotted instead. The
inbox offers shortcuts (delete the message, time out, kick, ban, delete the user’s content) that run the normal
moderation actions and note the report in the audit log. Every moderator of a room sees the room’s reports,
including those about channels hidden from them: moderation needs the context, and the reporter addressed the
room’s moderators as a whole (MODERATION.md §1.1). Give a private area that needs its own moderators its own room.
TAVRN_REPORTS_RATE_PER_HOUR (default 10) limits reports per user, TAVRN_REPORTS_RETENTION_DAYS (default 90)
deletes resolved and dismissed reports with their evidence; admins can delete a report at any time. Reports are
announced in the client (bell and toast) and, to moderators and admins who are not connected, by a web push that names
only the report’s kind and room (each user can turn it off: “Reports” in the notification settings).
Moderation bots can read a room’s reports: a bot whose token has the scope moderation and that holds “Moderate
members” in the room (give it a role with that permission) lists the room’s reports and receives new ones and changes,
for example to post a summary in a moderators’ channel or to escalate after several reports about one user. Bots
see metadata only: kind, category, the reported user, status, counts, times and the id of the reported message, never
the reporter’s text, the snapshot, released plaintext, your notes or actions, and the reporter only as a pseudonym
(the same for the same reporter in that room, never the address). Bots never see reports about themselves, their
owner, their owner’s other bots or the room’s owner, and they cannot report, change, act on, forward or delete reports: acting stays with people
(MODERATION.md §1.4a). Take the permission away to close the inbox for the bot.
Forwarding reports to another node
Section titled “Forwarding reports to another node”A report about a user of another node (a member from elsewhere in one of your rooms, or the author of a direct
message hosted elsewhere) lands with you, but only the admins of that user’s home node can act on the account. Node
admins can therefore forward such a report from Admin → Reports (“Forward to the user’s home node”, after a
confirmation); the home node must announce reports.v2 (current tavrn nodes with federation on do). Forwarding is a
federation message (report.forward, retried for three days like every federation message) and happens once per
report; the report stays in your inbox with “Forwarded to …” and you keep handling it as before.
What is forwarded: the category, the reporter’s text, the time, the message id, the snapshot of a plaintext message or the plaintext the reporter released for an encrypted one. What is not: the reporter’s address (the home node sees a pseudonym that stays the same for the same reporter, but cannot be linked across nodes), the addresses and devices of other people in the released messages (pseudonyms too), room names and ids, your notes and actions. The reporter and the reported user are told nothing. The text itself goes as it is: read it before you forward, since the other node’s admins, possibly the reported user themselves on a one-person node, will read it.
Forwarded reports from other nodes appear in Admin → Reports marked “Forwarded from …” with the pseudonym of the
reporter; they are node reports about your user and offer the account actions (node ban, delete the user’s content),
not the message actions (the content lives on the other node). Each original report arrives once; other nodes may
forward TAVRN_REPORTS_INBOUND_PER_HOUR (default 20) reports per hour per sending domain, five times as many from all
nodes together. Retention is the same as for every report (TAVRN_REPORTS_RETENTION_DAYS after closing; open reports
are kept), on each node independently: deleting a report on one node does not delete the other node’s copy, and an
erased account’s forwarded reports lose their target but keep the origin. Both directions are in the audit log
(report.forward, report.forwarded_in).
Content auto-moderation
Section titled “Content auto-moderation”Content rules only work where the node can read: unencrypted channels (never ciphertext). Rooms define their own
rules (room settings → Auto-moderation: word lists with * wildcards, link allow and block lists, exempt roles and
channels; actions block, delete or timeout), checked on send and edit, including attachment file names and bots’
interaction replies. Delete and timeout rules act only on members ranked below whoever last saved the rules (as that
member’s own moderation would), and a timeout is shown to the room like a moderator’s. Matching runs off the request
threads with a fixed amount of work per message; a message that would need more is refused. As operator
you can add node-wide lists that block in every unencrypted conversation: TAVRN_AUTOMOD_WORDS_FILE=/data/automod/words.txt
(one term per line, whole words, # comments) and TAVRN_AUTOMOD_LINKS=/data/automod/domains.txt (one domain per
line, subdomains included; off by default). Both files are read at start (at most 1 MiB and 10000 entries;
check-config names problems) and read again, without a restart, by the hourly housekeeping and when the node gets
SIGHUP (docker compose kill -s HUP tavrn; with several instances every instance reads its own copy, so signal
each one or wait for the hour). A reload validates both files like check-config: when one of them is invalid or
unreadable, the node keeps both previous lists and logs a warning naming the problem; otherwise it logs how many
terms and domains were added and removed (“Auto-moderation node lists reloaded”). Point the variables at a file, not
at a path that does not exist yet: the paths themselves are read from the configuration at start. Matches are
audited with the matched term, never the message text, and show up in the moderators’ inbox.
The welcome channel is the room’s security log: its entries cannot be deleted or purged by anyone. It never names a
channel that @everyone cannot view: when a bot joins or leaves the encryption group of such a channel, the entry is
written into that channel as a security notice instead (visible to the channel’s members only, never counted as
unread, protected like the welcome channel’s entries). Room ownership
moves with room settings → Overview → “Transfer ownership” (the owner confirms with their password or passkey);
accounts that own rooms must transfer or delete them before they can be deleted.
Audit logs
Section titled “Audit logs”Every room has an audit log (room settings → Audit log, for members with View audit log), and the node has one for
its admins (Node administration → Audit log, GET /api/v1/admin/audit-log). Entries name the action, who did it,
the target, a reason where one was given and details; they never contain message text, credentials or a date of
birth. Some of the actions they record:
| Audit log | Examples |
|---|---|
| Room | member.kick, member.ban, member.unban, member.timeout, moderation.purge, voice.move, voice.mute, room.update, room.legal, room.transfer, room.age_gate, channel.age_gate, invite.direct, automod.spam, automod.content, files.delete, files.backend, history.restore_requested, history.restore_approved, history.restore_denied, role.override_restricted, role.everyone_restricted |
| Node | user.register, user.second_factor_enroll, user.recovery_code_used, admin.user_disable, admin.user_delete, admin.second_factor_reset, admin.date_of_birth, admin.ban, admin.federation_block, federation.block_auto, federation.user_deleted, app.create, app.token_create, webhook.create, entitlements.grant_create, legal.*, retention.messages, directory.reports_notice, report.forward, report.forwarded_in |
Moderation shortcuts of the reports inbox add the report they act on (report_id). The node keeps audit entries as
long as the room (room log) or the node (node log) exists; deleted accounts stay in them pseudonymised (LEGAL.md).
History restore after a key reset
Section titled “History restore after a key reset”A user who resets their security key (lost every device and the recovery key) keeps their rooms but not their
encrypted history: the node stops serving the encrypted messages from before the reset to them, and other members’
apps no longer hand those keys over automatically (protocol: ENCRYPTION.md §7b). The member can ask the room for the
history; the owner, administrators and roles with Restore history (restore_history, never @everyone, never a
bot) approve or deny it in room settings → History requests. The approving member’s app sends the keys from its own
device, so an approval restores only what that device can read. Requests, approvals and denials are in the room’s
audit log (history.restore_requested, history.restore_approved, history.restore_denied with the reason) and the
decision is an entry in the welcome channel. Rooms switch requests off in room settings → Overview (“History after a
key reset”); remote members’ resets are learned through federation like the key change itself. There is nothing to
configure and nothing an operator can restore: the node never holds the keys. Decided requests are deleted after 30
days by the housekeeping; an approval stays valid for key shares for 30 days. Tell moderators to verify the person’s
identity on another channel before approving: a key reset is also what someone who took over the account would do.
This page is generated from tavrn-node/docs/HANDBOOK.md (AGPL-3.0-only) when the website is built; its links were adapted for this site.