Internal Telegram bot that turns a public GitHub or GitLab repository into a reviewed Android Repository channel post.
The bot collects repository evidence, generates a constrained English draft, renders a 1920 × 1080 PNG banner, enforces a three-calendar-month publication cooldown in PostgreSQL, and keeps a staff member in control of publication.
- GitHub and GitLab repository discovery with normalized, validated metadata.
- Structured AI copy generation from explicitly untrusted repository evidence.
- NASA-backed banner rendering with bundled offline artwork.
- Public
/startpresentation with source code, channel, and community links. - Staff-only Telegram review, regeneration, cancellation, and confirmation.
- Persistent repository identity, cooldown checks, and publication audit data.
- Layered Python workspace with framework-independent domain and application packages.
You need Docker with Compose, a Telegram bot and its target chats, and an OpenCode Zen API key.
-
Copy the environment template and replace every required placeholder:
cp .env.example .env
-
Build and start the application:
docker compose up --build bot
Compose starts PostgreSQL, waits for it to become healthy, applies all Alembic
migrations, and then starts the bot. PostgreSQL data is retained in the named
postgres-data volume.
You need Python 3.14, uv, and PostgreSQL.
-
Install the locked workspace:
uv sync --locked --all-packages
-
Create and configure the local environment. Use
localhostas the database host when the bot runs on the host:cp .env.example .env
-
Start the Compose database:
docker compose up -d postgres
-
Apply migrations to the local database:
AR_DATABASE_URL=postgresql+asyncpg://androidrepo:androidrepo@localhost:5432/androidrepo \ uv run alembic -c packages/persistence/alembic.ini upgrade head
-
Start the bot:
uv run androidrepo-bot
Settings are read from .env and process environment variables prefixed with
AR_. Process environment values take precedence; empty optional tokens are
ignored. See .env.example for annotated examples.
| Variable | Required | Default | Purpose |
|---|---|---|---|
AR_BOT_TOKEN |
yes | — | Telegram bot token |
AR_STAFF_CHAT_ID |
yes | — | Staff supergroup accepted by the bot |
AR_POST_TOPIC_ID |
yes | — | Topic that accepts /post, /cancel, and draft callbacks |
AR_LOG_TOPIC_ID |
yes | — | Topic that receives best-effort audit events |
AR_CHANNEL_ID |
yes | — | Channel that receives confirmed posts |
AR_OPENCODE_ZEN_API_KEY |
yes | — | Credential used by the generation model |
AR_DATABASE_URL |
yes | — | postgresql+asyncpg:// URL used by the runtime and migrations |
AR_LOG_LEVEL |
no | INFO |
Python log level |
AR_OPENCODE_ZEN_MODEL |
no | deepseek-v4-flash |
OpenCode Zen model identifier |
AR_GITHUB_TOKEN |
no | — | GitHub token for higher API limits or authorized access |
AR_GITLAB_TOKEN |
no | — | GitLab token for higher API limits or authorized access |
Telegram chat and channel IDs must be non-zero. Topic IDs must be positive.
Never commit .env or expose credentials in logs, screenshots, issues, or pull
requests.
- In the configured post topic, send
/postfollowed by a GitHub or GitLab repository root URL. - Wait while the bot loads evidence, checks publication history, generates the draft, and renders its banner.
- Review the draft and choose Publish, Regenerate, or Cancel.
- Confirm publication to copy the reviewed message to the configured channel.
The bot answers /start in any chat. It accepts the publication workflow only
in the configured staff chat and post topic.
Draft sessions use in-memory FSM storage and do not survive a process restart.
Publication history is persistent. A repository published within the last
three calendar months is blocked before AI generation and media rendering.
/post repository URL
│
▼
parse and validate RepositoryRef packages/domain
│
▼
fetch and normalize GitHub/GitLab data packages/integrations
│
▼
register identity and check cooldown packages/persistence
│
▼
generate and validate PostDraft packages/ai
│
▼
render PNG banner packages/media
│
▼
review, confirm, publish, and audit apps/bot
Dependency direction is intentional. domain uses only the Python standard
library; application depends only on domain; adapters implement application
ports; and apps/bot composes the system and owns Telegram interaction. Lower
layers do not import Telegram code.
| Path | Responsibility | Documentation |
|---|---|---|
apps/bot |
aiogram entry point, dependency wiring, FSM, and publication | Bot application |
packages/domain |
Framework-independent repository and post values | Domain package |
packages/application |
Use cases, ports, and application errors | Application package |
packages/integrations |
GitHub/GitLab HTTP access and normalization | Integrations package |
packages/ai |
Evidence, structured generation, and validation | AI package |
packages/media |
Artwork acquisition and PNG rendering | Media package |
packages/persistence |
PostgreSQL adapters and Alembic migrations | Persistence package |
Run repository checks from the workspace root:
uv run pytest
uv run pytest --cov
uv run ruff check .
uv run ruff format --check .
uv run pyright
uv run pre-commit run --all-files
uv build --all-packagesCoverage must remain at or above 85%. Tests use pytest-asyncio in strict mode.
Add regression tests beside the package or app that owns the changed behavior.
Telegram flows also require manual validation in the configured staff chat;
record the exercised flow in the pull request.
Keep changes inside the owning layer and use short, focused commits such as
fix: validate gitlab release links. Pull requests should explain behavior and
architecture changes, list the checks run, link related issues, and include a
screenshot or Telegram example for visible changes.
Package READMEs document public contracts and implementation boundaries. When behavior changes, update the owning README and affected public docstrings in the same change. Keep configuration, commands, errors, side effects, and examples aligned with code and tests.
The Android Repository team maintains this service. Use the repository's GitHub issues for verified bugs and scoped improvements. Do not include tokens, authorization headers, database credentials, private chat content, or secret-bearing URLs in a report.
Copyright (C) 2026 Hitalo M.
This project is licensed under the GNU Affero General Public License, version 3 or later (AGPL-3.0-or-later). It may be used, modified, and redistributed under those terms. A modified version made available for remote network interaction must offer its users the corresponding source code, as required by section 13 of the AGPL.
Third-party assets retain their own licenses and attribution requirements; see
packages/media/src/androidrepo_media/assets/README.md.