Documentation Index
Fetch the complete documentation index at: https://mintlify.com/noskap/kojima-bot/llms.txt
Use this file to discover all available pages before exploring further.
Kojima Bot stores all persistent state — channel spawn configuration, per-server player profiles, and achievement records — in a single SQLite file. By default this file is named bot.sqlite and is created in the working directory automatically on first run. The database layer is managed by Drizzle ORM, which provides type-safe queries and a schema-push workflow suited for self-hosted bots.
Tables
users
A minimal global cache of Discord usernames, populated whenever the bot resolves a user.
| Column | Type | Notes |
|---|
id | text | Primary key (Discord user ID) |
username | text | Discord username, defaults to "" |
channels
Per-channel spawn configuration and live spawn state. One row per channel that has been set up with /kojima setup.
| Column | Type | Notes |
|---|
id | text | Primary key (Discord channel ID) |
guild_id | text | Discord server ID |
cat | text | Message ID of the active spawn, or "0" if none |
spawn_times_min | integer | Minimum seconds between spawns (default 60) |
spawn_times_max | integer | Maximum seconds between spawns (default 450) |
lastcatches | integer | Unix timestamp of the last catch |
yet_to_spawn | integer | Unix timestamp when the next spawn is scheduled |
forcespawned | boolean | Whether the current spawn was force-triggered |
cattype | text | Rarity display name of the current spawn |
appear | text | Spawn appearance message ID |
cought | text | Catch confirmation message ID |
webhook | text | Webhook URL for the channel (if configured) |
cat_rains | integer | Rain event counter |
rain_should_end | integer | Unix timestamp when the rain event ends |
last_catcher_id | text | Discord user ID of the last catcher |
last_catcher_name | text | Display name of the last catcher |
last_catch_rarity | text | Rarity display name of the last caught spawn |
profiles
Per-server player statistics. Each (user_id, guild_id) pair is unique — a player has a separate profile in every server the bot runs in.
| Column group | Columns |
|---|
| Identity | id (autoincrement PK), user_id, guild_id |
| Catch stats | total_catches, total_catch_time, time (best catch seconds), timeslow (worst catch seconds), funny |
| Rarity counts | cat_Fine, cat_Nice, cat_Good, cat_Rare, cat_Wild, cat_Baby, cat_Epic, cat_Sus, cat_Brave, cat_Rickroll, cat_Reverse, cat_Superior, cat_Trash, cat_Legendary, cat_Mythic, cat_8bit, cat_Corrupt, cat_Professor, cat_Divine, cat_Real, cat_Ultimate, cat_eGirl |
| Gambling | roulette_balance (starts at 100), gambles, slot_spins, slot_wins, slot_big_wins, roulette_wins, roulette_spins, flip_plays |
| Gifting | cats_gifted, cat_gifts_recieved |
There is a unique index on (user_id, guild_id) — profiles_user_guild.
achievement_unlocks
Records which achievements each player has unlocked, with a timestamp.
| Column | Type | Notes |
|---|
id | integer | Autoincrement primary key |
user_id | text | Discord user ID |
guild_id | text | Discord server ID |
key | text | Achievement identifier (see src/lib/achievements.ts) |
unlocked_at | integer | Unix timestamp of when the achievement was unlocked |
A unique index on (user_id, guild_id, key) — achievement_user_guild_key — prevents duplicate unlock records.
Migrations
Drizzle Kit manages schema evolution. The schema source of truth is src/db/schema.ts; generated migration SQL files are stored in drizzle/.
| Command | What it does |
|---|
bun run db:push | Pushes the current schema directly to bot.sqlite — the simplest way to apply changes during development without generating migration files |
bun run db:studio | Opens Drizzle Studio in your browser — a visual table editor for inspecting and editing rows live |
The Drizzle config (drizzle.config.ts) points at ./src/db/schema.ts as the schema source and bot.sqlite as the target database.
Auto-migration on startup
When src/db/index.ts is first imported at process startup, it immediately calls ensureSqliteSchema() before the bot even logs in to Discord. This function uses SQLite’s PRAGMA table_info to check for missing columns and issues ALTER TABLE … ADD COLUMN statements for any that are absent. The separate initDB() function that is called on the ClientReady event only logs a confirmation message — the schema check has already completed by that point.
This mechanism protects against no column named … errors when upgrading an existing deployment from an older schema — you do not need to manually run migrations for additive column changes. The auto-migration currently covers all columns in channels, profiles, and the creation of the achievement_unlocks table if it does not exist.
Resetting the database
To wipe all data and start fresh:
- Stop the bot.
- Delete
bot.sqlite from the working directory.
- Re-create the schema:
bun run db:push
- Start the bot again.
pm2 stop kojima-bot
rm bot.sqlite
bun run db:push
pm2 start ecosystem.config.cjs
Changing the database file path
Set DB_FILE in .env to an absolute or relative path to use a different file location:
# .env
DB_FILE=/data/kojima/state.sqlite
Always stop the bot before deleting bot.sqlite. Deleting the file while the process is running may corrupt the file or cause unrecoverable write errors.
Use bun run db:studio to browse data during development — it opens a browser-based table editor where you can inspect profiles, channel state, and achievement records without writing any SQL.