Project layout¶
The repository is a uv workspace. The root builds no package of its own; every shippable unit is a workspace member under apps/, libs/, or tools/. All of them share one import namespace, mitup_bot, assembled as a single PEP 420 namespace package: no member ships a mitup_bot/__init__.py, so from mitup_bot.config import ... resolves into libs/core and from mitup_bot.guards import ... into libs/telegram without either member knowing about the other. Imports read the same no matter which member owns the module.
The three kinds of member¶
apps/ holds the deployable applications. Each one ships its own image or Lambda and never imports another app.
apps/bot(mitup-bot-app): the PTB runtime and the FastAPI webhook host, the handlers, the timezone API, the update processor, and themitup launchCLI.apps/events(mitup-events-app): the recurrent-events runner and its jobs, plus themitup recurrent-eventsCLI.apps/lambda-migrations(mitup-lambda-migrations-app): the Alembic-runner Lambda. PTB-free.apps/lambda-alarm(mitup-lambda-alarm-app): the CloudWatch-to-GitLab alarm Lambda.
libs/ holds the shared libraries the apps build on. They carry no deployment of their own.
libs/core(mitup-core): config, logging, the i18n engine and locale catalogs, base exceptions, callback data, handler ids, supporter and limits logic, the keyboard schema, and emojis.libs/data(mitup-data): the SQLModel tables, the async engine and session lifecycle, and the Alembic migrations tree.libs/telegram(mitup-telegram): the PTB API wrapper, the view layer, the message and callback utilities, and the shared glue both apps register at startup (guards, custom context, reconciliation).libs/monitoring(mitup-monitoring): CloudWatch EMF metrics emission.libs/patreon(mitup-patreon): the Patreon API client, OAuth flow, membership webhooks, and encrypted token storage.
tools/ holds dev-only members that never ship: the mb developer CLI and the one-off rails-migration tool. tests/ is a single suite covering every member.
Who owns what¶
When a change grows past a one-line fix, the conventions for the area live in a skill under .agents/skills/, and a specialist agent owns that area. The table below maps each part of the tree to both.
| Path | What it does | Governing knowledge |
|---|---|---|
apps/bot/mitup_bot/app.py + web/ |
The runtime entry point and the FastAPI webhook host that feeds updates into PTB. | web-conventions |
apps/bot/mitup_bot/handlers/ |
Bot logic grouped by feature area. Each handler answers one Telegram event. | handler-conventions · handler-expert |
libs/telegram/mitup_bot/views/ |
The screens the user sees. MitupView and the factory catalogue build the message text and inline keyboard. |
views · view-expert |
libs/data/mitup_bot/models/ + db.py |
SQLModel tables and the engine and session decorators that give handlers a database session. | database · handler-expert |
libs/telegram/mitup_bot/utils/messages.py |
Every user-facing string and button label. Nothing shown to a user is hardcoded elsewhere. | user-facing-text · bot-copywriter |
libs/telegram/mitup_bot/guards.py |
Input validation for handlers. Turns a raw Update into the typed pieces a handler needs, or raises. |
guards · handler-expert |
libs/core/mitup_bot/config.py |
The configuration system. Merges TOML and environment providers with Pydantic validation. | mitup-config |
App CLI entry modules (bot_cli.py, events_cli.py) |
The mitup launch and mitup recurrent-events production commands. |
cli-conventions · cli-expert |
apps/lambda-migrations/ + apps/lambda-alarm/ |
AWS Lambda functions that run outside the main bot process. | lambda-conventions · lambda-expert |
libs/data/mitup_bot/migrations/ |
Alembic migration scripts. One per schema change, applied in order. | new-migration · handler-expert |
tests/ |
The test suite, covering every workspace member. | test-conventions · test-expert |
How images map to deployables¶
Each apps/ member carries its own Dockerfile, built from the repo root so the whole uv workspace is the build context. Four members, four images, four running things:
| Member | Image | Runs as |
|---|---|---|
apps/bot |
mitup-bot-app |
An ECS service: the webhook host and PTB handlers. |
apps/events |
mitup-events-app |
An ECS service: the recurrent-events worker. |
apps/lambda-migrations |
mitup-lambda-migrations-app |
A Lambda that applies Alembic migrations on deploy. |
apps/lambda-alarm |
mitup-lambda-alarm-app |
A Lambda that forwards CloudWatch alarms to GitLab. |
Each image resolves only its own member's locked dependency closure, so the alarm Lambda never carries PTB and the migrations Lambda never carries the web stack.
Golden rules
- Never run
pythondirectly. The system interpreter has none of the project's dependencies. Useuv run python <args>. - No hardcoded user-facing strings. Every label and message lives in
libs/telegram/mitup_bot/utils/messages.pyand gets translated. Adding a string means adding it there. - Delegate by area. Each part of the tree has a specialist agent and a skill that carry its conventions. Reach for the matching one instead of editing blind.
- Run
uv run mb validatebefore you push. CI runs the same format, lint, type-check, and test gate and rejects merge requests that fail it.
The skill links above go to the full conventions for each area. Start there when a change grows past a one-line fix.