๐ Permissions & Caps¶
This page explains who can use Magikal bot commands, how access is checked, and where role permissions are configured.
The short version: Discord permissions control what Discord allows, while Magikal caps control what the bot allows.
Quick answer
Most staff-only bot access is controlled by capability roles.
Admins can map Discord roles to caps like admin, moderator, events, recruitment, and helper using /roles.
๐งญ Quick version¶
Magikal does not rely on one single permission system.
It uses a few layers together:
| Layer | Plain-English meaning |
|---|---|
| ๐ Discord permissions | Native Discord powers like Administrator, Manage Guild, Manage Messages, Ban Members, and Manage Channels |
| ๐ท๏ธ Magikal caps | Bot-level capability roles such as admin, moderator, events, recruitment, and helper |
| ๐ Owner-only tools | Commands only the bot owner can run, such as command dumps and deep diagnostics |
| ๐ฏ Feature allowlists | Extra feature-specific access, such as /ship allowed roles |
| ๐ Help visibility | Controls what appears in public/staff/admin help panels |
Important
Help panels and documentation only show what users should see.
Real permission checks must happen inside the bot command code.
๐งฑ Permission layers¶
Think of command access like a stack of gates.
| Layer | What it does | Example |
|---|---|---|
| Discord permissions | Checks native Discord power | Administrator, Manage Messages, Ban Members |
| Magikal caps | Checks mapped staff roles | admin, moderator, events |
| Bot owner checks | Locks commands to owner only | !dump_commands |
| Feature allowlists | Adds feature-specific access | /ship allowed roles |
| Help visibility | Controls what help panels display | Public, Moderator, Admin tabs |
Security rule
A command must never rely on help visibility alone.
If a user should not run a command, the command itself must deny them.
๐ท๏ธ Capability roles¶
Magikal caps are friendly names for staff responsibilities.
The core permission helper lives in:
bot/utils/perms.py
Current core caps listed there:
| Cap | Plain-English meaning |
|---|---|
admin |
Full bot/server configuration access |
moderator |
Moderation and staff command access |
events |
Event management access |
recruitment |
Recruitment/application access |
helper |
General helper/staff support access |
member |
Member-level marker |
The main helper functions are:
| Helper | What it is for |
|---|---|
slash_require_caps(...) |
Adds a Magikal cap check to slash commands |
prefix_require_caps(...) |
Adds a Magikal cap check to text/prefix commands |
gate_check(...) |
Performs the actual access check |
extract_caps_from_checks(...) |
Lets the help/audit tools detect command caps |
send_deny(...) |
Sends a clean permission denied message |
๐ Admin bypass¶
A user passes most Magikal cap checks if they have either:
Discord Administrator
OR configured Magikal admin role
OR the specific required cap role
So if a command requires moderator, these users can run it:
| User type | Can run it? |
|---|---|
| Discord Administrator | โ |
| Configured Magikal admin role | โ |
| Configured Magikal moderator role | โ |
| Normal member | โ |
Why admin bypass exists
Admin bypass prevents staff from locking themselves out of configuration commands.
๐ ๏ธ Managing role mappings¶
Role/capability mapping is handled by:
bot/cogs/roles_config.py
Main slash command group:
/roles
Current role mapping commands:
| Command | What it does |
|---|---|
/roles show |
Shows current cap โ role mapping |
/roles set |
Sets a Discord role for a cap |
/roles clear |
Clears a cap role |
/roles export |
Exports the mapping as JSON |
These commands require both:
@app_commands.default_permissions(administrator=True)
@slash_require_caps("admin")
That means Discord should treat them as admin-level commands, and Magikal also checks the admin cap.
๐งฉ Current configurable caps¶
roles_config.py currently exposes these choices in /roles set:
| Capability | Visible in /roles set |
|---|---|
admin |
โ |
moderator |
โ |
events |
โ |
recruitment |
โ |
finance |
โ |
helper |
โ |
Known issue: finance cap mismatch
roles_config.py exposes finance, and banking.py uses slash_require_caps("finance").
But the core CAPS set in bot/utils/perms.py does not currently include finance.
Until that is reviewed, a command requiring finance may fall back to the default moderator requirement.
Do not rely on finance-only access until this is fixed and tested.
โ ๏ธ Unknown cap fallback¶
The current gate filters out unknown cap names.
If no valid cap remains, it falls back to:
moderator
Example:
slash_require_caps("finance")
If finance is not recognised by the core CAPS set, the real requirement may become:
moderator
Adding new caps
When adding a new cap, add it everywhere it belongs.
Do not add a cap to one cog and forget the core permission helper.
๐ค Slash command permissions¶
Slash commands usually use Magikal caps like this:
@slash_require_caps("admin")
@app_commands.command(name="example", description="Example admin command")
async def example(self, interaction: discord.Interaction):
...
Many slash commands also use native Discord visibility permissions:
@app_commands.default_permissions(administrator=True)
or:
@app_commands.default_permissions(manage_guild=True)
Good slash command pattern
Use Discord permissions for native command visibility.
Use Magikal caps for the actual bot-level access rule.
๐ฌ Prefix/text command permissions¶
Prefix commands use:
@prefix_require_caps("admin")
or:
@prefix_require_caps("moderator")
Common live examples:
| Cog | Common cap |
|---|---|
admin_config.py |
admin |
moderation.py |
moderator and admin |
tempvc_v2.py |
admin |
basic.py |
admin |
Some prefix commands also use native Discord checks:
@commands.has_permissions(...)
@commands.bot_has_permissions(...)
๐งฐ Native Discord permission checks¶
Native Discord permissions still matter.
Examples found in live cogs:
| Check | Typical use |
|---|---|
commands.has_permissions(manage_messages=True) |
Purge/message tools |
commands.has_permissions(manage_channels=True) |
Lock, unlock, slowmode |
commands.has_permissions(ban_members=True) |
Ban and softban |
commands.has_permissions(manage_roles=True) |
Role tools |
commands.is_owner() |
Owner-only diagnostics/export |
app_commands.default_permissions(...) |
Slash command visibility |
Bot permissions matter too
A user having permission is not enough.
The bot also needs permission to perform the action.
Example:
@commands.bot_has_permissions(manage_messages=True)
๐ Owner-only commands¶
Some commands are restricted to the bot owner.
Examples:
| Command/source | Purpose |
|---|---|
!dump_commands |
Exports the live command tree to _exports/ |
diag_storage.py |
Owner-only storage/Redis diagnostics |
command_dump.py |
Command inventory export |
Owner-only rule
Owner-only tools should stay owner-only.
These commands can expose internal bot structure or operational details.
๐ฏ Feature-specific gates¶
Some features have extra access rules beyond the main cap system.
Example: Star Citizen ship tools.
| Feature | Storage/helper |
|---|---|
/ship role allowlist |
get_ship_roles, add_ship_role, remove_ship_role |
| command role gates | get_command_roles, add_command_role, remove_command_role |
These are feature-specific and should also be explained on the relevant feature page.
๐ Help panel visibility¶
Help visibility is generated by:
bot/cogs/help_auditor.py
bot/cogs/help_panel.py
Main registry file:
data/help_registry.json
The help auditor checks:
- slash commands
- prefix commands
- default Discord permissions
- command checks
- Helper 2.0 capability tags
- explicit public allowlist
Help panels are not security
Help panels decide what users see.
Command checks decide what users can actually run.
๐ Public command allowlist¶
Public help visibility is allowlist-driven.
Examples currently include:
| Public command |
|---|
!ping |
!whoami_public |
!help |
!commands |
/ping |
/help |
/info |
/ship |
/market |
/item |
/commodity |
/refinery audits |
/refinery capacities |
/refinery methods |
/refinery yields |
/rsi profile |
Public help rule
A command should not appear as public unless it is explicitly safe for normal members.
Unknown commands should default away from public visibility.
๐ฅ Help audience buckets¶
The help system groups commands into broad audiences.
| Audience | Plain-English meaning |
|---|---|
| User | Public/member-safe commands |
| Moderator | Staff, helper, event, recruitment, finance-style commands |
| Admin | Admin/config/owner-style commands |
Capability tags influence the bucket.
| Cap | Help audience |
|---|---|
admin |
Admin |
moderator |
Moderator |
events |
Moderator-style staff bucket |
recruitment |
Moderator-style staff bucket |
helper |
Moderator-style staff bucket |
finance |
Moderator-style staff bucket in help auditor logic |
๐งพ Help panel commands¶
Help panel commands live in:
bot/cogs/help_panel.py
Useful commands:
| Command | Purpose |
|---|---|
/help_panel |
Posts the role-aware help panel |
/help_role |
Shows help for a specific staff role/capability |
/handbook |
Posts the staff handbook |
/help_admin_panel |
Posts the admin help panel |
/help_moderator_panel |
Posts the moderator help panel |
/help_public_panel |
Posts the public help panel |
/help_events_panel |
Posts the events help panel |
/help_recruitment_panel |
Posts the recruitment help panel |
/help_finance_panel |
Posts the finance help panel |
/help_helper_panel |
Posts the helper help panel |
๐งช Testing a permission change¶
When adding or changing command access, test the real behaviour.
Good permission test
- Test as an admin.
- Test as a user with the mapped cap role.
- Test as a normal member without the cap.
- Confirm the command denies correctly.
- Confirm the help panel matches the real access.
- Check logs for errors.
For slash command visibility, also check whether Discord shows/hides the command as expected.
โ Adding a new capability¶
Before adding a new cap such as finance, support, or market:
- Add it to
CAPSinbot/utils/perms.py. - Add it to
/roles setchoices if it should be configurable. - Add it to role mapping display/export.
- Update
help_auditor.pyaudience mapping. - Update
help_panel.pyfiltering/panel support if needed. - Update documentation.
- Test that users with only that role can use the intended commands.
- Test that users without that role are denied.
Do not add cap names in only one place
A cap name used in a command decorator must exist in the core cap system.
Otherwise the command may fall back to a different permission requirement.
๐จ Red flags¶
Stop and review if:
- a command uses
slash_require_caps("something")but that cap is not inCAPS - a command modifies Discord state but has no Discord permission check
- a command saves config but has no admin cap
- a command appears in public help but should be staff-only
- a command is hidden from help but still usable by normal users
- a command uses only frontend/help visibility as a gate
- a new feature creates its own permission system instead of using caps
- role IDs are hardcoded
- raw Discord IDs are logged
โ Final checklist¶
Before calling a permission change done:
- command appears only for expected users where Discord supports visibility
- command denies correctly when a user lacks the cap
- command works for configured cap role
- admin bypass works
- non-admin/non-cap user cannot use it
- help panel visibility matches real access
- logs do not expose raw Discord IDs
- docs are updated
๐ง Rule¶
Permissions should be enforced by the bot, mapped through clear capability roles, reflected in help panels, and documented from the current live files.