- TypeScript 99.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| data | ||
| src | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| bun.lock | ||
| docker-compose.yml | ||
| Dockerfile | ||
| index.ts | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
Kagi Discord Bot
A Discord bot that integrates with the Kagi API to provide powerful search capabilities directly within Discord.
Test the discord bot and kagi api in this server: https://discord.gg/km4rpZBZfM
Features
This bot provides slash commands to interact with Kagi API:
/fastgpt- Query the Kagi FastGPT API for AI-powered answers/ask- Let an OpenRouter/OpenAI-compatible LLM plan searches and craft an answer with citations/websearch- Search small-web and web results using the Kagi Search API/newssearch- Search news results using the Kagi Search API/summarize- Summarize URLs, text, or channel conversations using the Kagi Universal Summarizer API/search- Search Kagi with workflows, filters, lenses, personalization, and result extraction/extract- Extract markdown content from up to 10 URLs using the Kagi Extract API/limits- Check your remaining query limits
Prerequisites
- Discord Bot Token
- Kagi API Key
- OpenRouter (or another OpenAI-compatible) API key for
/ask - Docker and optionally Docker Compose
Setup
Environment Configuration
Create a .env file in the root directory with the following content:
# Discord Bot Token
DISCORD_TOKEN=your_discord_token_here
# Discord Client ID
CLIENT_ID=your_client_id_here
# Kagi API Key
KAGI_API_KEY=your_kagi_api_key_here
# LLM Provider (OpenRouter or any OpenAI-compatible API)
# Leave blank when using providers that do not require authentication (e.g., local Ollama)
LLM_API_KEY=your_llm_api_key_here
# LLM_API_BASE_URL=https://openrouter.ai/api/v1
LLM_MODEL=openrouter/auto
# ASK_MODEL=meta-llama/llama-3.1-8b-instruct:free
# ASK_REWRITE_MODEL=openai/gpt-4o-mini
# ASK_RESULTS_PER_QUERY=4
# ASK_MAX_TOTAL_RESULTS=8
# ASK_MAX_TOKENS=4000
# ASK_TEMPERATURE=1.0
# ASK_REWRITE_TEMPERATURE=0.2
# LLM_HTTP_REFERER=https://your-site.example
# LLM_APP_NAME=Kagi Discord Bot
# Message Content Intent (set to 'true' to enable channel summarization)
# Note: For bots in more than 100 servers, Discord requires verification
# and approval to use this intent. Set to 'false' for large-scale bots.
MESSAGE_CONTENT_ENABLED=true
# Allow Commands in Direct Messages (set to 'true' to allow commands in DMs)
ALLOW_DM_COMMANDS=false
# Allow the expensive Muriel engine ($1 per summary)
ALLOW_MURIEL_ENGINE=false
# Create threads for results when needing to send more than one message (set to 'true' to automatically create threads)
CREATE_THREADS_FOR_RESULTS=true
# Comma-separated list of Discord user IDs that have unlimited queries (bypass all limits)
UNLIMITED_QUERY_USERIDS=
# Query Limits Configuration
# Limits are per Discord user. Use -1 for unlimited.
# Available periods: hourly, daily, weekly, monthly
# Global query limit (applies to all commands combined)
QUERY_LIMIT_GLOBAL=50
QUERY_LIMIT_GLOBAL_PERIOD=daily
# Command-specific limits (optional)
QUERY_LIMIT_FASTGPT=20
QUERY_LIMIT_FASTGPT_PERIOD=daily
QUERY_LIMIT_WEBSEARCH=15
QUERY_LIMIT_WEBSEARCH_PERIOD=daily
QUERY_LIMIT_NEWSSEARCH=15
QUERY_LIMIT_NEWSSEARCH_PERIOD=daily
QUERY_LIMIT_SUMMARIZE=10
QUERY_LIMIT_SUMMARIZE_PERIOD=daily
QUERY_LIMIT_SEARCH=10
QUERY_LIMIT_SEARCH_PERIOD=daily
QUERY_LIMIT_ASK=10
QUERY_LIMIT_ASK_PERIOD=daily
QUERY_LIMIT_EXTRACT=10
QUERY_LIMIT_EXTRACT_PERIOD=daily
# Set to 'true' to persist query counts between bot restarts
QUERY_LIMITS_PERSIST=true
Using Docker
Option 1: Build and run using docker-compose
- Build and start the Docker container:
git clone https://github.com/0xgingi/kagi-discord-bot
cd kagi-discord-bot
docker compose up -d
To rebuild the container after code changes:
git pull
docker compose up -d --build
To view logs:
docker compose logs -f
To stop the container:
docker compose down
Option 2: Pull from Docker Hub
You can use the pre-built Docker image from Docker Hub:
- Create a
.envfile as described above - Create the
data/directory - Create the
data/query_record.jsonfile - Run the container:
docker run -d --name kagi-discord-bot --restart unless-stopped --env-file .env -v $(pwd)/data:/app/data 0xgingi/kagi-discord-bot:latest
Using Bun (Local Development)
- Clone and Install dependencies:
git clone https://github.com/0xgingi/kagi-discord-bot
cd kagi-discord-bot
bun install
- Start the bot:
bun start
Adding the Bot to Your Server
- Go to the Discord Developer Portal
- Select your application
- Go to the "Bot" section
- If you want to use the channel summarization feature:
- Enable the "Message Content Intent" under "Privileged Gateway Intents"
- Note: For bots in more than 100 servers, Discord requires verification and approval for this intent
- Set
MESSAGE_CONTENT_ENABLED=truein your.envfile
- For bots in many servers (>100) without verified intents:
- Set
MESSAGE_CONTENT_ENABLED=falsein your.envfile - The
/summarize channelcommand will be disabled automatically
- Set
- Go to the "OAuth2" section
- In the URL Generator, select the following scopes:
botapplications.commands
- In the bot permissions section, select:
Send MessagesEmbed LinksUse Slash CommandsRead Message History
- Copy the generated URL and open it in your browser to add the bot to your server
Usage
Once the bot is added to your server, you can use the following slash commands:
FastGPT
/fastgpt query: Your question here [file: Optional] [cache: Optional] [prompt: Optional]
Available options:
file: Upload a file to include in your query (PDF, code files, text files, etc.)cache: Whether to allow cached responses (default: true)prompt: Name of a system prompt stored indata/prompts.json
File limitations:
- Maximum file size: 10MB
- Content is truncated to 8,000 characters if longer
- For PDFs: Only text-based PDFs work (scanned/image PDFs may fail)
Ask
/ask question: Explain topic here [results: Optional] [prompt: Optional]
How it works:
- The bot asks your configured LLM (OpenRouter/OpenAI compatible) to rewrite the question into focused web search queries.
- Each generated query hits the Kagi Search API; snippets are passed back to the LLM with the original question.
- The model synthesizes an answer and cites the referenced sources using
[n]markers.
Options:
results: Limit how many links are fetched per generated search query (defaults to 4, max 8).prompt: Choose a system prompt fromdata/prompts.jsonto steer tone or behaviour.
Make sure LLM_API_KEY is configured before using /ask. If you're using a local provider that doesn't require authentication (e.g., Ollama), leave LLM_API_KEY empty and point LLM_API_BASE_URL to your local endpoint.
Tune the LLM creativity via ASK_TEMPERATURE (default 1.0) and the search-query planner via ASK_REWRITE_TEMPERATURE (default 0.2) in your environment settings. Increase ASK_MAX_TOKENS if you need longer answers (default 4,000; supports up to 128,000 tokens when the model allows it).
System Prompts
- Store named prompts in
data/prompts.jsonas a simple key-value map. Example:
{
"helpful": "You are a helpful assistant. Answer concisely.",
"tarantulas": "Only answer about tarantulas, refuse to answer anything else."
}
- Default prompt: If no prompt is selected, the bot uses the
defaultprompt fromdata/prompts.json. Ifdefaultis missing, no system prompt is applied. - Use with
/fastgpt ... prompt: helpfulto apply the selected system prompt. - If an unknown prompt is provided, the bot lists available names.
- You can add unlimited prompts by editing
data/prompts.json. When running via Docker, ensure-v $(pwd)/data:/app/datais set so changes persist. - You can also reference a file relative to
data/for prompts by using the special value@file:<path>. Files must reside under thedata/directory. Supports Markdown/Text and PDFs (PDFs are parsed to text on demand). Example:
{
"default": "You are a helpful assistant. Answer concisely.",
"style_guide": "@file:example_prompt.md"
}
- For PDFs or large documents, point to a file under
data/(e.g.,@file:guide.pdf). The bot will extract text (truncated to 8,000 characters) when used.
Managing Prompts
- Edit
data/prompts.jsondirectly to add, change, or remove prompt entries.
Web Search
/websearch query: Your search query
Uses the new Kagi Search API and prioritizes interesting_finds plus regular web results.
News Search
/newssearch query: Your search query
Uses the Kagi Search API news workflow and includes news plus interesting_news results.
Search
/search query: Your search query [workflow: Optional] [display: Optional] [limit: Optional]
Available options:
workflow: Result workflow to request:search,images,videos,news, orpodcasts.display: Number of results to show in Discord (1-10, default: 5).limit: Maximum API results to request (1-1024).page: Search result page (1-10).timeout: Search timeout in seconds (0.5-4).safe_search: Enable or disable safe search.format: Requestjsonor experimentalmarkdownoutput.lens_id: Built-in lens ID, shared lens ID, or full Kagi lens URL.- Inline lens options:
sites_include,sites_exclude,keywords_include,keywords_exclude,file_type,time_after,time_before,time_relative, andsearch_region. - Result filters:
region,after, andbefore. extract_countandextract_timeout: Extract markdown into top search result snippets. This uses Extract API units.domain_rules: Personalization rules likeblock:example.com, raise:docs.example.com.regex_replacements: Regex personalization rules, one per line, like^https?://www\.reddit\.com=>https://old.reddit.com.
Extract
/extract urls: https://example.com/article [timeout: Optional] [format: Optional]
Available options:
urls: One to ten HTTPS URLs, separated by spaces, commas, or new lines.timeout: Bulk extraction timeout in seconds (0.5-10).format: Returnjsonsummaries or experimental rawmarkdown.
Universal Summarizer
For URLs:
/summarize url url: The URL to summarize [engine: Optional] [summary_type: Optional] [target_language: Optional]
For text:
/summarize text text: The text to summarize [engine: Optional] [summary_type: Optional] [target_language: Optional]
For channel messages (requires MESSAGE_CONTENT_ENABLED=true):
/summarize channel [messages: Optional] [engine: Optional] [summary_type: Optional] [target_language: Optional]
Available options:
engine:cecil(Default) - Friendly, descriptive, fastagnes- Formal, technical, analyticalmuriel- Best-in-class, enterprise-grade ($1 per summary)
summary_type:summary- Paragraph(s) of prosetakeaway(Default) - Bulleted list of key points
target_language: Various language options (EN, ES, FR, etc.)messages: Number of recent messages to include in channel summary (1-100, default: 20)
Check Query Limits
/limits
Displays your remaining query counts for all commands, based on your server's configuration.
Query Limits
The bot includes a configurable query limiting system to control API usage:
- Per-User Tracking: All limits are applied per Discord user ID
- Global Limits: Set a maximum number of queries across all commands
- Command-Specific Limits: Set separate limits for each command
- Time Period Options: Configure limits by hour, day, week, or month
- Persistence: Optionally persist query records between bot restarts
Configure limits in your .env file. Set any limit to -1 for unlimited queries.
Pricing
The bot uses paid Kagi API endpoints. Check the current Kagi API Pricing page before enabling public access or high limits.
For convenience, the /summarize command displays estimated costs for the legacy summarizer endpoint. /search extract_count and /extract can incur Extract API charges.
License
MIT