A Discord bot that connects your server to the Vaquill Legal AI engine. Members can ask legal questions and receive answers with source citations, multi-turn conversation memory, and interactive pagination -- all from within Discord.
- Overview
- Prerequisites
- Discord Bot Setup
- Quick Start (Local Development)
- Docker Deployment
- Cloud Deployment
- Commands
- Features
- Environment Variable Reference
- Troubleshooting
The bot forwards questions from Discord to the Vaquill API, which runs a retrieval-augmented generation (RAG) pipeline over Indian, US, and Canadian legal corpora. Answers come back with numbered source citations (cases, statutes, sections) that users can reveal with a button click. Conversation history is kept per-channel so follow-up questions work naturally.
Before you begin, make sure you have:
- A Discord account -- Sign up at discord.com if you do not have one.
- Administrator access to a Discord server -- You need the "Manage Server" permission to invite bots. Create your own server if needed (free).
- A Vaquill API key -- Sign up at vaquill.ai and generate an API key from your dashboard. Keys follow the format
vq_key_.... - Python 3.10 or higher -- Required for local development. Docker handles this automatically if you deploy with containers.
Follow these steps exactly to create a Discord application, configure the bot user, and invite it to your server.
- Go to the Discord Developer Portal.
- Click New Application in the top-right corner.
- Enter a name (e.g., "Vaquill Legal AI") and click Create.
- In the left sidebar of your new application, click Bot.
- Click Add Bot, then confirm with Yes, do it!.
- Under the bot's username, click Reset Token to generate a new token.
- Click Copy to copy the token. Save it somewhere safe -- you will need it for the
DISCORD_BOT_TOKENenvironment variable. You cannot view this token again after leaving the page.
This step is required. Without it, the bot cannot read message content and will silently ignore all commands.
- On the same Bot page, scroll down to Privileged Gateway Intents.
- Find Message Content Intent and toggle it ON.
- Click Save Changes at the bottom of the page.
- In the left sidebar, click OAuth2, then URL Generator.
- Under Scopes, check:
botapplications.commands
- Under Bot Permissions, check:
- Send Messages
- Embed Links
- Read Message History
- Use Slash Commands
- Add Reactions
- Copy the generated URL at the bottom of the page.
- Open the URL you copied in a browser.
- Select the server you want to add the bot to from the dropdown. You must have "Manage Server" permission on that server.
- Click Authorize and complete the CAPTCHA.
- The bot will appear in your server's member list (offline until you start it).
# Clone and enter the directory
git clone https://github.com/vaquill/integrations.git
cd integrations/discord-bot
# Create a virtual environment
python -m venv venv
source venv/bin/activate # macOS / Linux
# venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txt
# Configure environment variables
cp .env.example .envOpen .env in your editor and fill in the two required values:
DISCORD_BOT_TOKEN=your_discord_bot_token
VAQUILL_API_KEY=vq_key_your_api_key_hereStart the bot:
python bot.pyThe bot will log VaquillBot has connected to Discord! when it is ready. Go to your Discord server and type !help to verify.
docker build -t vaquill-discord-bot .
docker run -d --name vaquill-discord-bot --env-file .env vaquill-discord-botdocker logs -f vaquill-discord-botdocker stop vaquill-discord-bot
docker rm vaquill-discord-botCreate a docker-compose.yml alongside the Dockerfile:
version: "3.8"
services:
bot:
build: .
restart: unless-stopped
env_file:
- .envThen run:
docker compose up -d
docker compose logs -fRailway offers a simple Git-based deploy workflow.
- Sign up at railway.app.
- Install the CLI:
npm install -g @railway/cli
- Deploy:
cd discord-bot railway login railway init railway up - Set environment variables in the Railway dashboard under your service's Variables tab. Add
DISCORD_BOT_TOKENandVAQUILL_API_KEYat minimum. - Check logs:
railway logs
- Sign up at render.com.
- Create a New Web Service and connect your GitHub repository.
- Configure:
- Build Command:
pip install -r requirements.txt - Start Command:
python bot.py
- Build Command:
- Add
DISCORD_BOT_TOKENandVAQUILL_API_KEYunder Environment in the dashboard. - Deploy. Render auto-deploys on every push to the connected branch.
On any Linux VPS with Docker installed:
git clone https://github.com/vaquill/integrations.git
cd integrations/discord-bot
cp .env.example .env
nano .env # fill in your values
docker compose up -dFor systemd-based deployments without Docker, create a service file:
[Unit]
Description=Vaquill Discord Bot
After=network.target
[Service]
Type=simple
User=botuser
WorkingDirectory=/opt/vaquill-discord-bot
ExecStart=/opt/vaquill-discord-bot/venv/bin/python bot.py
Restart=always
RestartSec=10
EnvironmentFile=/opt/vaquill-discord-bot/.env
[Install]
WantedBy=multi-user.targetsudo cp vaquill-discord-bot.service /etc/systemd/system/
sudo systemctl enable vaquill-discord-bot
sudo systemctl start vaquill-discord-bot
# Check status
sudo systemctl status vaquill-discord-bot
sudo journalctl -u vaquill-discord-bot -f| Command | Aliases | Description |
|---|---|---|
!ask [question] |
!a, !q |
Ask a legal question. Supports follow-ups using channel conversation history. |
!starters |
!start, !questions |
Show starter questions as interactive buttons. Click a button to ask that question. |
!reset |
Clear the conversation history for the current channel. | |
!help |
Show the help menu with available commands. |
The command prefix defaults to ! and can be changed with the DISCORD_COMMAND_PREFIX environment variable.
When the Vaquill API returns source references (cases, statutes, sections), the bot adds a "Show Sources" button to the response. Clicking it reveals the list of cited sources. This can be disabled with ENABLE_SOURCES=False.
The bot maintains per-channel conversation history so you can ask follow-up questions without repeating context. History is capped at the most recent MAX_CHAT_HISTORY question/answer pairs (default: 20). Use !reset to clear history for the current channel.
Long responses are automatically split across pages. The bot sends an embedded message with Previous/Next buttons for navigation. Only the original requester can page through their response.
The !starters command shows a set of pre-configured legal questions as clickable buttons. Clicking a button sends that question through the same pipeline as !ask. Disable with ENABLE_STARTER_QUESTIONS=False.
Two independent limits are enforced:
- Per-user: Maximum queries per user within a sliding time window.
- Per-channel: Maximum queries per channel within the same window.
Limits use in-memory storage by default. Set REDIS_URL for persistent, distributed rate limiting across bot restarts or multiple instances.
Restrict the bot to specific channels or roles:
ALLOWED_CHANNELS: Comma-separated list of Discord channel IDs. If empty, all channels are allowed.ALLOWED_ROLES: Comma-separated list of Discord role IDs. If empty, all roles are allowed.
The bot shows a typing indicator while waiting for the Vaquill API response. Disable with TYPING_INDICATOR=False.
| Variable | Required | Default | Description |
|---|---|---|---|
DISCORD_BOT_TOKEN |
Yes | -- | Bot token from the Discord Developer Portal. |
VAQUILL_API_KEY |
Yes | -- | Vaquill API key (format: vq_key_...). |
VAQUILL_API_URL |
No | https://api.vaquill.ai/api/v1 |
Vaquill API base URL. Override for self-hosted or staging. |
VAQUILL_MODE |
No | standard |
RAG tier. standard for faster responses, deep for more thorough analysis. |
VAQUILL_COUNTRY_CODE |
No | (empty) | Jurisdiction filter: IN (India), US (United States), CA (Canada). Empty means all. |
DISCORD_COMMAND_PREFIX |
No | ! |
Character(s) that prefix bot commands. |
RATE_LIMIT_PER_USER |
No | 10 |
Maximum queries per user within the rate limit window. |
RATE_LIMIT_PER_CHANNEL |
No | 30 |
Maximum queries per channel within the rate limit window. |
RATE_LIMIT_WINDOW |
No | 60 |
Rate limit sliding window in seconds. |
MAX_CHAT_HISTORY |
No | 20 |
Maximum question/answer pairs retained per channel. |
REDIS_URL |
No | redis://localhost:6379 |
Redis connection URL. Only needed for distributed rate limiting. Falls back to in-memory if Redis is unavailable. |
ALLOWED_CHANNELS |
No | (empty) | Comma-separated Discord channel IDs. Empty allows all channels. |
ALLOWED_ROLES |
No | (empty) | Comma-separated Discord role IDs. Empty allows all roles. |
ENABLE_SOURCES |
No | True |
Show source citation buttons on responses. |
ENABLE_STARTER_QUESTIONS |
No | True |
Enable the !starters command. |
TYPING_INDICATOR |
No | True |
Show typing indicator while processing. |
- Verify
DISCORD_BOT_TOKENis correct. Regenerate it in the Developer Portal if unsure. - Check that
python bot.pyis running without errors. Look at the console or container logs. - If deploying on a cloud platform, confirm the service is not sleeping or out of free-tier hours.
- Message Content Intent not enabled. This is the most common cause. Go to Discord Developer Portal > your application > Bot > Privileged Gateway Intents and confirm Message Content Intent is toggled ON. Save changes and restart the bot.
- Check that you are using the correct prefix (default:
!). Type!helpexactly. - If
ALLOWED_CHANNELSorALLOWED_ROLESis set, make sure your channel/role is included.
This means Message Content Intent is not enabled. Follow the instructions in Step 3: Enable the Message Content Intent.
The bot needs these permissions in the channel: Send Messages, Embed Links, Read Message History. Either:
- Re-invite the bot using the URL from Step 4 which includes the correct permissions.
- Manually grant the permissions to the bot's role in Server Settings > Roles.
- Verify
VAQUILL_API_KEYis valid and has not been revoked. - Check that
VAQUILL_API_URLis reachable from the machine running the bot. - If using
VAQUILL_MODE=deep, confirm your API plan supports deep-tier queries.
Adjust RATE_LIMIT_PER_USER, RATE_LIMIT_PER_CHANNEL, or RATE_LIMIT_WINDOW in your .env file. For example, to allow 20 queries per user per 2 minutes:
RATE_LIMIT_PER_USER=20
RATE_LIMIT_WINDOW=120Redis is optional. If REDIS_URL points to an unavailable Redis instance, the bot falls back to in-memory rate limiting. To silence the warnings, either start a Redis server or remove the REDIS_URL variable from your .env.