Kevin is a modular, all-in-one Discord bot with a lightweight Telegram companion. Discord includes moderation, community, music, games, and utilities; Telegram focuses on OpenAI conversation and web-backed answers.
- Moderation: kick, ban/unban, softban/massban, timeout, purge, slowmode, channel locks, nicknames, role management, voice moderation, warnings, and case history.
- Automod: spam, invite, link, excessive-caps, mass-mention, and custom blocked-term filters, with moderator exemptions and action logging.
- Community: welcomes, goodbyes, autoroles, XP, ranks, leaderboards, polls, reminders, member/server info, timestamps, and a safe calculator.
- Economy: Kash wallet and bank balances, daily rewards, jobs, payments, admin
grants, robbery, a collectible shop, inventory, coin flips, dice, interactive blackjack
(
/blackjackor/bj), interactive craps (/craps) with pass/don't pass lines and true odds, and adventure-themed jungle slots. - Music: searches and URLs through yt-dlp, per-server queues, pause/resume, skip, loop, shuffle, volume, removal, and now-playing information.
- Support: private ticket channels, persistent open/close buttons, staff access controls, and text transcript export.
- Engagement: Twitch, YouTube, and TikTok live alerts, TikTok post alerts, button-entry giveaways, reaction roles, starboard highlights, suggestions, reusable tags, and AFK notices.
- Fun: interactive trivia with stats and leaderboards, 8-ball, dice notation, choices, rock-paper-scissors, jokes, compatibility, ratings, mock text, and social actions.
- AI mentions: ping K with a question for a short OpenAI answer with optional web search and clickable sources.
Every command is available as a slash command. Most also support the configurable text
prefix (default: k). Both k help and khelp work. Run /help after inviting K
for the live command list.
- Python 3.11 or newer (3.12 recommended)
- FFmpeg available on
PATHfor music - A Discord application and bot token
- A Telegram bot token from @BotFather for the Telegram bot
- The Server Members Intent and Message Content Intent enabled in the Discord developer portal
Discord.py's voice extra installs both PyNaCl and davey, which are required by the
current Discord voice protocol.
-
Create an application at the Discord Developer Portal, add a bot, and copy its token.
-
On the bot page, enable Server Members Intent and Message Content Intent.
-
Copy the environment template and insert the token:
cp .env.example .env
-
Install and run with uv:
uv sync --extra dev uv run k
Or use a regular virtual environment:
python3.12 -m venv .venv source .venv/bin/activate pip install -e '.[dev]' python -m kevin
-
Invite K using the OAuth2 URL Generator with the
botandapplications.commandsscopes. Start with Administrator while testing, then reduce permissions to those your enabled modules need. K can also generate its own permission-aware link with/invite.
The Telegram bot shares Kevin's OpenAI prompt, model setting, and automatic web-search
behavior. It searches when useful or explicitly requested and includes clickable source
citations when available. It does not port Discord-only moderation or music commands. In
a private chat, send Kevin any text. In a group, mention
@YourKevinBot or reply to one of Kevin's messages. Kevin keeps the 20 most recent
conversation turns per user and chat while the process is running; /reset clears them.
-
Message @BotFather, run
/newbot, and copy the bot token. -
Add the token to
.env:TELEGRAM_BOT_TOKEN=your-telegram-token -
To keep the bot private, start once with an empty allowlist, message Kevin
/id, then add the returned numeric ID to.envand restart. Multiple IDs are comma-separated; leaving it empty allows everyone:TELEGRAM_ALLOWED_USER_IDS=123456789 -
Start only Telegram:
uv run kevin-telegram
Or run Discord and Telegram together in one process:
uv run kevin-both
The original uv run k and uv run kevin commands still start only Discord. Telegram
uses long polling, so only one running Kevin process may use a given Telegram token.
For fast command updates during development, set KEVIN_TEST_GUILD_ID in .env to your
test server ID. Without it, commands sync globally and Discord may take time to display
changes.
Set the presence text and a Twitch or YouTube URL in .env, then restart K:
KEVIN_STATUS=with the community!
KEVIN_STREAM_URL=https://twitch.tv/yourchannel
When KEVIN_STREAM_URL is set, Discord shows K with the purple Streaming activity
and a Watch button that opens that URL. This setting does not need Twitch API
credentials; TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET are only for go-live alerts.
Put an OpenAI API key in .env, then restart K:
OPENAI_API_KEY=your-key-here
OPENAI_MODEL=gpt-5.6-luna
Anyone in a server can then ask a question by pinging the bot, for example
@K what's happening with the weather tomorrow?. Reply directly to one of K's messages
to ask a follow-up without pinging it again; K receives the previous reply as context.
K uses the Responses API and can search the web when useful. Replies are intentionally
short and include clickable source links when web search supplies citations. Each user
can ask once every five seconds, and at most three OpenAI requests run at once to keep
shared-key usage under control. The key stays server-side; never paste it into Discord
or Telegram, and never commit .env.
Recommended setup commands:
/config logs #mod-log
/config welcome #welcome Welcome {user} to {server}! Member #{count}.
/config goodbye #goodbye
/config autorole @Members
/automod enabled true
/automod filter spam true
/automod filter invites true
/ticket panel
/streamalert add twitch.tv/yourstreamer #stream-alerts @Live
/youtubealert add creator:@yourchannel destination:#stream-alerts role:@Live
/tiktokalert add creator:@yourcreator destination:#social-alerts live:true posts:true
Use /config and /automod without subcommands to inspect current settings. The bot's
role must be above any role it assigns or moderates.
Twitch alerts require a Twitch developer application. Create one in the
Twitch developer console, then put its credentials in
.env as TWITCH_CLIENT_ID and TWITCH_CLIENT_SECRET. Restart K and configure alerts:
/streamalert add streamer:yourstreamer channel:#stream-alerts role:@Live
/streamalert list
/streamalert remove streamer:yourstreamer
K checks Twitch once per minute and remembers the stream ID, so restarts and repeated
checks do not post duplicate alerts. A custom message can use {streamer}, {title},
{game}, {url}, and {role}.
Trivia needs no API key. Use /trivia play, /trivia stats, and
/trivia leaderboard; category and difficulty filters are optional.
Enable YouTube Data API v3 in Google Cloud, create an API key, and set
YOUTUBE_API_KEY in .env. After restarting K:
/youtubealert add creator:@yourchannel destination:#stream-alerts role:@Live
/youtubealert list
/youtubealert remove creator:@yourchannel
K checks the channel feed every three minutes and batches video status lookups to keep Data API quota usage low. Alerts are sent only while YouTube reports the video as live.
/tiktokalert add creator:@yourcreator destination:#social-alerts role:@Live live:true posts:true
/tiktokalert list
/tiktokalert remove creator:@yourcreator
Use live:false or posts:false when only one alert type is wanted. The first post
check saves the creator's newest post as a baseline and does not announce old content.
TikTok does not provide a general API for arbitrary creator live/post monitoring, so
these checks use yt-dlp against public pages and are best-effort. Private, region-locked,
age-gated, or bot-protected accounts may not work; YTDLP_COOKIE_FILE can help where an
authenticated session is required.
Music playback needs FFmpeg. On common platforms:
brew install ffmpeg # macOS
sudo apt install ffmpeg # Debian/UbuntuPlayback also needs the Opus library used by Discord voice. FFmpeg normally installs
it as a dependency. K searches common Homebrew and system locations automatically; set
OPUS_LIBRARY to the full library path if it is installed somewhere else.
Some media providers block datacenter IPs or require authentication. K supports a
Netscape-format cookie file through YTDLP_COOKIE_FILE; protect that file like a
password. Respect source terms and copyright rules.
K stores state in data/kevin.sqlite3 by default. SQLite WAL mode is enabled. Back
up the database file and its -wal companion while the bot is running, or stop the bot
before copying the main file. Change the location with KEVIN_DATABASE.
Never commit .env, cookies, the SQLite database, or a Discord token. If a token is
exposed, regenerate it immediately in the developer portal.
Useful checks:
uv run ruff check .
uv run pytest
uv run python -m compileall -q kevinEvery push to main runs linting, the test suite, and a compile check in GitHub
Actions. If all checks pass, the exact tested commit is deployed to the VPS and the
kevin.service user service is restarted. Deployments are serialized, so two quick
pushes cannot update the bot at the same time. The workflow can also be run manually
from the repository's Actions tab.
The VPS keeps runtime state outside Git: .env, data/, .venv/, bin/, and
vendor/ are preserved during deployment. Before each restart, the deploy script uses
SQLite's online backup API to save a consistent database copy under
data/backups/; the ten newest backups are retained.
The workflow expects these GitHub Actions secrets:
VPS_HOST VPS IP address or hostname
VPS_USER SSH account that owns the user service
VPS_SSH_KEY Dedicated private SSH key for deployments
VPS_KNOWN_HOSTS Pinned SSH host-key entry for the VPS
The service is installed at ~/.config/systemd/user/kevin.service and runs the
Discord and Telegram bots together from ~/apps/kevin. Useful VPS checks are:
systemctl --user status kevin.service
journalctl --user -u kevin.service -fkevin/
bot.py lifecycle, command loading, logging helpers
config.py environment configuration
database.py SQLite schema and atomic operations
cogs/ independent feature modules
utils/ shared parsing and presentation helpers
tests/ fast unit and database tests
This version is designed for one bot process and SQLite. For hundreds or thousands of servers, move member/economy state to PostgreSQL, cooldowns and music coordination to Redis, run Discord shards, and consider Lavalink for dedicated audio nodes. The cog and service boundaries are intentionally structured so those replacements do not require a command rewrite.