Before writing any feature code, you need a solid project structure and a plan. A well-scaffolded project makes everything easier: adding commands, testing, deploying. A bad structure means fighting the code at every step.
In this task, you use your coding agent to create a development plan and project skeleton.
- P0.1 Testable handler architecture — handlers work without Telegram
- P0.2 CLI test mode:
cd bot && uv run bot.py --test "/command"prints response to stdout
A bot/ directory inside your repo with an entry point, handler layer, configuration, dependencies, and a --test mode for offline verification.
se-toolkit-lab-7/
├── bot/ ← NEW
│ ├── bot.py ← entry point (Telegram startup + --test mode)
│ ├── handlers/ ← command handlers (no Telegram dependency)
│ ├── services/ ← API client, LLM client
│ ├── config.py ← env var loading
│ ├── pyproject.toml ← bot dependencies
│ └── PLAN.md ← development plan
├── backend/ ← existing
├── frontend/ ← existing
└── docker-compose.yml ← existing
The key idea is testable handlers: your command logic is just functions that take input and return text. They don't know about Telegram. The --test flag calls them directly, and later the Telegram bot calls the same functions. Same logic, different entry points.
The autochecker verifies the bot via --test — no Telegram connection needed:
cd bot
uv run bot.py --test "/start" # → prints welcome message
uv run bot.py --test "/help" # → prints command list
uv run bot.py --test "/health" # → prints backend status
uv run bot.py --test "/scores lab-04"
uv run bot.py --test "what labs are available" # Task 3
- Prints response to stdout, exits with code 0
- Reads config from
.env.bot.secret(LMS_API_BASE_URL,LMS_API_KEY,LLM_API_KEY) - Does not connect to Telegram (no
BOT_TOKENneeded in test mode)
A plan produced with your coding agent. Describe the approach for all tasks: scaffold, backend integration, intent routing, deployment. At least 100 words.
Ask your coding agent to create the entry point with --test mode support. Handlers can return placeholder text for now — real implementation comes in Task 2. Your job is to verify it works and understand the architecture (see Test mode above).
Handler modules separated from the Telegram transport layer. The --test mode calls them directly without Telegram.
Bot-specific Python project with dependencies. cd bot && uv sync must work without errors. Do not create requirements.txt — use pyproject.toml and uv exclusively.
.env.bot.example must include BOT_TOKEN, LMS_API_BASE_URL, LMS_API_KEY with placeholder values. On the VM, .env.bot.secret must exist with real values filled in.
Run on your VM:
cd ~/se-toolkit-lab-7/bot
uv sync
uv run bot.py --test "/start"
You should see a welcome message printed to the terminal. If it prints something and exits with code 0 — the scaffold works.
Try the other commands too — they can return placeholder text for now, but they must not crash:
uv run bot.py --test "/help"
uv run bot.py --test "/health"
uv run bot.py --test "/labs"
What to check:
- Each command prints something to stdout (even "Not implemented yet" is fine for this task)
- No Python tracebacks
- Exit code is 0 (the command doesn't show an error)
After verifying with --test, deploy the bot on your VM and check it responds in Telegram. You'll repeat this pattern after every task — it's how you know the bot works for real users, not just in test mode.
-
Push your changes and pull on the VM:
cd ~/se-toolkit-lab-7 git pull cd bot && uv sync -
Start the bot (kills any previous instance):
pkill -f "bot.py" 2>/dev/null; nohup uv run bot.py > bot.log 2>&1 & -
Open Telegram and send
/startto your bot. You should see the welcome message.
If the bot doesn't respond in Telegram:
- Check the log:
tail -20 bot.log - Common issues:
BOT_TOKENis wrong or missing in.env.bot.secret- Another bot process is already running (check
ps aux | grep bot.py) .env.bot.secretdoesn't exist (copy from.env.bot.example)
-
Git workflowfollowed (issue, branch, PR, review, merge).
-
bot/PLAN.mdwith at least 100 words exists. -
bot/pyproject.tomlexists. -
bot/handlers/directory with at least one module exists.
- Repo is cloned at
~/se-toolkit-lab-7. -
.env.bot.secretwithBOT_TOKEN,LMS_API_KEYexists. -
cd bot && uv syncsucceeds. -
cd bot && uv run bot.py --test "/start"exits 0 with non-empty output.
- Bot responds to
/start.