A small, single-threaded Rust Telegram guest bot. Mention it in a chat and it replies with exactly 🪨👍 or 🪨👎, each with an independent 50% chance. Replying to its guest message triggers another flip. No AI model is involved.
-
Create a bot with
@BotFatherand obtain its token. -
Open BotFather's Mini App, select your bot, and enable Guest Mode in its settings.
-
Build and run (Rust 1.85+):
cargo build --release --locked read -rs -p 'Bot token: ' TELEGRAM_BOT_TOKEN export TELEGRAM_BOT_TOKEN ./target/release/rock
-
Send a message such as
@your_bot should I do it?in a supported Telegram chat. The bot can answer without being added to that chat.
Only guest_message updates are handled; ordinary direct messages and inline
queries are ignored. Stop with Ctrl+C. Run only one instance per bot token.
If this token previously used webhooks, remove its webhook with Telegram's
deleteWebhook method first;
webhooks and long polling cannot run together.
Create a local .env containing TELEGRAM_BOT_TOKEN=your_bot_token, then run:
docker compose config --quiet
docker compose pull
docker compose up --no-build -d
docker compose logs --tail 20 rockStop with docker compose down. Do not run the native bot at the same time.
To build locally instead, use docker compose up --build -d.
The multi-stage build runs the tests and produces a static musl executable in a
scratch image. The Rust builder is pinned by version and digest. The build
context allowlists only the Cargo manifests and Rust sources; .env is injected
at runtime and never copied into the image. TLS uses rustls's bundled roots.
Compose runs as UID/GID 10001:10001, with a read-only root filesystem, all
Linux capabilities dropped, and privilege escalation disabled. Limits are
32 MiB RAM (no additional swap), 0.25 CPU, 16 tasks, and three 1 MiB log files.
There are no published ports or mounted volumes; the bot only needs outbound
DNS and HTTPS. Docker's default seccomp profile remains enabled.
GitHub Actions
builds and runs the Dockerfile's tests on pull requests. Pushes to main publish
ghcr.io/fivepebblesgpt/rock:latest; version tags such as v0.1.0 publish
ghcr.io/fivepebblesgpt/rock:0.1.0. Builds also publish a full sha-<commit> tag.
Images currently target Linux amd64 and include provenance and SBOM attestations.
Actions are pinned to commit hashes. Publishing uses the workflow's short-lived
GITHUB_TOKEN with packages: write; no Telegram credentials are needed in CI.
The .env file, local build artifacts, and editor settings are excluded from Git.
- Blocking HTTPS with connection reuse; no async runtime, worker pool, database, or listening server. Long polling sleeps on the network for up to 50 seconds.
- Only the guest query ID and update ID are deserialized; message contents and attached media are ignored. Media files are never downloaded.
- One OS-random bit per invocation gives unbiased 1:1 odds. Small samples need not contain equal numbers of each reply.
- Polling failures use exponential backoff (1–60 seconds), respecting Telegram's
retry_after. Rate-limited replies are retried once with the same outcome. - Other failed replies are logged and skipped, avoiding automatic resends after an ambiguous network failure. Updates are acknowledged on the next poll; a crash before acknowledgment can cause redelivery. No durable state is kept.
- Release builds use size optimization, LTO, symbol stripping, and abort-on-panic.
Actual memory use and binary size depend on your target and TLS libraries.
cargo fmt --check
cargo clippy --all-targets --locked -- -D warnings
cargo test --locked