Each app talks to users over Telegram, reasons through a local Ollama LLM, calls external tools via the Model Context Protocol (MCP), runs on a cron schedule, and can generate rich PDF reports on demand.
- 🤖 Per-bot Telegram agents — Create as many independent bots as you need; each with its own system prompt, personality, and Telegram token.
- 🧠 Local LLM via Ollama — Runs entirely against a self-hosted Ollama instance. Bring your own model (
llama3,mistral,phi3, …) provided it supports tool calling. - 🔌 MCP tool integration — Connect any Model Context Protocol server (local stdio or remote HTTPS) to extend a bot's capabilities.
- 🧭 Semantic MCP tool ranking — MCP servers are re-ranked per message using pgvector cosine similarity, so the most relevant tools surface first.
- ⏰ Scheduled cron jobs — Bots can schedule themselves: create, list, update, and delete jobs through the LLM using cron expressions. Embedding-driven tool selection for scheduled tasks too.
- 📄 On-demand PDF reports — Built-in PDF generator (WeasyPrint) turns LLM-authored HTML into styled PDFs and ships them directly to the user's Telegram chat.
- 🌐 Built-in web search — Default
web_search(DuckDuckGo) andfetch_and_extract(article → markdown) tools give the LLM live access to the web without any extra setup. - 🧠 Semantic memory (pgvector) — Every user message, cron job schedule, and MCP tool description is embedded for similarity retrieval and used to enrich context. MCP tool lists are also cached per
(bot, server)for 1 hour to avoid redundant discovery calls. - 📝 Conversation summarisation — Older messages are summarised into a system-role message when the context window tightens, preserving recent verbatim history.
- 🎯 Observed user patterns — An async worker periodically rebuilds a behavioural profile of the user (communication style, recurring topics, preferences) and injects it into the system prompt.
- 🔐 Encrypted secrets at rest — Telegram bot tokens and MCP server secrets are Fernet-encrypted in the DB, keyed off
SECRET_KEY; lookup happens via deterministic SHA-256 hash. - 🛠️ Ops tooling — Celery + Redis for the worker pool, Celery Beat for scheduling, Flower at
:5555for queue inspection, structured JSON logs everywhere.
| Layer | Technology |
|---|---|
| Web framework | Django 5.2 |
| Async tasks | Celery 5.6 + Celery Beat |
| Broker / Cache | Redis 7 |
| Database | PostgreSQL 16 with pgvector |
| LLM | Ollama (any tool-calling-capable model) |
| Tool protocol | Model Context Protocol (FastMCP + mcp SDK) |
| PDF rendering | WeasyPrint |
| Admin Markdown | Martor |
| WSGI server | Gunicorn |
| Container | Docker + Docker Compose |
┌─────────────────────────────────────────────────────────┐
│ Django (Core) │
│ Admin Panel │ REST API │ Models │ Business Logic │
└───────────────────────────┬─────────────────────────────┘
│
┌─────────────────┼─────────────────┐
│ │ │
┌──────▼──────┐ ┌───────▼──────┐ ┌──────▼──────┐
│ Celery │ │ Ollama │ │ Telegram │
│ Workers │ │ (Local LLM) │ │ Bot API │
│ + Beat DB │ │ │ │ │
└──────┬──────┘ └─────┬────────┘ └──────┬──────┘
│ │ │
┌──────▼──────┐ ┌──────▼──────┐ ┌────────▼──────┐
│ Redis │ │ pgvector │ │ Telegram │
│ (Broker) │ │ (Embeddings)│ │ Polling / │
└─────────────┘ └─────────────┘ │ Webhook │
└──────────────┘
📐 For the full architecture, data models, request flows, and Celery task reference, see docs/ARCHITECTURE.md.
Prerequisite: Docker + Docker Compose installed.
# 1. Clone the repository
git clone <your-fork-url> WhimsyBots
cd WhimsyBots
# 2. Configure environment
cd src
cp .env.example .env
# Edit .env — set SECRET_KEY, DB_PASSWORD, WEBHOOK_BASE_URL, etc.
# 3. Build images
make build
# 4. Start services (db, redis, app, celery_worker, celery_beat, flower)
make up
# 5. Run migrations and create an admin user
make migrate
make createsuperuser
# 6. Open the admin
open http://localhost:8000/admin/That's it. The admin panel is the only UI — every bot, MCP server, cron job, and Ollama config is configured there.
After make createsuperuser, log into http://localhost:8000/admin/ and complete these steps in order:
- Pull your Ollama models on the host (not in Docker):
ollama pull llama3 # or any tool-calling-capable model ollama pull nomic-embed-text # or your preferred embedding model
- Add an
Ollamaconfiguration (/admin/app/ollama/add/):- Endpoint:
http://localhost:11434(when running in Docker) num_ctx: 4096 minimum; raise if your hardware allows.
- Endpoint:
- Create a
Bot(/admin/app/bot/add/):- Pick the LLM model and embedding model you just pulled.
- Set
embedding_dimensionsto match the embedding model (e.g. 768 fornomic-embed-text). - Author a system prompt (Markdown supported).
- Paste a Telegram bot token from @BotFather.
- Register the webhook by saving the bot — a
setup_bot_webhookCelery task fires automatically. EnsureWEBHOOK_BASE_URLin.envis publicly reachable over HTTPS. - Send your bot a message on Telegram. The chat ID is auto-populated, an embedding is generated, and the bot responds.
💡 For a deeper walkthrough of all
maketargets, the project layout, and coding conventions, see docs/DEVELOPMENT.md.
| Document | What's inside |
|---|---|
| README.md (this file) | Project overview, features, quick start, first-time setup |
| docs/ARCHITECTURE.md | High-level diagram, request flows, data models, Celery task reference, retry strategy |
| docs/DEVELOPMENT.md | Contributor onboarding, project layout, coding conventions, testing, debugging |
| docs/TROUBLESHOOTING.md | Common issues with Ollama, Telegram, Celery, database, tests, and local dev |
WhimsyBots/
├── src/ # All application code lives here
│ ├── app/ # Core Django app — models, admin, tasks, validators
│ ├── clients/ # External API clients (Telegram, Ollama, MCP)
│ ├── managers/ # Lightweight factory / cache managers
│ ├── services/ # Business logic (bot processor, embeddings, rate limiter, …)
│ ├── mcp_tools/ # In-process MCP tool registry (cron, PDF, web search)
│ ├── utils/ # Cross-cutting helpers (crypto, formatting, scheduling, …)
│ ├── tests/ # Pytest suite (test_app/, test_services/, test_utils/, …)
│ ├── whimsybots/ # Django project (settings/, urls.py, views.py, celery.py, wsgi.py)
│ ├── manage.py
│ ├── docker-compose.yml
│ ├── Dockerfile
│ ├── Makefile
│ └── requirements.txt
├── docs/ # All in-depth documentation
│ ├── ARCHITECTURE.md
│ ├── DEVELOPMENT.md
│ └── TROUBLESHOOTING.md
├── Makefile # Top-level convenience targets (cd src && …)
├── README.md # ← you are here
└── LICENSE # MIT
📁 Full annotated layout, including every module's purpose, lives in docs/DEVELOPMENT.md.
# Run the full suite
make test
# Verbose or a single test:
make test-verbose
make test-specific FILE=test_app/test_models.py::TestBot::test_strTests use the dedicated whimsybots.settings.test module — SQLite in-memory, fakeredis for Celery/cache, and a pgvector shim — so they don't need a running Postgres or Ollama.
This project is licensed under the MIT LICENSE