A self-hosted Discord chatbot with configurable LLM backends, persistent memory, and a FastAPI dashboard.
"Cannons firing. Bells ringing. The overture begins." — Tchaikovsky, 1880
1812 is a self-hosted, open-source Discord chatbot backed by your choice of LLM. It maintains per-channel conversation history in SQLite, streams responses token-by-token, supports image input, and ships with a FastAPI health/dashboard sidecar.
Named after Tchaikovsky's 1812 Overture — a piece that knows exactly when to be quiet and exactly when to be deafening.
A CryptoJones project.
| Feature | Details |
|---|---|
| Multi-backend LLM | OpenAI, Anthropic Claude, Ollama (local), OpenRouter |
| Streaming responses | Token-by-token output, edited live in Discord |
| SQLite persistence | Per-channel history and per-server personas survive restarts |
| Per-user memory | Remember facts about individual users across sessions |
| Per-server personas | Different personality per Discord server |
| Slash commands | /clear, /persona, /model, /remember, /forget |
| Image input | Attach images — vision-capable models process them inline |
| Rate limiting | Per-user sliding window (configurable requests/window) |
| Auto-summarisation | History is summarised by the LLM when it gets too long |
| FastAPI sidecar | /health, /api/channels, /api/history/:id, and a live dashboard |
| JSON structured logging | Machine-readable logs with level, timestamp, and context |
| Docker | Single-container deploy via docker-compose up |
| Graceful shutdown | SIGTERM/SIGINT handled cleanly |
| Component | Technology |
|---|---|
| Bot framework | discord.py 2.3+ |
| LLM backends | OpenAI / Anthropic / Ollama / OpenRouter |
| History storage | SQLite via aiosqlite |
| Config | Pydantic Settings + .env |
| Web sidecar | FastAPI + uvicorn (background thread) |
| Container | Docker + Docker Compose |
| Tests | pytest + pytest-asyncio |
Docker (recommended)
cp .env.example .env
# Edit .env with your tokens
docker compose up -dManual
chmod +x setup.sh && ./setup.sh
cp .env.example .env
# Edit .env with your tokens
source .venv/bin/activate
python bot.py| Variable | Required | Default | Description |
|---|---|---|---|
DISCORD_TOKEN |
Yes | — | Your Discord bot token |
LLM_PROVIDER |
No | openai |
openai | anthropic | ollama | openrouter |
LLM_MODEL |
No | gpt-4o-mini |
Model name for the selected provider |
OPENAI_API_KEY |
If OpenAI | — | OpenAI API key |
ANTHROPIC_API_KEY |
If Anthropic | — | Anthropic API key |
OPENROUTER_API_KEY |
If OpenRouter | — | OpenRouter API key |
OLLAMA_BASE_URL |
No | http://localhost:11434/v1 |
Ollama endpoint |
SYSTEM_PROMPT |
No | You are 1812... |
Default bot personality |
MAX_HISTORY_MESSAGES |
No | 20 |
Messages to keep per channel before summarising |
SUMMARISE_AT |
No | 40 |
History length that triggers summarisation |
RATE_LIMIT_REQUESTS |
No | 10 |
Max requests per user per window |
RATE_LIMIT_WINDOW_SECONDS |
No | 60 |
Rate limit sliding window |
DB_PATH |
No | 1812.db |
Path to SQLite database file |
WEB_HOST |
No | 0.0.0.0 |
FastAPI sidecar host |
WEB_PORT |
No | 8080 |
FastAPI sidecar port |
SHUTDOWN_AFTER_MINUTES |
No | unset (= unbounded) | Auto-shutdown timer in minutes. CLI --shutdown-after N overrides this. |
| Flag | Description |
|---|---|
--shutdown-after N |
Self-shutdown after N minutes of runtime. Overrides SHUTDOWN_AFTER_MINUTES. 0 is an explicit "unbounded" sentinel that clears any env value. Useful for time-boxed runs, cron jobs, and CI canaries. |
# Run for exactly two hours, then graceful shutdown.
python bot.py --shutdown-after 120
# Wipe an env-configured timer for this invocation only.
SHUTDOWN_AFTER_MINUTES=30 python bot.py --shutdown-after 0| Command | Who | Description |
|---|---|---|
/clear |
Anyone | Wipe conversation history for the current channel |
/persona <name> |
Anyone | Switch persona: default, concise, creative, technical |
/model <name> |
Admin only | Change the LLM model at runtime |
/remember <text> |
Anyone | Save a personal note about yourself for the bot to use |
/forget |
Anyone | Clear your personal memory |
- Go to discord.com/developers/applications
- Create or select your application
- Navigate to Bot → enable Message Content Intent and Server Members Intent
- Copy your bot token into
.env - Invite via OAuth2 → URL Generator — scopes:
bot,applications.commands— permissions:Send Messages,Read Message History,Attach Files
The FastAPI sidecar runs on port 8080 by default:
| Endpoint | Description |
|---|---|
GET /health |
Liveness check |
GET /api/channels |
List all channels with history |
GET /api/history/{channel_id} |
Full message history for a channel |
GET / |
Live HTML dashboard |
1812/
├── bot.py # Discord bot, slash commands, streaming
├── config.py # Pydantic Settings
├── db.py # SQLite helpers (aiosqlite)
├── llm.py # LLM backend abstraction (OpenAI / Anthropic / Ollama / OpenRouter)
├── rate_limiter.py # Per-user sliding window rate limiter
├── web.py # FastAPI sidecar
├── tests/ # pytest test suite
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── setup.sh
└── .env.example
python3 -m pytest tests/ -v31 tests covering rate limiting, database operations, LLM backend selection, and bot helpers.
Pull requests welcome. Keep it simple. Keep it clean. Write tests first.
Apache License 2.0 — Copyright 2026 Aaron K. Clark. See LICENSE.
To Dr. John Crichton of the Farscape Project — astronaut, wormhole theorist, and the most unlikely hero to ever fall through the wrong end of the universe. Wherever he is.
Proudly Made in Nebraska. 🌽