Skip to content

About

a Telegram bot for casual team games among friends: who's in, who's maybe, the teams and the payment reminder.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

7 stars

Watchers

1 watching

Forks

Latest commit

 

History

208 Commits

Folders and files

PartitelleBot logo

PartitelleBot

Telegram bot that organizes casual team games among friends: who is in, who is maybe, and the teams.

telegram: @PartitelleBot website: partitelle.com license: AGPL-3.0

what it is

PartitelleBot keeps the participant list of the weekly match in a Telegram group and updates a single summary message as people join or drop out. When the list is full it splits the players into two random teams, and after the match it reminds the group to pay the pitch. The bot talks Italian; this README is in English.

It is a Python 3.12 project built on the async API of python-telegram-bot (v22). The bot runs on Render and stores its data in PostgreSQL on Neon (see docs/neon-db.md).

how to use it in a group

  1. Add @PartitelleBot to the group. Giving it administrator rights lets it pin its messages.
  2. Send /start to create the match. By default it is the next Wednesday at 20:00 (today, if it is a Wednesday and 20:00 has not passed yet), with 10 players. Change it with /setday, /settime and /setnumber.
  3. Everybody writes plain chat keywords (see below) to join. The bot prints the summary the first time and then edits it in place; /participants shows it again on demand.
  4. Once the confirmed players reach the target, the bot announces it and you can run /teams to get a black and a white team.
  5. Teams can be adjusted with scambia <name 1> con <name 2>. Removing a player or marking one as maybe revokes the teams (the bot says so); /teams generates them again.
  6. The day after the match, at no exact time, the bot asks the group whether everybody paid, and pins the message if it can. The reminder state is stored in the database, and a daily scheduled job calls an authenticated endpoint that sends it.

The summary looks like this (the pitch and the description are editable):

GIORNO: Mercoledì 04/11/2026 | 20:00

1. Anna ✅
2. Marco ❓
3. ❌
...

<description>

CAMPO:
<pitch>

✅ is confirmed, ❓ is maybe, ❌ is a free slot.

chat keywords

Keywords are plain messages, not commands. The message must start exactly with the keyword, and names are matched ignoring case. aggiungi, proponi accept several comma-separated names (aggiungi luca, sara). The names are free text: they do not have to be Telegram users.

message effect
aggiungimi add yourself, or confirm yourself if you were maybe
aggiungi <name> add someone, or confirm them if they were maybe
proponimi add yourself as maybe
proponi <name> add someone as maybe
toglimi remove yourself, whether confirmed or maybe
togli <name> remove one person, whether confirmed or maybe
scambia <name 1> con <name 2> swap two players of different teams (needs teams from /teams)

commands

/setday and /settime read a human date or time and refuse anything they cannot understand.

command description
/start create the match of the chat (does nothing if one is already active)
/setnumber <n> number of players, up to 40; teams need an even number. Revokes existing teams
/setday <date> day of the match, day first, e.g. /setday 25/10/2026
/settime <time> time of the match, e.g. /settime 21:30, /settime 21.30 or /settime 20
/setdescription <text> text shown under the list; Telegram markdown is allowed
/setpitch <name> pitch shown at the bottom of the summary
/participants show the summary of the current match
/teams generate the teams once the target is reached, or show the existing ones
/stop stop the current match; it is kept as history and /start can create a new one
/help list keywords and commands

mini app

When the bot is configured with a Mini App (PB_MINIAPP_SHORT_NAME, see CONTRIBUTING.md), every summary carries an apri la lista button. It opens the list of that match inside Telegram, where members of the chat can join, propose themselves or leave, add or propose other people by name, remove someone from the list, draw the teams and swap two players between teams, with the same rules and the same effects on the group as the chat keywords (when someone acts on others, the group message says who did it). Every member of the chat can use every action. The link is private to the match: a new /start creates a new link and the old one stops working. Without PB_MINIAPP_SHORT_NAME the feature is off: no button and no /app routes.

development

Setup, workflow and conventions are in CONTRIBUTING.md.

Prerequisites: uv and Docker.

  1. create your own bot with BotFather and copy its token
  2. cp default.env .env and set PB_TG_TOKEN to your token
  3. docker compose up -d starts a local PostgreSQL
  4. uv sync installs the dependencies
  5. uv run --env-file .env python -m db.migrate creates the PB_DB_SCHEMA schema and applies the migrations in migrations/
  6. uv run --env-file .env python main.py starts the bot (with ENV=local it uses polling instead of a webhook)
  7. uv run pytest runs the tests

The .env file is not loaded automatically by the code: pass it with uv run --env-file .env as above (or export the variables in your shell). Use docker compose down -v to also drop the local data.

variable meaning
ENV local runs the bot in polling mode, any other value uses a webhook
PB_TG_TOKEN Telegram bot token
PB_URL public URL of the hosting, used for the webhook (not needed locally)
PB_VERSION optional version shown by GET /health; defaults to the short RENDER_GIT_COMMIT
PB_JOBS_SECRET optional bearer token for POST /jobs/payment-reminders; when unset or empty the endpoint is disabled (404)
PB_WEBHOOK_SECRET optional secret Telegram sends with every webhook call ([A-Za-z0-9_-], 1-256 chars); when unset it is derived from PB_TG_TOKEN
PB_DB_SCHEMA PostgreSQL schema of the environment: prod or staging (mandatory: the bot does not start without it)
PB_DB_HOST PostgreSQL host
PB_DB_NAME PostgreSQL database name
PB_DB_USER PostgreSQL user
PB_DB_PASSWORD PostgreSQL password
PB_DB_PORT PostgreSQL port (also the host port published by docker compose)
PB_DB_SSLMODE optional: libpq sslmode of every database connection, default require; set disable for the local docker compose database (already in default.env)
PB_DB_MIGRATE_USER, PB_DB_MIGRATE_PASSWORD optional: credentials used only by python -m db.migrate, to run the bot with a role that cannot change the schema (see docs/neon-db.md); set both or neither, default PB_DB_USER/PB_DB_PASSWORD

sponsorships

Nothing mandatory, just do it if you feel like offering a coffee: tap the Sponsor button at the top, or click here.

privacy

How partitelle handles your data: partitelle.com/privacy.

license

Released under the GNU Affero General Public License v3.0, see LICENSE. Versions up to 1.6.2 were released under the GNU General Public License v3.0.

The name "partitelle", the name "PartitelleBot" and the whistle mark are not covered by the license: see TRADEMARKS.md.

About

a Telegram bot for casual team games among friends: who's in, who's maybe, the teams and the payment reminder.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

7 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages