kythia.config.js Reference
A complete, super-detailed reference for every setting in kythia.config.js — what it does, how to get it, and what to set it to.
The kythia.config.js file is the master control file for your entire bot. It controls its identity, features, behavior, and integrations. It is loaded at startup and injected throughout the bot via the dependency container.
To get started: Copy example.kythia.config.js → rename it to kythia.config.js.
.env and referenced via process.env.*. Committing secrets to version control is a security risk.I. General Settings
env
Type: string | Default: 'local'
Describes the environment the bot is running in. This is informational only — it shows in log output but does not change bot behavior.
env: 'local', // Use 'production' for your live VPS bot
| Value | When to use |
|---|---|
'local' |
Development on your own PC |
'production' |
Running 24/7 on a VPS/server |
version
Auto-managed. Do not change.
Automatically reads the version from package.json. This is shown in the /about command and log output.
version: require('./package.json').version,
licenseKey
Your Kythia license key, read from .env. Do not hardcode the key value here.
licenseKey: process.env.LICENSE_KEY,
Set LICENSE_KEY=your_key_here in your .env file.
legal ⚠️ Critical — Bot Will Not Start Without This
The bot refuses to start if either value is false. This is intentional — you must consciously accept both before running.
legal: {
acceptTOS: true, // ⚠️ MUST be true — Accept Terms of Service
dataCollection: true, // ⚠️ MUST be true — Accept anonymous telemetry
},
| Field | What it means |
|---|---|
acceptTOS |
You accept Kythia's Terms of Service. Change to true. |
dataCollection |
You accept anonymous usage telemetry (command usage stats). Change to true. |
owner
Defines who has superuser (owner) access to the bot. Owners can use owner-only commands, bypass all cooldowns (if ownerSkipCooldown is enabled), and interact with the AI using bypass filters.
owner: {
ids: '1158654757183959091', // Your Discord User ID
names: 'kenndeclouv', // Your display name
},
How to get your Discord User ID:
| Field | Description |
|---|---|
ids |
Your Discord User ID. For multiple owners, separate with commas: '111,222,333' |
names |
Your display name, shown in the /about command. Multiple: 'owner1,owner2' |
sentry
Optional. Enables automatic error tracking via Sentry. Unhandled exceptions will be reported to your Sentry dashboard. If SENTRY_DSN is empty, this has no effect.
sentry: {
dsn: process.env.SENTRY_DSN,
},
How to get your Sentry DSN:
SENTRY_DSN=your_dsn_here to your .env fileII. Discord Bot Core (bot)
This section controls your bot's core Discord identity and behavior.
bot: {
name: 'Kythia',
token: process.env.DISCORD_BOT_TOKEN,
clientId: process.env.DISCORD_BOT_CLIENT_ID,
clientSecret: process.env.DISCORD_BOT_CLIENT_SECRET,
totalShards: 'auto',
mainGuildId: '',
devGuildId: '',
color: '#FFFFFF',
prefixes: ['!', 'k!'],
status: 'online',
activityType: 'Playing',
activity: 'join support https://dsc.gg/kythia',
globalCommandCooldown: 5,
language: 'en',
locale: 'en-US',
timezone: 'Asia/Jakarta',
},
name
Type: string
The bot's internal name, shown in log headers, embeds, and the /about command.
token
Type: string (from .env)
Your Discord bot token. This is the most sensitive value — never share it or commit it to Git.
How to get your bot token:
DISCORD_BOT_TOKEN=your_token_here to your .envclientId
Type: string (from .env)
Your Discord application's Client ID (also called Application ID). Used to register slash commands and generate invite links.
How to get it:
DISCORD_BOT_CLIENT_ID=your_id_here to your .envclientSecret
Type: string (from .env)
Your Discord application's Client Secret. Only required if you are using the Dashboard (OAuth2 login).
How to get it:
DISCORD_BOT_CLIENT_SECRET=your_secret_here to your .envtotalShards
Type: 'auto' | number | Default: 'auto'
Controls how many shards the bot runs. Discord requires sharding for bots in 2,500+ servers.
| Value | When to use |
|---|---|
'auto' |
Recommended. Discord automatically determines the optimal shard count. |
4 (or any number) |
Only use if you have a specific reason to control the exact shard count. |
mainGuildId
Type: string
The ID of your main/support Discord server. Used internally for guild-specific features and logging.
How to get it: Right-click your server name in Discord → Copy Server ID (requires Developer Mode enabled).
devGuildId
Type: string
The ID of your development/testing Discord server. Slash commands deployed to a specific guild appear instantly, unlike global commands which can take up to 1 hour to propagate.
devGuildId for instant testing, deploy globally for production releases.color
Type: string (hex color) | Default: '#FFFFFF'
The embed accent color used across all bot messages and the ContainerBuilder interface.
color: '#F6B1CE', // Pink — change to your branding color
prefixes
Type: string[] | Default: ['!', 'k!']
List of text command prefixes. Users can type !ping or k!ping to trigger prefix commands.
prefixes: ['!', 'k!'], // Add or remove prefixes as needed
status
Type: 'online' | 'idle' | 'dnd' | 'invisible' | Default: 'online'
The bot's presence status shown in Discord.
activityType
Type: string | Default: 'Playing'
The type of activity shown in the bot's status.
| Value | Shows as |
|---|---|
'Playing' |
🎮 Playing ... |
'Watching' |
👁️ Watching ... |
'Listening' |
🎧 Listening to ... |
'Custom' |
(just the text) |
activity
Type: string
The text shown in the bot's Discord status next to the activity type.
activity: 'join support https://dsc.gg/kythia',
globalCommandCooldown
Type: number (seconds) | Default: 5
The minimum number of seconds a user must wait between any two command uses. This is a global anti-spam cooldown applied to all commands.
language
Type: string | Default: 'en'
The default language for bot responses. Currently supported: 'en' (English), 'id' (Indonesian).
locale
Type: string | Default: 'en-US'
Used for formatting numbers, dates, and currencies. Must be a valid BCP 47 locale tag.
Examples: 'en-US', 'id-ID', 'ja-JP'
timezone
Type: string | Default: 'Asia/Jakarta'
The IANA timezone string used for all time-based features (schedulers, daily resets, cron jobs). Should match your VPS/server's timezone for consistency.
Find your timezone: Wikipedia TZ Database List
Examples: 'Asia/Jakarta', 'America/New_York', 'Europe/London', 'UTC'
III. Database Configuration (db)
db: {
driver: process.env.DB_DRIVER,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
name: process.env.DB_NAME,
user: process.env.DB_USER,
pass: process.env.DB_PASSWORD,
storagePath: process.env.DB_STORAGE_PATH,
socketPath: process.env.DB_SOCKET_PATH,
dialectOptions: process.env.DB_DIALECT_OPTIONS,
timezone: '+07:00',
useRedis: true,
redis: process.env.REDIS_URLS,
redisCacheVersion: 'v1.0',
},
driver
The database engine to use. Set DB_DRIVER in your .env.
| Value | Database |
|---|---|
'mysql' |
MySQL 8+ |
'postgres' |
PostgreSQL |
'mariadb' |
MariaDB |
'sqlite' |
SQLite (file-based, no server needed) |
'mssql' |
Microsoft SQL Server |
host / port / name / user / pass
Standard database connection credentials. All read from .env.
| Field | .env key |
Example value |
|---|---|---|
host |
DB_HOST |
localhost or 127.0.0.1 |
port |
DB_PORT |
3306 (MySQL), 5432 (Postgres) |
name |
DB_NAME |
kythia |
user |
DB_USER |
root |
pass |
DB_PASSWORD |
your database password |
storagePath
SQLite only. Path to the .sqlite file on disk.
DB_STORAGE_PATH=./kythia.sqlite
socketPath
MySQL / MariaDB / Cloud SQL only. Path to the Unix socket used instead of TCP connections. Common with Google Cloud SQL.
DB_SOCKET_PATH=/var/run/mysqld/mysqld.sock
dialectOptions
MSSQL only. Extra driver options passed as a JSON string.
timezone
Type: string (UTC offset) | Default: '+07:00'
The timezone offset for the database connection. This controls how the database driver interprets DATETIME values. Use '+00:00' for UTC.
useRedis
Type: boolean | Default: true
Enables Redis as the caching layer. Strongly recommended. Some features (global chat, high-frequency lookups) may not work correctly without Redis.
useRedis: false will fall back to in-memory caching only, which does not persist across restarts and does not work in multi-shard environments.redis
Type: string (from .env) — comma-separated Redis URLs.
REDIS_URLS=redis://localhost:6379
# Multiple nodes:
REDIS_URLS=redis://localhost:6379,redis://localhost:6380
How to set up Redis:
sudo apt install redis-server
sudo systemctl enable --now redis
docker run -d --name redis -p 6379:6379 redis:latest
redisCacheVersion
Type: string | Default: 'v1.0'
A version tag appended to all Redis cache keys. Changing this value (e.g., from 'v1.0' to 'v1.1') invalidates all existing cached data on restart without touching the database.
IV. Addon Configuration (addons)
All bot features are packaged as addons. Every addon has an active toggle. Disabled addons are never loaded — their commands, events, and memory footprint are completely removed.
all — Global Master Switch
addons: {
all: {
active: true, // Set to false to disable ALL addons at once (useful for debugging)
},
}
adventure — RPG Adventure System
adventure: { active: true },
Enables the full text-based RPG system: character creation, dungeon battles, monster encounters, inventory management, and the in-game shop.
Commands enabled: /adventure battle, /adventure inventory, /adventure profile, /adventure recall, /adventure shop, /adventure start, /adventure use
ai — Google Gemini AI Chat
Enables AI-powered chat using Google's Gemini models.
ai: {
active: true,
model: 'gemini-2.5-flash',
geminiApiKeys: process.env.GEMINI_API_KEYS,
getMessageHistoryLength: 4,
perMinuteAiLimit: 10,
safeCommands: ['ping', 'avatar'],
additionalCommandKeywords: ['setting', 'musik', 'latency'],
personaPrompt: `You are Kythia, a friendly Discord assistant. Your creator is kenndeclouv.`,
defaultPersonality: 'friendly',
ownerInteractionPrompt: `kenndeclouv is your developer.`,
dailyGreeter: false,
dailyGreeterSchedule: '0 7 * * *',
dailyGreeterPrompt: `Make a warm greeting for the members.`,
ownerBypassFilter: true,
},
model
The Gemini model to use. See full model list.
| Model | Speed | Quality | Cost |
|---|---|---|---|
gemini-2.5-flash |
Fast | High | Free tier available |
gemini-2.5-pro |
Slower | Best | Paid |
geminiApiKeys
Comma-separated list of Gemini API keys. Multiple keys are used in round-robin rotation to spread requests and avoid per-key rate limits.
How to get Gemini API Keys:
.env: GEMINI_API_KEYS=key1,key2,key3getMessageHistoryLength
How many recent messages (before the user's message) to include as context for the AI. Higher values = better context, higher token usage.
perMinuteAiLimit
Max AI requests per minute across all users. Tune this based on your Gemini plan's rate limits.
personaPrompt
The system prompt that defines Kythia's personality. Customize this to fit your bot's character. Keep it concise.
personaPrompt: `You are Kythia, a friendly and helpful Discord bot. You are cheerful and love helping users. Your creator is kenndeclouv.`,
defaultPersonality
Default personality mode for new users. Users can change their own with /ai personality.
| Value | Behavior |
|---|---|
'friendly' |
Warm, casual, uses emoji |
'professional' |
Formal, no emoji |
'humorous' |
Jokes, playful tone |
'technical' |
Detailed, precise |
'casual' |
Relaxed, short responses |
dailyGreeter
Set to true to have the AI automatically send a morning greeting to configured channels.
dailyGreeterSchedule
Cron expression for when the greeting is sent. Uses crontab format.
dailyGreeterSchedule: '0 7 * * *', // Every day at 7:00 AM (server timezone)
ownerBypassFilter
When true, the bot owner can use the AI without content safety filtering.
checklist — Server Setup Checklist
checklist: { active: true },
Provides admin commands to create and manage interactive server setup checklists.
core — Core Utilities
core: {
active: true, // ❗ Do NOT disable
exchangerateApi: process.env.EXCHANGERATE_API, // For /currency command
},
Contains all essential utility commands: /ping, /stats, /help, /settings, /language, /about.
active: false. This addon contains essential infrastructure commands that the rest of the bot depends on.How to get ExchangeRate API key:
EXCHANGERATE_API=your_key to .enveconomy — Global Economy System
economy: {
active: true,
dailyCooldown: 86400, // 1 day — /eco daily
begCooldown: 3600, // 1 hour — /eco beg
lootboxCooldown: 14400, // 4 hours — /eco lootbox
workCooldown: 28800, // 8 hours — /eco work
robCooldown: 7200, // 2 hours — /eco rob
hackCooldown: 3600, // 1 hour — /eco hack
},
All cooldown values are in seconds. Here's a quick reference:
| Seconds | Equals |
|---|---|
3600 |
1 hour |
7200 |
2 hours |
14400 |
4 hours |
28800 |
8 hours |
86400 |
24 hours (1 day) |
api — Web Dashboard
api: {
active: true,
url: process.env.API_URL,
port: process.env.API_PORT || 3000,
secret: process.env.API_SECRET,
},
Enables the bot's built-in API server and web dashboard integration.
| Field | .env key |
Description |
|---|---|---|
url |
API_URL |
Full public URL of the API (e.g., https://api.kythia.my.id). Must match your Discord OAuth2 redirect URI. |
port |
API_PORT |
The port the API listens on internally (e.g., 3000). |
secret |
API_SECRET |
A random secret string for signing session cookies. Generate a strong one: openssl rand -hex 32 |
fun — Fun & Games
fun: {
active: true,
wordle: {
words: ['apple', 'grape', 'lemon', 'mango', 'peach', 'berry', 'melon', 'guava'],
},
},
words
The word pool for /fun wordle. All words must be exactly 5 letters. Users won't know which words are in the list.
giveaway — Giveaway System
giveaway: {
active: true,
checkInterval: 20, // Seconds between giveaway end checks
},
checkInterval
How often (in seconds) the bot checks whether any active giveaways have ended. Lower = more responsive, but slightly more CPU usage. 20 is a good balance.
globalchat — Cross-Server Chat
enabled: false unless you have been specifically given access. Setting this up incorrectly will do nothing.globalchat: {
enabled: false,
apiUrl: process.env.GLOBAL_CHAT_API_URL,
apiKey: process.env.GLOBAL_CHAT_API_KEY,
healthCheckSchedule: '*/30 * * * *',
healthCheckDelay: 1000,
},
globalvoice — Cross-Server Voice
active: false.globalvoice: {
active: false,
apiUrl: process.env.GLOBAL_VOICE_API_URL,
apiKey: process.env.GLOBAL_VOICE_API_KEY,
},
invite — Invite Tracker
invite: { active: true },
Tracks which Discord invite link was used when a new member joins. Enables /invite commands to view invite leaderboards and stats.
image — Image Storage
active: false if you have not set this up.image: {
active: false,
storageUrl: process.env.KYTHIA_IMAGE_STORAGE_URL,
apiKey: process.env.KYTHIA_IMAGE_STROAGE_API_KEY,
},
| Field | Description |
|---|---|
storageUrl |
The base URL of your deployed Kythia Storage instance |
apiKey |
The API key configured on your storage server |
leveling — XP & Rank Cards
leveling: {
active: true,
backgroundUrl: 'https://placehold.co/800x250.png',
},
backgroundUrl
The background image for the /rank card. Replace the placeholder with your own hosted image.
- Recommended size:
800 × 250 px - Format: PNG or JPG
- Host on: Cloudflare Images, ImageKit, Imgur (permanent link), or your own CDN
music — Lavalink Music Player
music: {
active: true,
defaultPlatform: 'ytsearch',
useAI: true,
playlistLimit: 3,
autocompleteLimit: 5,
suggestionLimit: 7,
lavalink: {
hosts: process.env.LAVALINK_HOSTS || 'localhost',
ports: process.env.LAVALINK_PORTS || '2333',
passwords: process.env.LAVALINK_PASSWORDS || 'youshallnotpass',
secures: process.env.LAVALINK_SECURES || 'false',
},
spotify: {
clientId: process.env.SPOTIFY_CLIENT_ID,
clientSecret: process.env.SPOTIFY_CLIENT_SECRET,
},
artworkUrlStyle: 'banner',
},
defaultPlatform
The source used when a user searches by text (not a URL).
| Value | Source |
|---|---|
'ytsearch' |
YouTube |
'scsearch' |
SoundCloud |
playlistLimit
Max number of custom playlists a user can save.
autocompleteLimit
Number of results shown in /music play autocomplete dropdown.
suggestionLimit
Number of related songs shown on the Now Playing embed.
artworkUrlStyle
How the song artwork is displayed.
| Value | Description |
|---|---|
'thumbnail' |
Small square thumbnail |
'banner' |
Large banner image at the top of embed |
Lavalink Setup
Lavalink is a separate audio server that handles all music streaming. You must run at least one Lavalink node.
Required Lavalink plugins:
lavasrc-plugin— Spotify, Apple Music, Deezer supportyoutube-plugin— YouTube streaminglavasearch-plugin— Search autocompletesponsorblock-plugin— Skip sponsored segments
For multiple Lavalink nodes, use comma-separated values:
LAVALINK_HOSTS=node1.example.com,node2.example.com
LAVALINK_PORTS=2333,2334
LAVALINK_PASSWORDS=pass1,pass2
LAVALINK_SECURES=false,true
Spotify Setup
How to get Spotify API credentials:
.env:SPOTIFY_CLIENT_ID=your_client_id
SPOTIFY_CLIENT_SECRET=your_client_secret
pet — Virtual Pet System
pet: {
active: true,
useCooldown: 28800, // 8 hours — how often users can interact with their pet
gachaCooldown: 3600, // 1 hour — how often users can pull the pet gacha
},
pro — Cloudflare Subdomain Manager
Allows users to claim their own subdomains (e.g., username.kyth.me) via bot commands.
pro: {
active: false,
cloudflare: {
token: process.env.CLOUDFLARE_API_TOKEN,
zoneId: process.env.CLOUDFLARE_ZONE_ID,
domain: process.env.CLOUDFLARE_DOMAIN,
},
maxSubdomains: 5,
},
How to set up Cloudflare:
.env:CLOUDFLARE_API_TOKEN=your_token
CLOUDFLARE_ZONE_ID=your_zone_id
CLOUDFLARE_DOMAIN=kyth.me
| Field | Description |
|---|---|
token |
A scoped DNS:Edit API token (NOT the Global API Key) |
zoneId |
The Zone ID from your domain's Cloudflare overview page |
domain |
Your root domain (e.g., kyth.me) |
maxSubdomains |
Max subdomains one user can create |
server — Server Management Tools
server: { active: true },
Enables /server autobuild, /server backup, /server restore, and other server structure tools.
streak — Daily Streaks
streak: { active: true },
Tracks users' daily activity streaks. Users who interact every day maintain their streak.
suggestion — Suggestion Board
suggestion: { active: true },
Enables the /suggest command, letting users submit suggestions to a configured channel with upvote/downvote reactions.
ticket — Support Ticket System
ticket: { active: true },
Enables the full ticket system: panel creation, private ticket channels, transcript export, and staff assignment.
quest — Quest System
quest: {
active: false,
scheduler: '*/30 * * * *',
apiUrls: 'http://.../quests,http://...',
},
V. Webhooks & Top.gg (api — top-level)
This is a separate api key at the root config level (outside of addons). It configures Discord webhooks and Top.gg vote tracking.
api: {
webhookGuildInviteLeave: process.env.WEBHOOK_GUILD_INVITE_LEAVE,
webhookErrorLogs: process.env.WEBHOOK_ERROR_LOGS,
topgg: {
authToken: process.env.TOPGG_AUTH_TOKEN,
apiKey: process.env.TOPGG_API_KEY,
},
webhookVoteLogs: process.env.WEBHOOK_VOTE_LOGS,
},
How to create a Discord Webhook:
.env| Field | Description |
|---|---|
webhookGuildInviteLeave |
Notified when the bot joins or leaves a server |
webhookErrorLogs |
Notified on unhandled errors (works together with settings.webhookErrorLogs: true) |
topgg.authToken |
The auth token you set in the Top.gg webhook settings for your bot |
topgg.apiKey |
Your Top.gg API key for checking if a user has voted |
webhookVoteLogs |
Notified when a user votes for your bot on Top.gg |
VI. Miscellaneous Settings (settings)
Logging
logConsoleFilter: 'all', // 'all' or e.g. 'warn,error,info,debug'
logFormat: 'HH:mm:ss', // Timestamp format — see: https://date-fns.org/v4.1.0/docs/format
logConsoleFilter value |
What's shown |
|---|---|
'all' |
Everything |
'warn,error' |
Only warnings and errors |
'info' |
Only info messages |
Links
supportServer: 'https://dsc.gg/kythia',
inviteLink: `https://discord.com/oauth2/authorize?client_id=${process.env.DISCORD_BOT_CLIENT_ID}&scope=bot%20applications.commands&permissions=8`,
ownerWeb: 'https://kenndeclouv.me',
kythiaWeb: 'https://kythia.me',
statusPage: 'https://status.kythia.my.id',
| Field | Description |
|---|---|
supportServer |
Your Discord support server link — shown in help embeds |
inviteLink |
Bot invite link — auto-uses your Client ID from .env |
ownerWeb |
Your personal website — shown in /about |
kythiaWeb |
The bot's official website |
statusPage |
URL shown in /status command (e.g., an Uptime Kuma page) |
Banner Images
All banners default to placeholder images. Replace with your own hosted URLs.
- Recommended size:
800 × 300 px - Host on: Cloudflare Images, ImageKit, or any public CDN
| Field | Used in |
|---|---|
bannerImage |
General bot embeds |
voteBannerImage |
Vote reminder messages |
gcBannerImage |
Global Chat announcements |
statsBannerImage |
/stats command |
helpBannerImage |
/help command |
aboutBannerImage |
/about command |
tempvoiceBannerImage |
Temp voice control panel |
Webhooks Toggle
webhookErrorLogs: false, // true = send errors to the error logs webhook
webhookGuildInviteLeave: true, // true = notify when bot joins/leaves a server
Owner Privileges
ownerSkipCooldown: true, // Bot owner bypasses all command cooldowns (economy, pet, etc.)
AutoMod Thresholds
These values control Kythia's built-in AutoMod detection engine.
| Field | Default | Description |
|---|---|---|
spamThreshold |
7 |
Max messages in the fastTimeWindow before spam is detected |
duplicateThreshold |
5 |
Max identical messages in duplicateTimeWindow before flagging |
mentionThreshold |
4 |
Max @mentions allowed in a single message |
fastTimeWindow |
40000 (40s) |
Time window in ms for spam detection |
duplicateTimeWindow |
900000 (15min) |
Time window in ms for duplicate detection |
cacheExpirationTime |
900000 (15min) |
How long AutoMod internal cache stays alive |
shortMessageThreshold |
5 |
Messages shorter than this character count are considered "short" |
punishmentCooldown |
1000 (1s) |
Minimum ms between AutoMod punishments per user |
antiAllCapsMinLength |
15 |
Only check ALL CAPS on messages longer than this |
antiAllCapsRatio |
0.7 |
Flag if 70%+ of characters are uppercase |
antiEmojiMinTotal |
11 |
Only check emoji ratio on messages with 11+ characters |
antiEmojiRatio |
0.8 |
Flag if 80%+ of message is emojis |
antiZalgoMin |
8 |
Flag if 8+ Zalgo (corrupted text) characters are found |
VII. Emojis (emojis)
All button emojis used by the bot's interactive components. You can use:
- Default Unicode emoji:
'▶️' - Custom server emoji:
'<:name:id>'
How to get a custom emoji ID: Type \:emojiname: in any Discord message and send it. The raw format <:name:id> will appear.
Music Player Emojis
emojis: {
music: {
playPause: '⏯️',
play: '▶️',
pause: '⏸️',
skip: '⏭️',
stop: '⏹️',
loop: '🔁',
autoplay: '🎶',
lyrics: '📝',
queue: '📜',
shuffle: '🔀',
filter: '🎚️',
favorite: '❤️',
back: '⏮️',
},
Temp Voice Control Panel Emojis
tempvoice: {
rename: '⌨️',
limit: '👥',
privacy: '🛡️',
waiting: '⏲️',
stage: '🎙️',
trust: '🤝',
untrust: '✂️',
invite: '📞',
kick: '👢',
region: '🌐',
block: '🚫',
unblock: '🟢',
claim: '👑',
transfer: '🔁',
delete: '🗑️',
},
},