Character management bot for themed roleplay servers.
Originally developed for Academia Arcana Isefora — adaptable for any similar community.🇪🇸 ¿No entiendes inglés? Puedes ver la guía completa en español aquí: Guía de Instalación ESP
ArcanaBot automates character management and moderation workflows for themed Discord roleplay servers. It includes:
- Character sheet system — Students, professors and workers with detailed profiles
- Staff review workflow — Approve/reject with feedback in designated channels
- Academic Conduct Points (PCA) — Sanctions, redemptions and appeals
- Power Spin system — 7 secret weighted race categories with randomized draws
- Battle system — Duels with results logged to Google Sheets
- ID card generation — Visual ID cards built with PIL/Pillow
- Admin panel — Stats, generation management and data cleanup
- Slot tracking — Configurable per-generation character limits
- Uniform system — Users choose from configurable uniform variants defined for your server
- Prerequisites
- Step 1 — Download the bot
- Step 2 — Create the Discord bot
- Step 3 — Set up Google Sheets
- Step 4 — Customize for your server
- Step 5 — Hosting (Railway or your PC)
- Command Reference
- Troubleshooting
Before you start, make sure you have these accounts ready:
| What | What for | Link |
|---|---|---|
| GitHub account | Store and upload the code | github.com |
| Discord account with a server | Where the bot will live | discord.com |
| Google account | For Google Sheets | You already have one |
| Railway account | To keep the bot running 24/7 | railway.app |
💡 Not sure what GitHub is? Think of it like Google Drive, but for code. It's free for this use.
There are two ways to get the bot files. Choose whichever is easier for you:
- Go to the GitHub repository:
https://github.com/DevilishhSmile/IseforaBot - Click the green
<> Codebutton - Click
Download ZIP - Extract the ZIP file to a folder on your computer (e.g.
C:\ArcanaBot\)
- Download GitHub Desktop from desktop.github.com
- Install it and sign in with your GitHub account
- Go to the GitHub repository
- Click
<> Code→Open with GitHub Desktop - Choose a folder on your computer and click Clone
✅ After Step 1, you should have a folder containing:
bot.py,requirements.txt,.env.example,cogs/,utils/, etc.
- Go to discord.com/developers/applications
- Sign in with your Discord account
- Click the blue
New Applicationbutton (top right) - Type a name for your bot (e.g.
ArcanaBot) and clickCreate
- In the left menu, click
Bot - If you see an
Add Botbutton, click it and confirm withYes, do it! - Scroll down to the
Privileged Gateway Intentssection and enable all three:- ✅ Presence Intent
- ✅ Server Members Intent
- ✅ Message Content Intent
- Click
Save Changes(the green button at the bottom)
⚠️ The token is like the bot's password. Never share it with anyone.
- Still in the
Botsection, find theTOKENarea - Click
Reset Tokenand confirm - Click
Copyand save that text somewhere safe (Notepad, etc.)- It looks something like:
MTIzNDU2Nzg5MDEy.AbCdEf.xYzAbCdEfGhIjKlMnOpQrStUv
- It looks something like:
You'll need this to copy channel and role IDs later:
- Open Discord on your computer
- Go to User Settings (the gear icon ⚙️ next to your name)
- In the left menu, click
Advanced - Enable
Developer Mode
✅ Now when you right-click any channel, role, or user, you'll see a
Copy IDoption.
- In Discord, right-click your server icon (in the left sidebar)
- Click
Copy Server ID - Save that number — you'll need it for the
.envfile
- In the developer portal, go to
OAuth2→URL Generator - Under
Scopes, check:- ✅
bot - ✅
applications.commands
- ✅
- Under
Bot Permissions(appears below), check:- ✅
Send Messages - ✅
Embed Links - ✅
Attach Files - ✅
Read Message History - ✅
Use External Emojis - ✅
Add Reactions - ✅
Manage Roles
- ✅
- Copy the generated URL at the bottom of the page
- Paste that URL into your browser, select your server and click
Authorize
✅ The bot should now appear in your server's member list (it will show as offline until you start it)
The bot saves all character information in a Google Sheets spreadsheet. You need to create that spreadsheet and give the bot access to it.
- Go to sheets.google.com and sign in
- Click the
+button (Blank spreadsheet) - Give it a name at the top (e.g.
ArcanaBot Data) - Now create 15 tabs with exact names. For each tab:
- Click the
+at the bottom left - Double-click the tab name and rename it
- Click the
Create these tabs exactly as shown (case-sensitive, no extra spaces):
| # | Exact Tab Name | What it stores |
|---|---|---|
| 1 | UniformesPendientes |
Pending uniform requests |
| 2 | UniformesAprobados |
Approved uniforms |
| 3 | EstudiantesPendientes |
Pending student sheets |
| 4 | EstudiantesAprobados |
Approved students |
| 5 | Profesores |
Approved professors |
| 6 | Trabajadores |
Approved workers |
| 7 | TrabajosPendientes |
Pending work sheets |
| 8 | GlobalStats |
Server-wide statistics |
| 9 | PuntosPC |
Current conduct points per user |
| 10 | HistorialPC |
Full points history |
| 11 | Sanciones |
Active sanctions log |
| 12 | FichasPoder |
Approved power sheets |
| 13 | HistorialSpins |
Power spin history |
| 14 | HistorialBatallas |
Battle history |
| 15 | CodigosID |
Generated ID codes |
⚠️ Tab names must be exactly as listed. An extra space or different capitalization will cause the bot to fail.
From the browser address bar, copy the ID from the URL:
https://docs.google.com/spreadsheets/d/ THIS_IS_THE_ID /edit
Save that ID — you'll need it for the .env.
💡 Google Cloud is the system that lets the bot read and write to your spreadsheet automatically.
- Go to console.cloud.google.com and sign in
- At the top, click the project selector (it says "Select a project" or shows a project name)
- In the window that appears, click
New Project - Give it a name (e.g.
ArcanaBot) and clickCreate - Wait a few seconds and make sure that project is selected at the top
- In the left menu, click
APIs & Services→Library - In the search box, type
Google Sheets API - Click the result, then click the blue
Enablebutton - Go back to the library, search for
Google Drive APIand enable it too
💡 A "service account" is like a robot user the bot will use to access your sheet without needing your password.
- Go to
APIs & Services→Credentials - Click
+ Create Credentials→Service Account - In
Service account nametype something likearcanabot-sheets - Click
Create and Continue - In step 2 ("Grant access..."), in the
Select a roledropdown, chooseEditor(under "Basic") - Click
Continue, thenDone
- You'll see your new service account in the list. Click its name (or the pencil ✏️ icon)
- Go to the
Keystab - Click
Add Key→Create New Key - Select
JSONformat and clickCreate - A file will automatically download with a long name. Rename it to
credentials.json - Move that file into the bot's folder
- Open
credentials.jsonwith Notepad - Find the line that says
"client_email"— copy the email address there- It looks like:
arcanabot-sheets@arcanabot-12345.iam.gserviceaccount.com
- It looks like:
- Go to your Google Sheets spreadsheet
- Click the
Sharebutton (top right) - Paste the service account email in the recipient field
- Change the permission to
Editor - Uncheck "Notify people" (so no email is sent to a robot)
- Click
Share
✅ The bot now has access to read and write your spreadsheet.
This is where you adapt the bot to use your server's specific names, roles, and channels. There are two files to edit.
The .env file stores your bot's private data (tokens, IDs).
- In the bot folder, find the file called
.env.example - Copy that file and rename the copy to
.env(without.example) - Open
.envwith Notepad
Fill in each field with your server's information:
# ── DISCORD ──────────────────────────────────────────
# The token you copied in Step 2.3
DISCORD_TOKEN=paste_your_token_here
# Your server ID from Step 2.5
GUILD_ID=123456789012345678
# ── GOOGLE SHEETS ─────────────────────────────────────
# Your spreadsheet ID from Step 3.2
GOOGLE_SHEETS_ID=1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms
# ── CHANNELS ──────────────────────────────────────────
# For each channel: right-click the channel in Discord → Copy ID
CANAL_ENVIAR_UNIFORME=id_of_channel_where_users_request_uniform
CANAL_REGISTRAR_ESTUDIANTE=id_of_channel_where_users_register_students
CANAL_REGISTRO_TRABAJOS=id_of_channel_where_users_register_workers
CANAL_CARTA_ACEPTACION=id_of_channel_where_acceptances_are_announced
CANAL_FICHAS_ESTUDIANTES=id_of_channel_where_student_sheets_are_stored
CANAL_FICHAS_PROFESORES=id_of_channel_where_professor_sheets_are_stored
CANAL_FICHAS_TRABAJADORES=id_of_channel_where_worker_sheets_are_stored
CANAL_REVISION_UNIFORMES=id_of_staff_uniform_review_channel
CANAL_REVISION_FICHAS=id_of_staff_sheet_review_channel
CANAL_LOGS_BOT=id_of_channel_where_the_bot_logs_its_actions
CANAL_SANCIONES=id_of_channel_where_sanctions_are_published
# ── ROLES ─────────────────────────────────────────────
# For each role: in Discord, go to Server Settings → Roles
# Right-click any role → Copy ID
ROL_STAFF=id_of_staff_role
ROL_ESTUDIANTE=id_of_role_given_when_student_sheet_is_approved
ROL_PROFESOR=id_of_role_given_when_professor_sheet_is_approved
ROL_TRABAJADOR=id_of_role_given_when_worker_sheet_is_approved
ROL_REGISTRADO=id_of_role_given_when_any_character_is_approved
ROL_SLOT_ADICIONAL=id_of_role_consumed_when_using_an_extra_slot
ROL_CONSEJO=id_of_student_council_role_that_can_assign_points
# ── GENERATION ────────────────────────────────────────
# Current generation number (start at 1)
GENERACION_ACTUAL=1💡 How to copy a channel ID: In Discord, right-click the channel →
Copy ID(if this doesn't appear, go back to Step 2.4 to enable Developer Mode).
💡 How to copy a role ID: Go to Server Settings → Roles → right-click a role →
Copy ID.
⚠️ If a role doesn't exist in your server or you don't want to use it, put0instead. For example:ROL_CONSEJO=0
This file is where you customize the lists of houses, subjects, jobs, clubs, and other server-specific things. Open it with Notepad or any text editor.
💡 Only change values between quotes
""or inside brackets[]. Don't delete commas or colons:.
CASAS = ["Redmeadow", "Ledacrealis", "Ravyelle", "Azorya"]Replace the names with your server's houses. If your server has no houses, leave it as an empty list:
CASAS = []
⚠️ If left empty ([]), the bot will automatically skip the house selector when registering characters.
CARGOS = {
"Librarian": 2,
"Secretary": 2,
"Nurse": 3,
"Inspector": None,
"Dean": 1,
}Each position has:
- The name of the position (in quotes)
- The max number of people who can hold that position (
None= no limit)
To add a new position:
"Position Name": 2, # max 2 people
"Another Position": None, # unlimitedMATERIAS = [
"Criminology", "Chemistry", "Astronomy", "Biology",
"History of Magic", "Alchemy",
]Change or add the subjects your server has. Each subject allows 1 professor by default. To allow more, also edit:
MATERIAS_LIMITE = {m: 1 for m in MATERIAS} # 1 professor per subject
MATERIAS_LIMITE["Substitute Professor"] = 3 # except substitutes: 3CLUBES = {
"Dance": 123456789012345678,
"Sports": 123456789012345678,
"Music": 123456789012345678,
}Each club has:
- The name of the club (in quotes)
- The Discord role ID assigned to members of that club
To get a role ID: right-click the role in Discord → Copy ID.
If your server has no clubs, leave it as an empty dictionary:
CLUBES = {}
⚠️ If left empty ({}), the bot will automatically skip the club selector when registering students.
SLOTS_CONFIG = {
1: {"estudiantes": 3, "trabajadores": 2, "profesores": 2},
"default": {"estudiantes": 3, "trabajadores": 2, "profesores": 2}
}This defines how many characters of each type each user can create per generation.
- The number
1is the configuration for Generation 1 "default"applies to any generation without a specific config- You can add future generation configs:
SLOTS_CONFIG = { 1: {"estudiantes": 3, "trabajadores": 2, "profesores": 2}, 2: {"estudiantes": 2, "trabajadores": 1, "profesores": 1}, "default": {"estudiantes": 2, "trabajadores": 1, "profesores": 1} }
The bot includes identity card images pre-designed for the Isefora Academia Arcana server. To adapt them to your server you need to replace them with your own designs:
⚠️ Important: Image files must keep exactly the same names as the originals and be placed in the project root (the main folder, next tobot.py) so the bot can find them correctly.
| File | For | Dimensions |
|---|---|---|
IDEstudiante.png |
Students | 600 × 400 px |
IDWorker.png |
Teachers & Staff | 400 × 600 px |
- Go to the folder where the card images are stored (inside the project)
- Design your own versions for your server following the same template / disposition of the card imagaes.
- Save them with the exact same file names (
IDEstudiante.pngandIDWorker.png) as the originals (matching uppercase, lowercase, and extension) - Copy them to the project root folder, replacing the original files
If you upload an image with a different name or place it in a different folder, the bot won't be able to find it and the cards won't generate correctly.
💡 Tip: Leave blank space in the areas where the bot writes text (name, house, generation, code) and where it places the character photo. If you're unsure where those areas are, use the original templates as a visual reference first.
The race categories and their probabilities are in CATEGORIAS_RAZA. Current weights:
| Category | Probability |
|---|---|
| ⚪ Basic | 40% |
| 🔵 Sensitive | 25% |
| 🟢 Epic | 15% |
| 🟡 Mythic | 10% |
| 🟠 Legendary | 6% |
| 🔴 Cursed | 3% |
| ✨ Divine | 1% |
To adjust probabilities, change the "peso" (weight) value of each category. Weights don't need to add up to 100 — the bot calculates percentages automatically.
You have two options for running the bot. Choose whichever works best for you:
| Option A: Railway (cloud) | Option B: Your computer | |
|---|---|---|
| Cost | Free (with limits) or ~$5/mo | Free |
| Bot runs | 24/7 always | Only when your PC is on |
| Difficulty | Medium | Easy |
| Best for | Active servers | Testing or small servers |
⚠️ Another thing to have in mind: If you choose to run the bot from your PC, you'll have to start the bot again from the terminal everytime you turn your PC off.
💡 About Railway's cost: Railway charges for actual usage. A small bot typically uses less than $1-2 of the monthly $5 credit. In practice you'll almost never hit the limit.
🔍 Want to explore other hosting options? Services like Fly.io, Oracle Cloud Free Tier, Render or DigitalOcean can also work for hosting Discord bots. Each has its own setup process — if any of them interest you, feel free to ask your favorite AI how to set them up for a Python bot. 😊
Railway keeps the bot running 24/7 without leaving your computer on.
If you downloaded the ZIP and have never used GitHub:
- Go to github.com and sign in
- Click
+→New repository - Give it a name (e.g.
my-arcanabot) - Select
Private(so nobody can see your code) - Click
Create repository - Download GitHub Desktop from desktop.github.com
- In GitHub Desktop:
File→Add Local Repository→ select the bot folder - Click
Publish repositoryand select your new repository
⚠️ Before uploading, make sure.envandcredentials.jsonare in.gitignore(they already should be). These files contain private information and should never be pushed to GitHub.
- Go to railway.app and sign in (you can use your GitHub account)
- Click
New Project - Select
Deploy from GitHub repo - Connect your GitHub account if prompted
- Find and select the repository you created in the previous step
- Railway will start trying to start the bot (it will fail for now — you still need to configure the variables)
- Click on your service in Railway (the box that appears in the project)
- Go to the
Variablestab - Add every variable from your
.envfile:- Click
New Variable - Type the name (e.g.
DISCORD_TOKEN) - Type the value (the token you copied)
- Repeat for every variable
- Click
💡 You can also click
RAW Editorand paste your entire.envfile contents at once.
The credentials.json file can't be uploaded to GitHub for security. In Railway you add it as a variable:
- Open your
credentials.jsonwith Notepad - Select all content (Ctrl+A) and copy it (Ctrl+C)
- In Railway → Variables, create a new variable:
- Name:
GOOGLE_CREDENTIALS_JSON - Value: paste all the file's content
- Name:
- Click
Add
Railway wipes temporary files when the bot restarts. To save the database permanently, you need a volume:
- In your Railway project view, click
+ New - Select
Volume - In
Mount Pathtype:/app/data - Click to connect it to your bot service
- Railway will automatically redeploy the bot
- In Railway, click your service and go to the
Logs(orDeploy Logs) tab - You should see something like:
✅ Cog cargado: cogs.admin ✅ Cog cargado: cogs.estudiantes ... ✅ Bot conectado como YourBot#1234 (ID: 123456789) ✅ 25 comando(s) sincronizados: [uniforme, estudiante, ...] - If you see errors, check the Troubleshooting section
This option is ideal if you want to test the bot, have a small server, or prefer not to pay for hosting. The bot will only work while your computer is on and the script is running.
- Go to python.org/downloads
- Download Python 3.11 (look for the version that says
3.11.x) - Run the installer
- Important: on the first installer screen, check the box that says "Add Python to PATH" before clicking Install
- Verify it installed: open a terminal (Windows: search
cmdin the Start menu) and type:It should showpython --versionPython 3.11.x
- Navigate to the folder where you downloaded the bot
- Windows: hold
Shiftand right-click inside the folder → select "Open PowerShell window here" (or "Open in Terminal") - Mac: right-click the folder → "New Terminal at Folder"
In the terminal you opened, type these commands one by one (press Enter after each):
# Create the virtual environment
python -m venv venv# Activate it (Windows)
venv\Scripts\activate# Activate it (Mac/Linux)
source venv/bin/activateYou'll know it's active because (venv) appears at the start of the terminal line.
# Install all dependencies
pip install -r requirements.txtThis may take a few minutes. You'll see several packages being downloaded and installed.
You should have done this in Step 4.1. If you haven't yet, go there now.
With the virtual environment active ((venv) showing in the terminal):
python bot.pyIf everything is working, you'll see something like:
✅ Cog cargado: cogs.admin
✅ Cog cargado: cogs.estudiantes
...
✅ Bot conectado como YourBot#1234 (ID: 123456789)
✅ Base de datos SQLite lista
✅ 25 comando(s) sincronizados
✅ The bot is running! You can minimize the terminal but don't close it — closing it disconnects the bot.
Every time you want to start the bot from your computer:
# 1. Activate the virtual environment
venv\Scripts\activate # Windows
source venv/bin/activate # Mac/Linux
# 2. Run the bot
python bot.py💡 Tip: On Windows, you can create a
start.batfile with those two lines to start the bot with a double-click.
| Command | Description |
|---|---|
/about-bot |
Show bot info, features, version and credits |
| Command | Description |
|---|---|
/uniforme |
Request uniform approval |
/estudiante |
Register student sheet |
/profesor |
Register professor sheet |
/trabajo |
Register worker sheet |
/editar-ficha |
Edit an existing sheet |
| Command | Description |
|---|---|
/poder |
Spin for a power (requires sheet photo) |
/respin |
Re-spin (requires special role) |
/iniciar-batalla |
Start a duel with another user |
| Command | Description |
|---|---|
/generar-id |
Generate visual ID card |
/ver-id |
View a previously generated ID |
| Command | Description |
|---|---|
/asignar-pc |
Assign positive or negative points |
/sancionar |
Create a formal sanction |
/redimir-sancion |
Approve a sanction redemption |
/apelar |
Appeal a sanction |
/ver-sanciones |
View a user's active sanctions |
/historial-pc |
View a user's points history |
| Command | Description |
|---|---|
/admin |
Control panel (stats, slots, generation) |
/admin-data ver |
View all characters of a user |
/admin-data eliminar-personaje |
Delete a specific character |
/admin-data eliminar-tipo |
Delete all characters of a type |
/admin-data reset-slots |
Reset a user's slots |
/admin-data reset-total |
Fully reset a user's data |
Cause: The DISCORD_TOKEN variable isn't configured in Railway.
Fix: Go to Railway → your service → Variables and make sure DISCORD_TOKEN has the correct token.
Cause: Railway can't create the database because no volume is mounted.
Fix: Follow Step 5.5 to create the volume at /app/data.
Cause 1: The bot doesn't have the applications.commands permission.
Fix 1: Follow Step 2.6 to re-invite the bot with the correct permissions (it won't kick it, just updates permissions).
Cause 2: Commands failed to sync.
Fix 2: Check the Logs in Railway for ❌ Error sincronizando. If there's an error, fix the underlying issue and trigger a new Deploy.
Cause: The bot can't find your Google Sheets spreadsheet.
Fix:
- Verify
GOOGLE_SHEETS_IDin Railway Variables has the correct ID (just the ID, not the full URL) - Verify you shared the sheet with the service account email (Step 3.7)
Cause: You're using Python 3.12 or higher, which isn't compatible.
Fix: In Railway, create a file called .python-version in the project root with content 3.11.9. Then trigger a new Deploy.
Cause: Privileged Intents aren't enabled.
Fix: Go to discord.com/developers/applications → your app → Bot → enable all three Privileged Gateway Intents (Step 2.2).
Cause: The bot's role in the server isn't above the roles it's trying to assign.
Fix: In Discord, go to Server Settings → Roles, and drag the bot's role so it's above all the roles the bot assigns (ROL_ESTUDIANTE, ROL_PROFESOR, etc.)
| Error | Cause | Fix |
|---|---|---|
ModuleNotFoundError: audioop |
Python 3.12+ incompatible | Use exactly Python 3.11; add .python-version with 3.11.9 |
Forbidden: 403 on sync |
Bot missing applications.commands scope |
Re-invite the bot with the correct scope |
gspread.exceptions.SpreadsheetNotFound |
Wrong URL or missing permissions | Check URL in .env and confirm sheet is shared with the service account |
discord.errors.InteractionTimedOut |
Interaction not responded to within 3s | Add await interaction.response.defer() at the start of slow callbacks |
Extension has no 'setup' function |
Missing async def setup(bot) in cog |
Add it at the end of every cog file |
| Slots showing wrong generation data | Outdated GENERACION_ACTUAL variable |
Update the environment variable in Railway/Render |
⚠️ Never share or upload these files to GitHub:
.env— contains the Discord tokencredentials.json— contains Google Sheets access
If someone gets your Discord token, they can fully control your bot. If this happens:
- Go to discord.com/developers/applications → Bot → Reset Token immediately
- Update the new token in Railway
CC BY-NC 4.0 — Free to use, modify and share. Commercial use and resale are not permitted. Credit to the original author is required.
See the LICENSE file for full details.
Built with ❤️ by Devilishh · Need technical support? Contact devilishh. on Discord