Skip to main content

Permissions (bit positions, normative)

Permissions are a 64-bit mask, transported over the API as a decimal string. Bit positions are never reassigned; new permissions get new positions. Reference implementations: permissions.rs in tavrn-node (Rust) and permissions.ts in @tavrn/sdk (tavrn-js, TypeScript); both must pass testvectors/permissions.json.

BitNameMeaning
0view_channelSee the channel and read its history. Without it no other permission applies in the channel.
1send_messagesSend messages
2manage_messagesDelete other people’s messages, bypass slowmode
3attach_filesAttach files
4add_reactionsAdd reactions
5mention_everyoneMention @everyone and @here
6create_threadsStart threads and write in them (text and announcement channels; forum posts need send_messages only, PROTOCOL.md §7e)
7manage_channelsCreate, edit and delete channels and categories (including the encryption switch)
8manage_rolesManage roles and overrides (only below your own highest role, only permissions you hold)
9manage_roomRoom settings, invites
10create_invitesCreate invite links
11kick_membersRemove members
12ban_membersBan members and domains
13moderate_membersTimeouts; receives auto-moderation alerts
14purgeBulk deletion (time range, author, channel history)
15view_audit_logRead the audit log
16connectJoin a voice channel
17speakSpeak
18streamShare screen or window
19mute_membersMute others
20move_membersMove others between voice channels, also into channels they may not view or connect to (they see the channel while connected)
21use_soundboardUse the soundboard
22manage_emojisManage custom emojis and sounds
23change_nicknameChange own nickname
24manage_nicknamesChange other people’s nicknames
25pin_messagesPin messages
26use_cameraShare the camera
27use_whiteboardOpen a whiteboard in the channel (voice channels also need connect); viewing a board only needs read access
28manage_whiteboardClose any whiteboard and change who may edit someone else’s board
29manage_webhooksManage the channel’s webhooks (APPLICATIONS.md §6)
30priority_speakerMay activate priority speaking in voice channels (others are ducked while they hold the key, design note 4.13)
31use_external_emojisUse custom emojis of other rooms and personal emojis in this room (default for @everyone, design note 4.13)
32use_external_soundsPlay soundboard clips of other rooms and personal clips in this room (default for @everyone, design note 4.13)
33manage_filesFiles channels: rename, move and delete entries of others (own entries need attach_files, which also uploads and creates folders), configure the storage backend together with manage_channels (design note 4.13, FILES.md)
34read_historyEncrypted channels: read messages from before joining as far as the channel’s history_for_new_members policy allows, and receive their keys from other members (default for @everyone, design note 4.13 item 11, ENCRYPTION.md §7b). Without it the history starts at the member’s join. Plaintext messages are not affected.
35manage_applicationsInstall and remove applications (bots) in the room and edit the room’s command settings (APPLICATIONS.md §4.2, §4.3, §5.3). The managed role of an installation additionally needs manage_roles, and the bot never gets more than the installer holds. Covered by the app token scope rooms:manage; bots still cannot install bots.
36manage_threadsRename, archive, lock and delete other people’s threads and edit the tags of any forum post (PROTOCOL.md §7e). Covered by the app token scope moderation.
37restore_historyEncrypted channels: decide about requests to restore a member’s history after a key reset and send the keys from before the reset (ENCRYPTION.md §7b “History after a key reset”). Default: nobody besides the owner and administrator; no app-token scope covers it.
38voice_statusSet or clear the status text of a voice channel (VOICE.md §2a) at any time, through the channel update route without manage_channels. Channel-scoped, grantable alone; granted once to every role that held manage_channels when it was introduced (marker fixup.voice_status). Covered by the app token scope rooms:manage.
39create_pollsSend polls (PROTOCOL.md §7g) together with send_messages: plaintext content of type poll and any message with a close time (poll_closes_at); clients enforce it for encrypted polls, whose type the node cannot see. Voting needs only view_channel. Channel-scoped, grantable alone; default for @everyone; granted once to every role and override that allowed send_messages when it was introduced (marker fixup.create_polls). Covered by the app token scope messages:write.
40use_componentsUse the buttons, select menus and modals of applications’ messages (APPLICATIONS.md §5.10): clicking, selecting and submitting create interactions. Channel-scoped, grantable alone, independent of send_messages (a read-only announcement channel can still carry a sign-up button). Default for @everyone; granted once to every role holding send_messages when it was introduced (marker fixup.use_components). No app-token scope covers it: bots never use components.
62administratorAll permissions, overrides are ignored

Default permissions of @everyone in new rooms: view_channel, send_messages, attach_files, add_reactions, create_threads, create_invites, connect, speak, stream, use_camera, use_soundboard, change_nickname, use_whiteboard, use_external_emojis, use_external_sounds, read_history, create_polls, use_components. Migration 0060 added use_whiteboard to the @everyone role of every existing room, so boards keep working where they did; read_history is added once to the @everyone role of every room that existed before it (startup fixup, recorded in node_settings so a later removal by the room is kept). manage_applications (bit 35) replaced manage_room as the right to install applications: a startup fixup grants it once to every role that held manage_room when the bit was introduced (marker fixup.manage_applications), so nobody loses the ability; rooms may narrow it afterwards. manage_threads (bit 36) is granted the same way once to every role that held manage_messages when it was introduced (marker fixup.manage_threads), so moderators keep moderating threads. voice_status (bit 38) is granted once to every role that held manage_channels when it was introduced (marker fixup.voice_status); rooms may hand it to other roles alone (a channel override can grant it too), so people in a voice channel can keep its status current. create_polls (bit 39) is granted once to every role holding send_messages (@everyone included) and added to the allow mask of every override that allows send_messages when it was introduced (marker fixup.create_polls), so whoever could write a message can still send a poll; rooms narrow it afterwards. use_components (bit 40) is granted once to every role holding send_messages (@everyone included; overrides are not touched) when it was introduced (marker fixup.use_components), so everybody who could use commands can use the buttons of their answers.

change_nickname covers the whole per-room profile (nickname, avatar and bio in that room, PROTOCOL.md §6b); manage_nicknames lets moderators change or reset the per-room profiles of members below them.

The welcome channel (kind = "system", system_name = "welcome") is the room’s security log (PROTOCOL.md §7). It is visible and read-only for every member, owners and administrators included. After the evaluation below (the input flag system_channel):

  • SYSTEM_CHANNEL_FORCED = view_channel | read_history is added: no override (on the channel or its category, for @everyone, a role or the member), no missing room-level bit and no timeout can hide the channel or its history;
  • SYSTEM_CHANNEL_DENIED = send_messages | attach_files | create_threads | mention_everyone | pin_messages | use_whiteboard | create_polls is removed;
  • then the bot branch applies as everywhere (a bot in a “no bots” zone still has nothing).

The room cannot switch the channel off (the former setting welcome_channel_enabled is gone); reactions follow the normal bits. Its entries cannot be deleted by anyone, manage_messages, owners and node admins included (MODERATION.md §3). The shared test vectors (testvectors/permissions.json) cover the forced and the denied bits.

Which kinds of files a member may attach is a per-role setting, not a permission bit (PROTOCOL.md §7a): roles carry allowed_upload_categories (null = not set), overrides carry upload_allow / upload_deny. Evaluation: the member’s highest role (by position) with a value decides, else @everyone; then the same layers as below (the category’s overrides, then the channel’s own on top), each in the same order (@everyone override, all role overrides deny-then-allow, the member override); an upload category that a layer neither allows nor denies keeps the value of the layer below. Owners, node admins and administrator may upload every category; executables additionally need the node setting.

Management-class permissions can never be granted to @everyone, neither in the role itself nor through an @everyone override (allow) on a category or channel (design note 4.11). Nodes refuse such updates with 400 role.everyone_restricted; clients grey the bits out for @everyone and explain why. Reference constant: EVERYONE_RESTRICTED in @tavrn/sdk.

BitName
2manage_messages
7manage_channels
8manage_roles
9manage_room
11kick_members
12ban_members
13moderate_members
14purge
15view_audit_log
19mute_members
20move_members
22manage_emojis (emojis and soundboard sounds)
24manage_nicknames
28manage_whiteboard
29manage_webhooks
33manage_files
35manage_applications
36manage_threads
37restore_history
62administrator

New management-class bits are added to this list when they are introduced. Denying any of them to @everyone stays allowed. The same constant lives in the node (tavrn-node, value 4611686268363406212).

Nodes remove these bits from existing @everyone roles and @everyone overrides at start (idempotent) and record every removal in the room’s audit log as role.everyone_restricted (meta: kind role|override, removed, names).

Overrides (on categories and on channels) may only carry bits that mean something inside a channel. A PUT /rooms/{room_id}/overrides whose allow or deny contains another bit is refused with 400 permissions.not_channel_scoped (meta.names: the refused bit names); room-level bits are granted through roles only. Reference constant: CHANNEL_SCOPED in the node (tavrn-node) and in @tavrn/sdk, value 2027195138559. Clients list only these bits in override editors.

BitName
0view_channel
1send_messages
2manage_messages
3attach_files
4add_reactions
5mention_everyone
6create_threads
7manage_channels
8manage_roles
16connect
17speak
18stream
19mute_members
20move_members
21use_soundboard
25pin_messages
26use_camera
27use_whiteboard
28manage_whiteboard
29manage_webhooks
30priority_speaker
31use_external_emojis
32use_external_sounds
33manage_files
34read_history
36manage_threads
38voice_status
39create_polls
40use_components

Room-level only (roles, never overrides): administrator, manage_room, create_invites, kick_members, ban_members, moderate_members, purge, view_audit_log, manage_emojis, change_nickname, manage_nicknames, manage_applications, restore_history (bit 37: a decision about a member’s history in the room’s encrypted channels, not a right inside one channel). New bits state whether they are channel-scoped when they are introduced. The @everyone restriction above applies to overrides as well: a channel-scoped bit in EVERYONE_RESTRICTED still cannot be allowed for @everyone.

Nodes remove bits outside CHANNEL_SCOPED from the allow and deny masks of existing overrides at start (idempotent; an override left with nothing is deleted) and record every change in the room’s audit log as role.override_restricted (target: the category or channel id; meta: target_type, subject_type, subject_id, removed, names).

The evaluation is layered (it replaced the earlier “synced with its category” rule, see “Changes” below): role base → category overrides → channel overrides.

  1. base = everyone | OR(member's roles). Owner, node admin or administrator → all permissions, done.
  2. Category layer: if the channel belongs to a category, the category’s overrides apply to base.
  3. Channel layer: the channel’s own overrides apply to the result of step 2. Order inside each layer: @everyone override (deny, then allow) → all role overrides of the member (all denies first, then all allows, each unioned) → member override (deny, then allow). Only the bits of CHANNEL_SCOPED (below) of an override take part; other bits in stored data are ignored. A bit that an override neither allows nor denies (the neutral state ”–”) inherits the value of the layer below: a channel override always wins over the category, which wins over the role base.
  4. If view_channel is missing afterwards, the result is 0.
  5. Members in timeout keep only view_channel and read_history (a timeout limits writing, not reading). Typing notices need send_messages; ephemeral events (cursors, whiteboard strokes) are refused in a timeout (403 member.timed_out, WHITEBOARD.md §2.1).

Age gates (PROTOCOL.md §5e) come before this evaluation: in a channel whose effective age_gate is adults_only, a member below it (a minor or a user of unknown age) has 0, owners and node admins included. The gate is not an input of testvectors/permissions.json; implementations apply it around the evaluation.

Moved participations (VOICE.md §7): in the voice channel into which a moderator moved a member, from the move until the moved participation ends, view_channel, read_history and connect are added after step 3 (before step 4), whatever the overrides deny. Steps 4 and 5, the bot cap and the age gate apply as usual, so a timeout still leaves only reading. Like the age gate this is node state, not an input of the test vectors.

Example: the @everyone role lacks view_channel, the category has no override for it (”–”), and the channel allows view_channel for @everyone: every member sees that channel. A category is a container, not a permission target for viewing: clients show it as soon as at least one of its channels is visible. A category that allows view_channel and a channel in it that denies it: the channel is hidden. The shared test vectors cover these cases (“Layered: …”).

Moving channels. A channel that leaves its category (the category is deleted, or the channel moves to another category or to none) would lose the category layer. The node first writes the category’s overrides into the channel’s own: per subject, a bit the channel’s override sets stays, a bit it leaves neutral takes the category’s value; a bit the channel’s @everyone override decides is decided for everybody in the channel layer and is not copied. One layer cannot express every pair of layers (a category allow for one role and a channel deny for another role a member also holds: in one layer the allow would win), so a member who would still gain a permission gets a member override denying it. Nothing becomes visible or allowed that was not; the result may be narrower. Audited as channel.overrides_copied ({ category_id, to, overrides, members_denied }), announced as override.update. Moving a channel without a category into one applies the category’s overrides underneath the channel’s from then on; when that grants anybody more than before, the actor needs manage_roles in that category (403 role.manage_forbidden), as for setting those overrides.

Hierarchy: roles have a position (@everyone = 0). Members can only manage or assign roles below their own highest position, only grant permissions they hold themselves, and only kick, ban or time out members whose highest role is lower. Owners outrank everything, node admins as well. “Grant” covers every way of handing out bits: creating or editing a role, assigning a role (to another member or to oneself; a role the member already holds may stay in the list) — 403 role.escalation when the role carries a bit the actor lacks — and overrides, where the actor may neither allow nor deny a bit they do not hold where the override applies, nor allow or deny an upload category they cannot use there (403 override.escalation).

The evaluation input carries three more fields: kind (the account kind, default user), no_bots (the channel’s effective “no bots” flag, see below) and scopes (the effective scopes of the bot’s token; absent = all scopes). For every kind except user (bots, webhooks and kinds a client does not know, fail closed) the result of steps 1–5 is capped afterwards:

  1. no_bots set → 0, whatever roles, overrides, ownership or administrator say.
  2. Otherwise perms ∩ (ALWAYS ∪ ⋃ bits(scope)) with ALWAYS = view_channel | change_nickname and the scope bits of APPLICATIONS.md §2.4. Owner and administrator expand to all bits first, so a bot’s administrator role is masked by its scopes; administrator itself is never part of any scope.
  3. If view_channel is missing afterwards, the result is 0.

Room-level permissions of a bot (my_permissions) are capped the same way with the room’s flag.

Effective “no bots” flag of a channel (APPLICATIONS.md §3.5): room.no_bots ∨ category.no_bots ∨ channel.no_bots ∨ (channel encrypted ∧ ¬channel.bots_allowed ∧ room.bots_in_encrypted_channels ≠ "allowed"). The room setting bots_in_encrypted_channels is per_channel (default of new rooms; every encrypted channel is closed to bots unless the channel allows them) or allowed (rooms that existed before the setting; encrypted channels follow the flags only); unknown values count as per_channel. bots_allowed never opens a channel that one of the three flags closes. Reference: no_bots_effective / noBotsEffective, vectors in testvectors/no_bots.json. Reference: SCOPES, scope_mask and cap_bot in the node (tavrn-node) and @tavrn/sdk; test vectors with kind, no_bots and scopes in testvectors/permissions.json.

  • 2026-10-15, use_components (bit 40): interacting with application message components (APPLICATIONS.md §5.10) has its own permission, channel-scoped, not management-class, in the defaults of @everyone, covered by no app-token scope (bots never click), granted once to every role holding send_messages at start (marker fixup.use_components). Timeouts remove it like every bit but reading. CHANNEL_SCOPED becomes 2027195138559; the shared test vectors cover the bit.

  • 2026-10-14, create_polls (bit 39): polls (PROTOCOL.md §7g) have their own permission next to send_messages, channel-scoped, not management-class, in the defaults of @everyone, covered by messages:write, granted once to every role and override that allowed send_messages at start (marker fixup.create_polls). The node enforces it for plaintext polls and for every message with a close time; clients enforce it for encrypted polls. CHANNEL_SCOPED becomes 927683510783; the shared test vectors cover the bit.

  • 2026-10-14, voice_status (bit 38): the status text of voice channels (VOICE.md §2a) has its own permission, channel-scoped, not management-class (so @everyone may hold it), covered by rooms:manage, granted once to every role with manage_channels at start (marker fixup.voice_status). CHANNEL_SCOPED becomes 377927696895; the shared test vectors cover the bit.

  • 2026-10-11, moved participations: a member moved into a voice channel by a moderator with move_members holds view_channel, read_history and connect there while the moved participation lasts (“Evaluation” above, VOICE.md §7); before, a move needed connect of the member in the target.

  • 2026-10-09, layered overrides: the evaluation applies the category’s overrides and then the channel’s own on top (above) instead of either the category’s (a channel “synced with its category”) or the channel’s. The channel field sync_with_category is removed: GET no longer returns it, PATCH ignores it (accepted and ignored for one release, then unknown). A channel without own overrides behaves exactly as a synced channel did; a channel with own overrides now also inherits its category’s overrides underneath. Overrides carry CHANNEL_SCOPED bits only (400 permissions.not_channel_scoped, start-up strip with role.override_restricted). Node and client ship together in this development phase, so there is no capability for the change.

  • 2026-10-09, moving channels: deleting a category or moving a channel out of it copies the category’s overrides into the channel (“Moving channels” above); moving a channel into a category that grants more needs manage_roles. Before, a private channel became public when its category was deleted.


This page is generated from tavrn-protocol/permissions.md (CC-BY-4.0; the permission tables and their values: Apache-2.0) when the website is built; its links were adapted for this site.