My name Isobel
Married to myself
My love Isobel
Living by herself
In a heart full of dust
Lives a creature called lust
It surprises and scares
Like me, like me
My name Isobel
Married to myself
My love Isobel
Living by herself
ISOBEL is a highly-opinionated midwestern, now German claimed (same thing really), self-hosted Discord music bot that doesn't suck. It's made for small to medium-sized Discord servers/guilds (think about a group the size of you, your friends, and your friend's friends).
The original author of the bot is codetheweb with the original code for muse found here and I cannot thank him enough for the inspiration and foundation he laid.
Thus I claim the same: This discord bot is one that doesn't suck.
There are a lot of changes made since Max Isom's original version. First of all, this bot does not depend on YouTube or Spotify for music streaming. Instead, it uses its own music api, we just call it the ominous music Songbird API. (Formerly starchild music api that's why you might find references in code or docs)
Yes, it is more of a black box experience now than before, but with spotify and youtube being so unreliable for music streaming, this was the only way to go. Sorry Max. The second big change is that this bot is coming with its own web interface for configuration and settings management but this is work in progress. See ./web/README.md.
OTHERWISE, ISOBEL works like before, you /play songs, /file uploads, /skip, /pause, /resume, /seek, etc.
- 🎵 High-Quality Audio: 320kbps MP3 source with 192kbps Opus output for crystal-clear sound
- ⏹️ Animated Progress Bar: Real-time updating progress bars in Discord embeds
- 🎥 Livestream Support: Stream HLS live audio feeds
- ⏩ Seeking: Seek to any position within a song
- 💾 Advanced Caching: Local MP3 caching for instant playback and better performance
- 📋 No Vote-to-Skip: This is anarchy, not a democracy
- 🎶 Songbird API: Streams directly from the Songbird Music API (no YouTube or Spotify required)
↗️ Custom Shortcuts: Users can add custom shortcuts (aliases) for quick access- 1️⃣ One Song Per Command: Predictable queue management - one song per
/playcommand - 🔄 Smart Skipping: Skip only works when more songs are queued - no errors at end of queue
- 🔊 Volume Management: Normalizes volume across tracks with automatic ducking when people speak
- 🌐 Web Interface: Optional web UI for managing settings and favorites
- ✍️ TypeScript: Written in TypeScript with full type safety, easily extendable
- ❤️ Loyal Packers fan
- Quick Start
- Prerequisites
- Environment Variables
- Running with Docker
- Running with Node.js
- Database Setup
- Web Interface
- Health Checks
- Development
- Configuration
- Troubleshooting
- License
The fastest way to get ISOBEL running:
# 1. Clone the repository
git clone --recursive https://github.com/soulwax/ISOBEL.git
cd ISOBEL
# 2. Copy environment template
cp .env.example .env
# 3. Edit .env with your credentials (required!)
# You MUST set: DISCORD_TOKEN, SONGBIRD_BASE_URL, SONGBIRD_API_KEY, DATABASE_URL
# 4. Run with Docker (recommended)
docker compose up -d --build
# OR run with Node.js
pnpm install
pnpm build
pnpm startAccess your bot:
- Bot will log an invite URL - use it to add ISOBEL to your server
- Health check: http://localhost:3002/health
- Web interface (if enabled): http://localhost:3001
-
Discord Bot Token
- Create at Discord Developer Portal
- Create a "New Application" → Go to "Bot" → Copy token
-
Songbird Music API
- ISOBEL requires a Songbird API instance for music streaming
- Set up your own instance or use a hosted service
- You'll need the base URL and API key
-
PostgreSQL Database (NEW - REQUIRED!)
-
64-bit Operating System
- Required for audio processing
- Docker 20.10+
- Docker Compose v2+
- Node.js 20.x or later (24.x recommended)
- pnpm 10.x or later (via Corepack)
- ffmpeg 4.1 or later
- PM2 (installed automatically)
ISOBEL requires several environment variables to run. Copy .env.example to .env and configure:
cp .env.example .envThese variables are REQUIRED for ISOBEL to start:
# Discord Bot Configuration
DISCORD_TOKEN=your-discord-bot-token-here
# Songbird Music API
SONGBIRD_BASE_URL=https://your-songbird-api-url
SONGBIRD_API_KEY=your-songbird-api-key
# PostgreSQL Database (REQUIRED!)
DATABASE_URL=postgresql://user:password@host:5432/isobel?sslmode=requireNeon (recommended):
DATABASE_URL=postgresql://user:pass@ep-cool-darkness-123456.us-east-2.aws.neon.tech/isobel?sslmode=requireSupabase:
DATABASE_URL=postgresql://postgres:pass@db.projectref.supabase.co:5432/postgres?sslmode=requireLocal PostgreSQL:
DATABASE_URL=postgresql://postgres:password@localhost:5432/isobel# Bot Data and Cache
DATA_DIR=./data
CACHE_LIMIT=2GB
HEALTH_PORT=3002
# Bot Presence
BOT_STATUS=online # Options: online, idle, dnd
BOT_ACTIVITY_TYPE=LISTENING # Options: PLAYING, LISTENING, WATCHING, STREAMING
BOT_ACTIVITY=music
# BOT_ACTIVITY_URL= # Required ONLY if BOT_ACTIVITY_TYPE=STREAMING
# SponsorBlock Integration (optional)
ENABLE_SPONSORBLOCK=false
SPONSORBLOCK_TIMEOUT=5
# Advanced Configuration
# SONGBIRD_NEXT_URL= # Alternative Songbird API URL
# REGISTER_COMMANDS_ON_BOT=false # Global vs per-guild command registration
NODE_ENV=production # Usually set by PM2/Docker automaticallyOnly needed if you want to use the web UI:
# Discord OAuth (for web login)
DISCORD_CLIENT_ID=your-discord-oauth-client-id
DISCORD_CLIENT_SECRET=your-discord-oauth-client-secret
# Auth.js Configuration (NEXTAUTH_* env names)
NEXTAUTH_SECRET=your-random-secret-here # Generate with: openssl rand -base64 32
NEXTAUTH_URL=http://localhost:3001 # Or your public domain
# Web Service Ports
WEB_PORT=3001 # Web interface
# API_PORT=3003 # Dev only: API server when using pnpm web:dev:all
# Note: HEALTH_PORT (3002) is for bot health checksBefore starting ISOBEL, validate your environment:
# Check environment variables
pnpm verify:env
# Test database connection
pnpm verify:db
# Check health (after starting)
pnpm healthDocker is the recommended deployment method. ISOBEL can be deployed in two configurations:
Using Docker Compose:
# Start the bot
docker compose up -d --build
# View logs
docker compose logs -f bot
# Check health
curl http://localhost:3002/health
# Stop the bot
docker compose downUsing Docker Run:
docker run -d \
--name isobel-bot \
-v "$(pwd)/data":/data \
-p 3002:3002 \
-e DISCORD_TOKEN='your-discord-token' \
-e SONGBIRD_API_KEY='your-songbird-api-key' \
-e SONGBIRD_BASE_URL='https://your-api-url' \
-e DATABASE_URL='postgresql://user:password@host:5432/isobel?sslmode=require' \
--restart unless-stopped \
ghcr.io/soulwax/ISOBEL:latestPrerequisites:
- Create Discord OAuth Application (guide)
- Generate Auth.js secret:
openssl rand -base64 32 - Update
.envwith web variables (see Environment Variables)
Start all services:
# Start bot + web interface (single web process: frontend + API + auth)
docker compose -f docker-compose.yml -f docker-compose.web.yml up -d --build
# View logs for all services
docker compose -f docker-compose.yml -f docker-compose.web.yml logs -f
# Check health
curl http://localhost:3002/health # Bot
curl http://localhost:3001/health # Web
curl http://localhost:3001/health # Web (API + frontend)
# Stop all services
docker compose -f docker-compose.yml -f docker-compose.web.yml downServices included:
- bot (port 3002) - Discord music bot
- web (port 3001) - Web interface
- web (port 3001) - Web UI, API, and Discord auth (single process)
# Update to latest version
docker compose pull
docker compose up -d
# Rebuild from source and replace containers
docker compose up -d --build --force-recreate
# View container status
docker compose ps
# Restart services
docker compose restart
# Remove everything (keeps data volume)
docker compose down
# Remove everything INCLUDING data (CAUTION!)
docker compose down -vIf you change .env, docker compose build by itself is not enough. It rebuilds the image, but it does not replace the running container. Use docker compose restart for runtime-only env changes, or docker compose up -d --build --force-recreate after changing ports or other Compose-level settings. Docker Compose reads .env automatically, not .env.local.
ghcr.io/soulwax/ISOBEL:latest- Latest releaseghcr.io/soulwax/ISOBEL:2- Version 2.x.xghcr.io/soulwax/ISOBEL:2.12- Version 2.12.xghcr.io/soulwax/ISOBEL:2.12.2- Exact version
For running ISOBEL directly with Node.js on your host machine.
# 1. Clone repository with web submodule
git clone --recursive https://github.com/soulwax/ISOBEL.git
cd ISOBEL
# 2. Install dependencies
pnpm install
# 3. Configure environment
cp .env.example .env
# Edit .env with your values
# 4. Set up database (first time only)
pnpm prisma:migrate:deploy
# 5. Build and start
pnpm build
pnpm startTo run both bot and web interface on a single machine without Docker:
# 1. Install all dependencies
pnpm install -r
# 2. Build everything
pnpm build:all
# 3. Start all services with PM2
pnpm start:all:prod
# 4. Check status
pm2 status
# 5. View logs
pnpm logs:allYour services will be available at:
- Bot health: http://localhost:3002/health
- Web interface: http://localhost:3001
- Web (API + auth): http://localhost:3001
# Start services
pnpm start # Bot only
pnpm pm2:start:prod # Bot only (explicit)
pnpm web:pm2:start:prod # Web only
pnpm start:all:prod # Bot + Web + Auth
# Stop services
pnpm pm2:stop # Bot only
pnpm web:pm2:stop # Web only
pnpm stop:all # Everything
# Restart services
pnpm pm2:restart # Bot only
pnpm web:pm2:restart # Web only
pnpm restart:all # Everything
# View logs
pnpm pm2:logs # Bot logs
pnpm web:pm2:logs:web # Web logs
pnpm web:pm2:logs:web # Web logs
pnpm logs:all # All logs
# View status
pm2 status # All PM2 processes
pm2 monit # Real-time monitoring
# Reset PM2 (nuclear option)
pnpm pm2:reset # Stops and deletes all processes# Bot only (with hot reload)
pnpm dev
# Web only (with hot reload)
pnpm web:dev:all
# Both bot and web (with hot reload)
pnpm dev:all# Quick deployment
pnpm deploy # Builds and starts everything
# Or step by step
pnpm build:all # Build bot and web
pnpm start:all:prod # Start with PM2
pm2 save # Save PM2 process list
pm2 startup # Enable PM2 on system bootISOBEL requires a PostgreSQL database. The database is used to store:
- Guild (server) settings
- User favorites and shortcuts
- Queue history
- Web authentication sessions
Neon (Free tier available):
- Create account at neon.tech
- Create a new project
- Copy the pooled connection string for runtime traffic
- Copy the direct connection string for migrations
- Add to
.env:DATABASE_URL=postgresql://...DATABASE_URL_UNPOOLED=postgresql://...
Supabase (Free tier available):
- Create account at supabase.com
- Create a new project
- Go to Settings → Database → Connection String
- Copy the connection pooler URL for
DATABASE_URL - Copy the direct connection URL for
DATABASE_URL_UNPOOLED - Add both to
.env
Railway:
- Create account at railway.app
- Create PostgreSQL database
- Copy DATABASE_URL from variables
- Add to
.env
# Docker PostgreSQL
docker run -d \
--name isobel-postgres \
-e POSTGRES_PASSWORD=yourpassword \
-e POSTGRES_DB=isobel \
-p 5432:5432 \
-v isobel-db:/var/lib/postgresql/data \
postgres:16-alpine
# Then set in .env:
DATABASE_URL=postgresql://postgres:yourpassword@localhost:5432/isobelISOBEL automatically runs migrations on startup, but you can run them manually:
# Run pending migrations
pnpm prisma:migrate:deploy
# Check migration status
pnpm db:status
# Reset database (CAUTION: deletes all data!)
pnpm db:reset
# Generate Prisma client after schema changes
pnpm prisma:generateIf your provider gives you both pooled and direct PostgreSQL URLs, use:
DATABASE_URL=postgresql://pooled-runtime-url
DATABASE_URL_UNPOOLED=postgresql://direct-migrations-urlISOBEL uses DATABASE_URL_UNPOOLED for Prisma CLI migrations and DATABASE_URL for the running bot.
# Test database connection
pnpm verify:db
# This checks:
# - DATABASE_URL is valid
# - PostgreSQL connection works
# - Database is accessible
# - Migrations are up to dateThe web interface provides a modern UI for managing ISOBEL settings, favorites, and more.
1. Create Discord OAuth Application:
- Go to Discord Developer Portal
- Create new application (or use existing bot application)
- Go to OAuth2 → General
- Add redirect URL:
http://your-domain:3001/api/auth/callback/discord - Copy Client ID and Client Secret
2. Generate Auth.js Secret:
openssl rand -base64 323. Configure Environment:
Add to your .env file:
# Discord OAuth
DISCORD_CLIENT_ID=your-client-id
DISCORD_CLIENT_SECRET=your-client-secret
# Auth.js
NEXTAUTH_SECRET=your-generated-secret
NEXTAUTH_URL=http://localhost:3001 # Or your public domain
# Optional
WEB_PORT=3001
API_PORT=30034. Start Web Interface:
With Docker:
docker compose -f docker-compose.yml -f docker-compose.web.yml up -d --buildWith Node.js:
pnpm install -r
pnpm build:all
pnpm start:all:prod5. Access:
- Open http://localhost:3001
- Click "Login with Discord"
- Authorize the application
- You're in!
- 📊 Dashboard: View bot status and active guilds
- 🎵 Now Playing: See what's playing across all servers
- ⭐ Favorites: Manage favorite songs and playlists
- ⚙️ Settings: Configure bot behavior per guild
- 📜 Queue History: View playback history
- 👥 User Management: See who's using the bot
ISOBEL includes health check endpoints for monitoring:
Endpoint: http://localhost:3002/health
# Check bot health
curl http://localhost:3002/health
# Or use pnpm script
pnpm healthResponse:
{
"status": "ok",
"uptime": 123456,
"timestamp": "2024-01-01T00:00:00.000Z",
"version": "2.12.0"
}Endpoint: http://localhost:3001/health
# Check web health
curl http://localhost:3001/health
# Or use pnpm script
pnpm health:webDocker health checks:
- Automatically configured in docker-compose files
- Check with:
docker compose ps
Monitoring:
- Use with uptime monitoring services (UptimeRobot, Pingdom, etc.)
- Set up alerts for when health checks fail
Reverse Proxy:
# Nginx example
location /health {
proxy_pass http://localhost:3002/health;
}ISOBEL consists of two projects:
ISOBEL/
├── src/ # Bot source code
│ ├── bot.ts # Main bot entry point
│ ├── commands/ # Discord slash commands
│ ├── services/ # Business logic (DI services)
│ ├── managers/ # Player, queue, cache managers
│ └── utils/ # Utility functions
├── web/ # Web interface (git submodule)
│ ├── src/ # Web source code
│ ├── public/ # Static assets
│ └── auth-server/ # Auth server
├── prisma/ # Database schema
└── ecosystem.config.cjs # PM2 configuration
1. Clone with submodules:
git clone --recursive https://github.com/soulwax/ISOBEL.git
cd ISOBEL2. Install dependencies:
pnpm install # Bot dependencies
pnpm --filter isobel-web install # Web dependencies (optional)3. Set up environment:
cp .env.example .env
# Edit .env with your values4. Run database migrations:
pnpm prisma:migrate:dev5. Start development server:
# Bot only
pnpm dev
# Web only
pnpm web:dev:all
# Both (recommended for full-stack development)
pnpm dev:all# Code Quality
pnpm lint # Lint bot code
pnpm lint:fix # Auto-fix bot code
pnpm lint:all # Lint bot + web
pnpm lint:fix:all # Auto-fix bot + web
pnpm typecheck # Type check bot
pnpm typecheck:all # Type check bot + web
# Database
pnpm prisma:studio # Open Prisma Studio (database GUI)
pnpm prisma:migrate:dev # Create new migration
pnpm prisma:generate # Generate Prisma client
# Building
pnpm build # Build bot only
pnpm build:all # Build bot + web
# Utilities
pnpm verify:env # Validate environment variables
pnpm verify:db # Test database connectionAdding a new Discord command:
- Create file in
src/commands/ - Extend
BaseCommandclass - Implement
execute()method - Bot auto-discovers new commands
Modifying database schema:
- Edit
prisma/schema.prisma - Run
pnpm prisma:migrate:dev - Name your migration
- Run
pnpm prisma:generate
Working on web interface:
cd web- Make changes in
web/src/ - Changes auto-reload in dev mode
- See web/README.md for details
The web interface is a git submodule. To update it:
# Pull latest web changes
git submodule update --remote web
# Or initialize if missing
git submodule update --init --recursiveISOBEL uses advanced local MP3 caching for better performance.
Configure cache size:
CACHE_LIMIT=2GB # Default
CACHE_LIMIT=512MB # Smaller
CACHE_LIMIT=10GB # LargerCache location:
- Docker:
/data/file-cache/ - Node.js:
./data/file-cache/
Clear cache:
# Docker
docker compose exec bot rm -rf /data/file-cache/*
# Node.js
rm -rf ./data/file-cache/*Examples:
Listening to music:
BOT_STATUS=online
BOT_ACTIVITY_TYPE=LISTENING
BOT_ACTIVITY=musicWatching a movie:
BOT_STATUS=dnd
BOT_ACTIVITY_TYPE=WATCHING
BOT_ACTIVITY=a movieStreaming on Twitch:
BOT_STATUS=online
BOT_ACTIVITY_TYPE=STREAMING
BOT_ACTIVITY=Monstercat
BOT_ACTIVITY_URL=https://www.twitch.tv/monstercatAutomatically skip non-music segments:
ENABLE_SPONSORBLOCK=true
SPONSORBLOCK_TIMEOUT=5Configure automatic volume reduction when people speak:
/config set-reduce-vol-when-voice true
/config set-reduce-vol-when-voice-target 70
Problem: Bot won't start, complains about missing variables.
Solution:
# Check what's missing
pnpm verify:env
# Make sure these are in .env:
# - DISCORD_TOKEN
# - SONGBIRD_BASE_URL
# - SONGBIRD_API_KEY
# - DATABASE_URLProblem: Can't connect to PostgreSQL.
Solution:
# Test database connection
pnpm verify:db
# Common issues:
# - Wrong DATABASE_URL format
# - Database server not running
# - Firewall blocking connection
# - Wrong credentials
# DATABASE_URL format:
postgresql://username:password@host:port/database?sslmode=requireProblem: Web interface submodule not initialized.
Solution:
git submodule update --init --recursive
pnpm --filter isobel-web installProblem: Can't stop or restart PM2 processes.
Solution:
# Nuclear option - reset everything
pnpm pm2:reset
# Then start fresh
pnpm start:all:prodProblem: Bot is online but commands don't work.
Checklist:
- Check bot has proper permissions in Discord server
- Verify bot has "applications.commands" scope
- Re-invite bot with correct permissions
- Check logs:
docker compose logs botorpnpm pm2:logs
Problem: Can't start service, port is occupied.
Solution:
# Find what's using the port
lsof -i :3002 # Bot health
lsof -i :3001 # Web
lsof -i :3003 # Dev API server (when using web:dev:all)
# Change port in .env
HEALTH_PORT=3012
WEB_PORT=3011
API_PORT=3013Problem: Docker build error.
Solution:
# Clear Docker cache and rebuild
docker compose down
docker system prune -a
docker compose build --no-cache
docker compose up -dCheck logs:
# Docker
docker compose logs -f bot
docker compose logs -f web
# PM2
pnpm pm2:logs
pnpm logs:allEnable debug mode:
NODE_ENV=developmentReport issues:
- Check existing issues
- Create new issue with:
- ISOBEL version
- Node.js version
- Operating system
- Complete error logs
- Steps to reproduce
mainbranch - Development/bleeding edge (may be unstable)- Tags - Stable releases (recommended for production)
Use stable releases:
# List available versions
git tag
# Checkout specific version
git checkout v2.12.2- Web Interface Documentation
- CLAUDE.md - Development guidelines for Claude Code
- Discord Developer Portal
- Prisma Documentation
ISOBEL uses the Songbird Music API for all music streaming and searching. This means:
- ✅ No YouTube API keys required
- ✅ No Spotify credentials required
- ✅ Self-hosted or cloud-hosted API support
- ✅ High-quality audio streaming (320kbps MP3)
- ✅ Fast and reliable search
- ✅ Livestream support
You'll need to set up your own Music API instance or use a hosted service.
GPLv3 - see LICENSE file for details.