AGENTS.md — Project Agent Guide
Project: Telegram Weather Bot Repo root:
telegram-weather-bot-pub/Primary entrypoint:app.pyArchitecture: Clean Architecture (DDD, DI, event-driven modules) Languages: Python 3.12+, async-first, i18n: ru/en/de License: MIT
Table of Contents
- Agent System Prompt
- Mission & Scope
- Repository Map (Authoritative)
- Operational Constraints & Budgets
- Security, Privacy, Compliance
- Environment & Configuration
- Coding Standards
- Internationalization & UX
- Rate Limiting & Quotas
- Jobs, Backups & Admin
- Error Handling & Observability
- CI/CD & Tooling
- Makefile Commands Reference
- Git Conventions
- Task Execution Protocol
- Do / Don't
- Change Placement Decision Tree
- Machine-Readable Policy
- Storage Schema Contracts & Migrations
- i18n Style Guide
- Pre-PR Checklist
- Incident Playbooks
- Observability Contract
- Common Tasks Cookbook
- Minimal E2E Smoke (Local)
- PR Template
- Issue Template
- Release & Versioning
- Glossary
- Escalation & Non-Goals
Agent System Prompt
- You are the “WeatherBot Project Agent.”
- Objectives: adhere to Clean Architecture boundaries; keep diffs minimal and reversible; maintain multilingual UX (ru/en/de); never leak secrets; keep tests green.
- When unsure: document reasoning briefly in the PR description; propose the smallest viable option.
- PR output style: concise summary listing touched layers and exact commands run.
- Hard constraints:
- Do not modify storage schemas without a version bump, migration, and tests.
- Do not commit
.envfiles, tokens, or secrets; avoid logging secrets/PII. - Keep per-chat command localization in sync whenever language-facing strings change.
- Acceptance criteria (default):
- Tests pass and coverage is not reduced on touched files.
- Admin gating, rate limits, and quotas remain intact.
- Clean Architecture layering respected; no inward dependency leaks.
Mission & Scope
Mission: Deliver a reliable, privacy-respecting Telegram weather bot with delightful multilingual UX and predictable operational costs.
In scope:
- Telegram handlers, keyboards, onboarding flows, admin tools.
- Weather queries, geocoding, subscriptions, backups, observability.
- Tests, documentation, CI/CD refinements, refactors aligning with architecture.
- Localization improvements for Russian, English, and German.
Out of scope (unless explicitly requested):
- Switching persistence away from JSON without a migration plan.
- Massive architectural rewrites or multi-instance scaling.
- Introducing paid/closed APIs by default.
Repository Map (Authoritative)
weatherbot/
├─ core/ # Value objects, entities, configuration contracts
├─ domain/ # Ports/interfaces, domain services
├─ application/ # Use cases, orchestrators, conversation logic
├─ infrastructure/ # External adapters (HTTP, storage, DI container)
├─ presentation/ # Formatters, i18n resources, keyboards
├─ handlers/ # Telegram command/callback handlers
├─ jobs/ # Scheduled jobs, backup routines
├─ modules/ # Modular bootstrapping & runtime composition
├─ observability/ # Logging, metrics, health endpoints
├─ utils/ # Shared utilities (time, text, validation)
└─ tests/ # Pytest suites across layers
app.py # Application bootstrap & module assembly
CONFIG.md # Environment variable reference
ARCHITECTURE.md # Detailed architecture documentation
Do not move files across layers without a clear architectural justification and accompanying documentation update.
Operational Constraints & Budgets
- Weather provider: Open-Meteo (default, keyless) — shared budget of ~1000 calls/day.
- Geocoding provider: Nominatim — respect rate limits; cache results where reasonable.
- Telegram API: Soft limit 30 msgs/sec globally;
python-telegram-botenforces per-chat throttling. - Internal throttle: Target ≤5 requests/minute per user for expensive operations.
- Storage: JSON files in
data/; maintain backward compatibility and migrate gracefully.
Security, Privacy, Compliance
- Never commit secrets or
.envfiles. Provide.env.*.exampleonly. - Sensitive data (tokens, chat IDs beyond numeric) must not appear in logs or docs.
- Implement data minimization: store only what is required (language, home location, subscriptions, spam counters).
/dataexport and/delete_meflows must remain functional and tested.- Backups should respect
BACKUP_*environment variables; redact secrets from backup archives.
Environment & Configuration
- Mandatory:
BOT_TOKEN(Telegram bot token). - Common optionals:
ADMIN_IDS,ADMIN_LANGUAGE,STORAGE_PATH,TIMEZONE,BACKUP_*,WEATHER_API_*,WEATHER_SERVICE_PROVIDER,GEOCODE_SERVICE_PROVIDER. - Load configuration through DI/container abstractions; never hardcode secrets or rely on implicit globals.
- Local development uses
.env.dev; production uses.env.prod. Provide sample entries in docs if changed.
Coding Standards
- Python 3.12+, async-first, minimal blocking I/O.
- Prefer value objects, immutable conversation state, and pure functions in inner layers.
- Formatting:
make format(Black + isort). Linting:make lint(flake8). - Tests:
pytest; keep or improve coverage on touched files. - Layering rules:
weatherbot/coreandweatherbot/domaincannot import from outer layers.weatherbot/applicationorchestrates via interfaces only.weatherbot/infrastructuresupplies implementations & DI wiring.weatherbot/presentationandweatherbot/handlersown user-facing strings and Telegram API usage.
- Follow type hints; prefer
Protocolfor ports; avoidAnyunless justified.
Internationalization & UX
- Supported languages: ru / en / de.
- User-facing strings live in
locales/(GNU gettext) or presentation helpers; never hardcode in handlers. - Maintain parity across languages when adding keys; ensure command menus refresh after language changes.
- Keep onboarding accessible: provide language choice, home location guidance, and fallback instructions.
Rate Limiting & Quotas
- Respect per-user throttle and global daily quotas for weather/geocoding providers.
- Use caching and quota tracking utilities in
weatherbot.utilsandweatherbot.infrastructurewhere available. - Notify admins proactively when approaching limits (re-use existing admin notification patterns).
Jobs, Backups & Admin
- Jobs defined in
weatherbot/jobsand registered via modules must be idempotent and timezone-aware. - Backups read
BACKUP_*configuration, store artifacts underdata/backups/, and must not block the event loop. - Admin commands gated by
ADMIN_IDS; test negative paths to prevent privilege escalation.
Error Handling & Observability
- Structured JSON logging (see
weatherbot/observability). No secrets or PII beyond numeric IDs. - Prefer explicit exception types and user-facing remediation tips.
- Emit metrics for API calls, quota usage, job execution, and error counts.
- Health endpoints and readiness checks should remain lightweight and authenticated if exposed.
CI/CD & Tooling
- Keep GitHub Actions workflows green (mirrors
make ci-all). - Local pre-push checklist:
make formatmake lintmake testmake coverage
- Docker:
make prod-up/make prod-downfor local container runs. - Security scans:
make ci-security(bandit) — run when touching security-sensitive code.
Makefile Commands Reference
CRITICAL: Always use Makefile commands instead of direct CLI invocations for consistency and cross-platform compatibility.
Development Workflow
make help— Show all available commands with descriptionsmake venv— Create virtual environment (.venv/)make install— Install all dependencies (prod + dev)make run-dev— Run bot locally with.env.devconfigurationmake run-prod— Run bot locally with.env.prodconfiguration
Testing & Quality Assurance
Use these commands, NOT raw pytest/black/flake8:
make test— Quick test run (pytest -q)make coverage— Run tests with coverage report (generatescoverage.xml)make coverage-html— Generate HTML coverage report (htmlcov/index.html)make test-all— Run coverage + upload to Codecov (requiresCODECOV_TOKEN)
Code Quality
Always run before commits:
make format— Auto-format code (black + isort)make format-check— Check formatting without changesmake lint— Run flake8 lintermake pre-commit-install— Install pre-commit hooks
CI/CD Validation
Run before pushing release candidates:
make ci-test— Run all CI tests (black check + isort check + flake8 + pytest with coverage)make ci-security— Run security scan (bandit)make ci-all— Run complete CI pipeline (ci-test + ci-security)
Docker Operations (Local)
make prod-up— Start containers with.env.prod(detached mode, with build)make prod-logs— Show container logs (tail -f, last 100 lines)make prod-restart— Restart running containersmake prod-down— Stop and remove containersmake prod-clean— Stop, remove, and clean up containers
Remote Deployment (SSH)
Requires .env.deploy with SSH_HOST, PROJECT_DIR, BRANCH:
make deploy— Simple deploy (pull + rebuild + up)make deploy-clean— Clean deploy (stop → hard reset → rebuild)make deploy-logs— Show logs from remote containersmake deploy-prune— Prune unused Docker images on remotemake ssh-connect— Connect to remote server via SSH
Local Server Deployment
When already on the server:
make local-deploy— Deploy on current machine (hard reset to origin)make local-logs— Show local container logs
Maintenance
make clean— Remove__pycache__and*.pycfilesmake clean-venv— Remove virtual environmentmake freeze— Createrequirements.lockfrom venvmake backup-now— Manually trigger storage backup
Common Use Cases
1. Initial setup:
make venv
make install
# Create .env.dev with BOT_TOKEN
make run-dev
2. Before committing changes:
make format # Auto-fix formatting
make lint # Check code quality
make test # Verify tests pass
3. Pre-release validation (Release Checklist Phase 2):
make ci-all # Must pass before pushing RC branch
4. Code review / coverage check:
make coverage-html # Generate detailed HTML report
# Open htmlcov/index.html in browser
5. Production deployment:
# Remote (via SSH):
make deploy-clean
# Local (on server):
make local-deploy
6. Debugging production:
make deploy-logs # Remote logs
make local-logs # Local logs
Anti-Patterns to Avoid
❌ Don't:
- Run
pytestdirectly → Usemake testormake coverage - Run
black .directly → Usemake format - Run
flake8directly → Usemake lint - Run
docker compose updirectly → Usemake prod-upormake local-deploy - Install dependencies with
pip install -r requirements.txt→ Usemake install
✅ Do:
- Always use Makefile commands for consistency
- Check
make helpwhen unsure about available commands - Run
make ci-allbefore pushing release branches - Use
make formatbeforemake lintto auto-fix issues
Git Conventions
- Branch naming:
feat/*,fix/*,chore/*,docs/*,test/*,refactor/*. - Commit messages: Conventional Commits (
feat: …,fix: …, etc.). - Keep PRs focused; describe layer impact, UX changes, and test results.
- Avoid large unrelated refactors; split into separate PRs when needed.
Task Execution Protocol
- Clarify requirements only when absolutely necessary; otherwise infer from docs/tests.
- Locate the relevant layer(s) using the repository map and architecture guidelines.
- Design briefly—note significant choices or trade-offs in the PR body.
- Implement minimal, reversible changes; respect DI patterns and event flows.
- Test: add/adjust unit, handler, and integration tests as appropriate.
- Run
make format && make lint && make test && make coveragelocally before committing. - Document behavior changes in README/CONFIG/ARCHITECTURE as needed.
- Open PR using the provided template; include coverage deltas and manual QA steps.
Default acceptance: tests pass, coverage not reduced, i18n updated, quotas respected, no schema breaks.
Do / Don’t
Do
- Extend functionality via defined interfaces and dependency injection.
- Centralize localization updates and refresh command menus on change.
- Add deterministic tests covering new behavior.
- Cache expensive API calls and respect provider policies.
Don’t
- Commit secrets or environment files.
- Introduce heavy dependencies without discussion.
- Bypass Clean Architecture boundaries or couple handlers to infrastructure details.
- Block the event loop with synchronous I/O in async code paths.
Change Placement Decision Tree
- Pure domain rules / value checks? →
weatherbot/core - Ports, policies, domain contracts? →
weatherbot/domain - Use-case orchestration (no IO specifics)? →
weatherbot/application - External IO, storage, DI wiring? →
weatherbot/infrastructure - Formatting, keyboards, text? →
weatherbot/presentation - Telegram update routing, command handlers? →
weatherbot/handlers - Scheduled tasks, backups? →
weatherbot/jobs - Cross-cutting logging/metrics? →
weatherbot/observability
Machine-Readable Policy
Create or update .agent-policy.yml at repo root:
language: "python3.12"
test_commands:
- "make format"
- "make lint"
- "make test"
- "make coverage"
risk_rules:
forbid:
- "commit_env_files"
- "hardcode_tokens"
- "blocking_io_in_async"
- "schema_change_without_migration"
require:
- "i18n_update_on_command_change"
- "admin_gating_on_admin_commands"
- "quota_checks_on_weather_calls"
coverage:
min_delta: ">=0"
rate_limits:
per_user_rpm: 5
telegram_global_mps: 30
weather_daily_calls: 1000
Keep this file synchronized with policy changes; update agents if constraints shift.
Storage Schema Contracts & Migrations
- Primary storage:
data/storage.json. Changes must remain backward-compatible. - Maintain a JSON schema similar to the structure documented in
ARCHITECTURE.md. - Each breaking change requires:
- Version bump in the stored data.
- Migration script
data/migrations/mig_<N>_<desc>.pywithupgrade()/downgrade(). - Tests in
tests/test_migrations.pycovering happy path, corrupted data, and rollback.
- Never write partial data on failure; use atomic file writes.
i18n Style Guide
- Key format:
scope.feature.message(e.g.,cmd.start.welcome). - Placeholder syntax:
{city},{temp},{time}— handled via.formator gettext substitution. - Keep sentences concise, sentence case, no trailing spaces.
- Update RU/EN/DE simultaneously; add tests ensuring command menus include new translations.
Pre-PR Checklist
-
make format -
make lint - Tests added/updated (
make test) - Coverage maintained/improved (
make coverage) - i18n strings updated in ru/en/de; command menu refresh verified
- Quotas and throttling respected (tests or reasoning documented)
- No secrets or
.envfiles committed - Storage schema changes include migration + tests (if applicable)
- Docs updated (README/CONFIG/ARCHITECTURE) when behavior changes
Release Checklist
Follow this step-by-step procedure when preparing a new release:
Phase 1: Branch and Version Bump
-
Create Release Candidate Branch
git checkout dev git pull origin dev git checkout -b rc/X.Y.Z -
Update Version Metadata in
weatherbot/__version__.py- Update
__version__ = "X.Y.Z" - Update
__version_info__ = (X, Y, Z) - Update
__release_date__ = "DD.MM.YYYY"(current date) - Add new release notes to
RELEASE_NOTESat the top with🎉 New in X.Y.Zheader - Include: bug fixes, new features, breaking changes, improvements
- Keep previous releases under "Previous Releases" section
- Update
-
Sync Version in
pyproject.toml- Update
[project] version = "X.Y.Z"
- Update
-
Update Localization Files (
locales/{en,ru,de}.json)- Change
admin_version_whats_newto reference new version:- EN:
"What's new in version X.Y.Z" - RU:
"Что нового в версии X.Y.Z" - DE:
"Neuerungen in Version X.Y.Z"
- EN:
- Change
-
Update README.md
- Change version badge:
[] - Update "What's New — Version X.Y.Z" section with release highlights
- Keep highlights concise (3-5 bullet points with emoji)
- Focus on user-visible improvements and bug fixes
- Change version badge:
Phase 2: Validation
-
Run Full CI Pipeline
make ci-all- All tests pass (282+ tests expected)
- Coverage maintained at ≥73%
- No linting errors (black, isort, flake8)
- Security scan clean (bandit: no issues)
-
Verify Release Metadata Consistency
- Run
pytest tests/test_release_metadata.py -v - Ensure all version checks pass:
- Version matches across
__version__.py,pyproject.toml,README.md - Localization keys updated in all languages
- Release date format valid (DD.MM.YYYY)
- Release date not in future
RELEASE_NOTEScontains entry for new version
- Version matches across
- Run
Phase 3: Commit and Push
-
Commit Release Candidate
git add -A git commit -m "chore(release): prepare X.Y.Z RC Version bump to X.Y.Z with release notes updates. Highlights: - [Feature 1] - [Feature 2] - [Bug fix] CI: 282+ tests passing, coverage ≥73%, bandit clean." -
Push Release Branch
git push origin rc/X.Y.Z
Phase 4: Merge to Dev and Verify CI
-
Merge RC to Dev
git checkout dev git pull origin dev git merge --no-ff rc/X.Y.Z -m "Merge release candidate X.Y.Z to dev" git push origin dev -
Verify GitHub Actions CI Pipeline
- Navigate to GitHub Actions tab
- Wait for CI pipeline to complete on
devbranch - Ensure all checks pass (tests, linting, security)
- If CI fails, fix issues in
devand cherry-pick torc/X.Y.Z
Phase 5: Merge to Main and Tag
-
Merge Dev to Main
git checkout main git pull origin main git merge --no-ff dev -m "Release X.Y.Z" git push origin main -
Create Git Tag
git tag -a vX.Y.Z -m "Release X.Y.Z [Copy release notes highlights here]" git push origin vX.Y.Z
Phase 6: Post-Release
-
GitHub Release (Optional)
- Create GitHub release from tag
vX.Y.Z - Copy release notes from
RELEASE_NOTES - Attach any binaries or deployment artifacts if needed
- Create GitHub release from tag
-
Deployment
- Deploy to production environment
- Verify bot responds with new version in
/admin_versioncommand - Monitor logs for errors during initial rollout
-
Cleanup
- Delete release candidate branch (optional):
git branch -d rc/X.Y.Z git push origin --delete rc/X.Y.Z
- Delete release candidate branch (optional):
Release Type Guidelines
Patch Release (X.Y.Z where Z increments):
- Bug fixes only
- No new features
- Backward compatible
Minor Release (X.Y.Z where Y increments):
- New features
- Improvements
- Backward compatible
- May include bug fixes
Major Release (X.Y.Z where X increments):
- Breaking changes
- Major architectural changes
- Requires migration guide
- Update
RELEASE_NOTESwith ⚠️ BREAKING CHANGES section
Common Release Pitfalls
❌ Don't:
- Skip CI validation
- Forget to update localization in all languages
- Commit version bumps directly to
mainordev - Merge RC directly to
mainwithout testing indevfirst - Tag before merging to
main - Use generic commit messages
✅ Do:
- Always create an RC branch
- Merge RC → dev → verify CI → main
- Run full test suite before pushing
- Keep release notes user-friendly
- Update all version references atomically
- Test metadata consistency with
test_release_metadata.py - Wait for GitHub Actions to pass on
devbefore merging tomain
Incident Playbooks
Weather Provider Outage
- Return friendly fallback message; log
level=WARNINGwith context. - Retry with capped exponential backoff (≤2 retries).
- Notify admins once; avoid spam.
Geocoding Throttling
- Apply exponential backoff; encourage user to retry later.
- Cache last successful result per query to reduce load.
Storage Corruption
- Quarantine corrupted file (
storage.json.broken.<timestamp>). - Restore latest backup; notify admins; run in degraded mode if necessary until restored.
Observability Contract
- Logs: JSON fields (
ts,level,event,user_id?,chat_id?,lang,cmd,duration_ms,ok,err?). No secrets. - Metrics: weather calls, geocode calls, quota remaining, subscriptions sent, rate-limit hits, job durations.
- Tracing/health: keep lightweight; expose only non-sensitive data.
Common Tasks Cookbook
Add a new user command (e.g., /hourly):
- Define request/response models in
weatherbot/domain(ports + DTOs). - Implement use case in
weatherbot/applicationand wire through modules. - Add presenter/formatter in
weatherbot/presentation. - Implement handler in
weatherbot/handlersand register viamodules/command.py. - Update localization strings and command menus (ru/en/de).
- Add tests: use case, presenter snapshot, handler integration.
Add a background job (e.g., subscription digest):
- Implement job in
weatherbot/jobsusing async-friendly patterns. - Register in the Jobs module; ensure schedule respects
TIMEZONE. - Cover with tests (scheduling, quota respect, failure handling).
Swap or extend weather provider:
- Implement provider adapter in
weatherbot/infrastructure/weather/behind existing interface. - Update DI to allow selection via
WEATHER_SERVICE_PROVIDERenv. - Add tests using provider overrides (
weatherbot.infrastructure.containerhelpers) — no monkeypatching globals.
Minimal E2E Smoke (Local)
- Create
.env.devwithBOT_TOKEN=<test token>and runmake run-dev. /start→ language menu renders./sethome <city>→ stored;/homereturns localized weather summary./subscribe→ schedules daily job; verify logs for job queue entry./language→ switch tode; command menu updates accordingly.
PR Template
### Summary
(What changed and why—succinct.)
### Layer Impact
- Core: [ ] none / [ ] touched (details)
- Domain: [ ] none / [ ] interfaces changed
- App: [ ] none / [ ] new use case / [ ] modified
- Infra: [ ] none / [ ] new client / [ ] DI changes
- Present: [ ] none / [ ] i18n/formatting changes
- Handlers:[ ] none / [ ] commands affected
- Jobs: [ ] none / [ ] scheduler changes
### i18n
- [ ] ru updated
- [ ] en updated
- [ ] de updated
- Per-chat menu refreshed on change: [ ] yes
### Quotas & Rate Limiting
- [ ] respected
- [ ] near-limit messaging for users/admins added (if relevant)
### Testing
- [ ] unit tests
- [ ] handler tests
Coverage: before → after: X% → Y%
### Docs
- [ ] README / ARCHITECTURE / CONFIG updated (if needed)
### Risks & Rollback
(Top risks + quick rollback strategy.)
Issue Template
### Task
(Concise change request.)
### Acceptance Criteria
- [ ] Expected behavior described
- [ ] i18n updated (ru/en/de)
- [ ] Command menus refreshed (if applicable)
- [ ] Quotas & throttling respected
- [ ] Tests pass; coverage not reduced
### Notes
(Layers involved, related tickets, references.)
Release & Versioning
- Update
weatherbot/__version__.pyand accompanying release notes when introducing user-visible changes. - Keep README “What’s New” aligned with latest tag.
- Follow semantic versioning unless product requirements dictate otherwise.
Glossary
- Home Location:
{lat, lon, label}stored per user for quick forecasts and subscriptions. - Subscription: Scheduled push delivering weather updates at configured local time.
- Quota: Shared 24h budget for weather provider calls.
- Command Menu: Localized Telegram command list configured via Bot API (
setMyCommands). - Modules: Bootstrap components in
weatherbot/modulesthat register handlers, jobs, and services.
Escalation & Non-Goals
- If a change risks breaking architectural boundaries or quotas, pause and surface a design note before implementation.
- Avoid stateful singletons, cross-layer imports, or schema changes without migration.
- Non-goals: multi-instance scaling, database migrations, paid API integration—unless explicitly requested by stakeholders.
End of AGENTS.md