-
Notifications
You must be signed in to change notification settings - Fork 0
Authentication & ACL
Rina edited this page May 12, 2026
·
1 revision
Every incoming message passes through authorize() in auth.ts:
Message received
│
├─ Is author a bot? → SKIP
├─ Is it a DM? → SKIP
├─ Is channel registered (created via /new)? → ALLOW (no ACL check needed)
├─ Is user ID in ACL? → ALLOW
├─ Does user have an ACL-listed role? → ALLOW
├─ Is channel ID in ACL? → ALLOW
└─ Otherwise → SKIP
-
Registered channels (created via
/new) are unconditionally trusted — all messages pass through - ACL only applies to non-registered channels
- Authorization is synchronous — reads from in-memory Sets, no database hit per message
- The check runs on every
MessageCreateevent
Bot owners are auto-detected from two sources:
-
Discord Application Info — fetched via
GET /oauth2/applications/@me(the application owner/team members) -
BOT_OWNER_IDSenv var — comma-separated Discord user IDs
Results are cached for 60 seconds. Bot owners can use /acl commands.
The AclState class is an in-memory write-through cache:
-
Reads: Always from in-memory
Set<string>(per type: users, roles, channels) - Writes: Go to Prisma DB first, then update the in-memory Set
| Type | Value | What it allows |
|---|---|---|
user |
Discord user ID | Messages from this user in any non-registered channel |
role |
Discord role ID | Messages from any user with this role |
channel |
Discord channel ID | All messages in this specific channel |
/acl add type:user value:123456789012345678
/acl add type:role value:@SomeRole
/acl add type:channel value:#some-channel
/acl remove type:user value:123456789012345678
/acl list
model AclEntry {
id Int @id @default(autoincrement())
type String // "user", "role", "channel"
value String // Discord snowflake ID
addedBy String @map("added_by")
addedAt DateTime @default(now()) @map("added_at")
@@unique([type, value])
@@map("acl_entries")
}Each room has a mode that controls Claude Code's permission level:
| Mode | Flag | Description |
|---|---|---|
default |
(none) | Standard Claude permissions — prompts for file edits, commands, etc. |
plan |
--permission-mode plan |
Claude can only plan, not execute |
acceptEdits |
--permission-mode acceptEdits |
Claude can edit files without prompting |
bypassPermissions |
--dangerously-skip-permissions |
All permission checks disabled |
Note:
bypassPermissionsis the default mode for new rooms. Change with/new name:foo mode:defaultor/mode mode:default.
Changing the mode via /mode kills the current tmux session — the next /enter restarts Claude with updated flags.
claude-tmux-discord — Discord bot for per-channel Claude Code sessions via tmux
Setup
Usage
Technical
Help