This guide covers running the Phase 1 Discord frontend (lang2sql-bot). Be
honest with yourself about scope first: see §What's stub.
| Variable | Required | Purpose |
|---|---|---|
DISCORD_BOT_TOKEN |
yes | Bot token from the Discord developer portal. The bot raises a clear error and exits if this is unset. |
OPENAI_API_KEY |
no | When set, the agent uses OpenAI gpt-4.1-mini. When unset, it falls back to the offline FakeLLM (deterministic canned tool cycles — fine for a smoke run, not for real answers). |
LANG2SQL_SECRET_KEY |
no | A urlsafe-base64 Fernet key used to encrypt stored secrets (DSNs/API keys) at rest. If unset, a key is auto-generated and persisted in the SQLite kv table — self-contained but only as private as the DB file. Set this in production so secrets decrypt across restarts and machines. |
Generate a Fernet key:
.venv/bin/python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"Copy .env.example to .env and fill it in. (The bot reads
from the process environment; use your hosting platform's secrets mechanism or a
tool like direnv/dotenv to export them.)
- Go to the Discord Developer Portal → New Application.
- Bot tab → Add Bot → Reset Token → copy it into
DISCORD_BOT_TOKEN. - Privileged Gateway Intents → enable MESSAGE CONTENT INTENT (the bot reads message text to answer @mentions and thread replies).
- OAuth2 → URL Generator:
- Scopes:
bot - Bot permissions: Send Messages, Read Message History, Attach Files (for CSV results), Create Public Threads, Send Messages in Threads.
- Scopes:
- Open the generated invite URL and add the bot to your test guild.
Then run it:
export DISCORD_BOT_TOKEN=...
.venv/bin/lang2sql-botThe bot connects to the gateway and serves. Mention it in a channel or DM it.
Per the v4.1 plan (§4.1), V1 targets a free always-on host:
- Provision an Always Free ARM (Ampere A1) or AMD micro VM.
- Install uv, clone the repo,
uv sync. - Export the env vars and run
lang2sql-botunder a process supervisor (systemdunit ortmux/screenfor a quick trial).
- A tiny
fly.tomlrunninglang2sql-botas the process; the bot is a long-lived gateway client, not an HTTP server, so no exposed ports are needed. - Set
DISCORD_BOT_TOKEN,OPENAI_API_KEY,LANG2SQL_SECRET_KEYwithfly secrets set.
A minimal systemd unit:
[Service]
WorkingDirectory=/opt/lang2sql
ExecStart=/opt/lang2sql/.venv/bin/lang2sql-bot
Environment=DISCORD_BOT_TOKEN=...
Environment=OPENAI_API_KEY=...
Environment=LANG2SQL_SECRET_KEY=...
Restart=on-failureThe V1 SqliteStore defaults to :memory:, so audit/session/secret state is
lost on restart. For a real deployment, construct the store with a file path so it
survives restarts and back it up alongside LANG2SQL_SECRET_KEY (you need both to
decrypt stored secrets).
- No real database execution.
PostgresExplorerreturns cannedorders/usersschema and sample rows.run_sqlenforces the safety gate and goes through the executor, but there is no live psycopg connection in V1 — real execution is v1.5./connectstores a DSN (encrypted) but it is not yet used to open a connection. - No reasoning without
OPENAI_API_KEY. The offlineFakeLLMproduces deterministic tool cycles, not real answers. - No rate limiting in V1 — keep deployments to small trial guilds so token spend stays bounded (rate limit + per-user token caps are v1.5).