{"id":51715481,"url":"https://github.com/tomusdrw/telemach-bot","last_synced_at":"2026-07-17T02:09:52.793Z","repository":{"id":367026048,"uuid":"1242302044","full_name":"tomusdrw/telemach-bot","owner":"tomusdrw","description":"A personal Telegram bot that forwards messages, attachments, and transcribed voice notes to your email. Subject lines generated by an LLM via OpenRouter, delivery via Resend. Multi-user with admin approval. Single container, one mounted data volume.","archived":false,"fork":false,"pushed_at":"2026-07-08T21:40:40.000Z","size":249,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-08T23:18:12.154Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tomusdrw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-18T09:55:31.000Z","updated_at":"2026-07-08T21:40:43.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tomusdrw/telemach-bot","commit_stats":null,"previous_names":["tomusdrw/telemach-bot"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/tomusdrw/telemach-bot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomusdrw%2Ftelemach-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomusdrw%2Ftelemach-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomusdrw%2Ftelemach-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomusdrw%2Ftelemach-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tomusdrw","download_url":"https://codeload.github.com/tomusdrw/telemach-bot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tomusdrw%2Ftelemach-bot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35563726,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-17T02:00:06.162Z","response_time":116,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-17T02:09:52.324Z","updated_at":"2026-07-17T02:09:52.787Z","avatar_url":"https://github.com/tomusdrw.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# telemach-bot\n\n[![CI](https://github.com/tomusdrw/telemach-bot/actions/workflows/ci.yml/badge.svg)](https://github.com/tomusdrw/telemach-bot/actions/workflows/ci.yml)\n\nA personal Telegram bot that forwards messages, attachments, and transcribed\nvoice notes to your email. Subject lines generated by an LLM via OpenRouter,\ndelivery via Resend. Multi-user with admin approval. Single container, one\nmounted data volume.\n\nSee `docs/superpowers/specs/2026-05-18-telegram-email-bot-design.md` for the\nfull design.\n\n## Quick start (Docker)\n\n1. Copy `.env.example` to `.env` and fill in:\n   - `TELEGRAM_BOT_TOKEN` from @BotFather\n   - `ADMIN_TELEGRAM_USER_ID` (your numeric Telegram user id, ask @userinfobot)\n   - `ADMIN_EMAIL`\n   - `OPENROUTER_API_KEY` (used for both transcription and subject generation)\n   - Optionally override `OPENROUTER_MODEL` (subjects) and `OPENROUTER_TRANSCRIPTION_MODEL` (voice → text)\n   - Optionally set `EVENT_MODEL` (event extraction) and `EXPANSION_MODEL` (body cleanup/expansion); both default to `OPENROUTER_MODEL`\n   - `RESEND_API_KEY` and `RESEND_FROM_EMAIL` (must be a verified Resend domain)\n2. Create the data directory with the right ownership. The container runs as the\n   `node` user (UID 1000); the bind-mount preserves host UID, so:\n\n   ```bash\n   mkdir -p data\n   sudo chown 1000:1000 data\n   ```\n\n   Skip the `chown` if your host user is already UID 1000 (typical for a fresh\n   non-root user on most Linux distros).\n3. `docker compose up -d --build` (or pull the prebuilt image — see below).\n4. DM your bot `/start`.\n\n### Using the prebuilt image from GHCR\n\nEvery push to `main` builds and publishes an image to\n`ghcr.io/tomusdrw/telemach-bot`. To pull it instead of building locally, edit\n`docker-compose.yml`:\n\n```yaml\nservices:\n  telemach-bot:\n    image: ghcr.io/tomusdrw/telemach-bot:latest   # remove `build: .`\n    # ... rest unchanged\n```\n\nThen `docker compose pull \u0026\u0026 docker compose up -d`.\n\n## Development\n\n```bash\nnpm install\nnpm test\nnpm run dev\n```\n\n## How it works\n\n- `/start` → bot greets, asks for `/register your@email.com`.\n- `/register` → bot stores email, DMs admin with Approve/Reject buttons.\n- After approval, forwarded messages are acknowledged with reactions only:\n  👀 received → ✍ working → 👍 sent (or 💩 on error).\n- A short, single-line message (≤ 80 chars) becomes the email subject verbatim;\n  longer messages get an LLM-generated subject. For every text message the LLM\n  also appends a cleaned-up/expanded rendition (typos fixed, terse notes spelled\n  out) below the original in the body; links are left untouched.\n- Voice messages are transcribed via OpenRouter's `/audio/transcriptions`\n  endpoint (default model: `openai/whisper-large-v3`, override with\n  `OPENROUTER_TRANSCRIPTION_MODEL`). The transcript is sent as the email\n  body; original audio is not attached.\n- Photos/documents/videos/audio/animations/stickers are attached verbatim.\n- Multiple photos uploaded together bundle into one email.\n- When a message contains a date, the bot extracts the event and attaches an\n  `.ics` calendar file to the email so you can add it to your calendar in one\n  click. A 📅 reaction confirms the attachment was created.\n- `/timezone Europe/London` sets your per-user IANA timezone (default:\n  `Europe/Warsaw`). Run `/timezone` with no argument to see the current value.\n  Affects how calendar invite times are interpreted and displayed.\n\n## Admin commands\n\nThese work only when invoked by the configured `ADMIN_TELEGRAM_USER_ID`:\n\n- `/users` — list up to 50 most-recent users with status and email.\n- `/revoke \u003ctelegramId\u003e` — flip an `APPROVED` user to `REJECTED`. Refuses to act on the admin.\n- `/reset \u003ctelegramId\u003e` — clear the user's email and return them to `PENDING_EMAIL` so they can re-register.\n\n## Troubleshooting\n\n- **💩 reaction on every message.** Check the container logs (`docker compose\n  logs -f telemach-bot`). The error class (`TransientError`/`FatalError`) and\n  provider (`whisper` / `openrouter` / `resend` / `telegram` / `db`) are in\n  every error line. The most common first-deploy cause is an unverified\n  `RESEND_FROM_EMAIL` domain — verify the domain at\n  \u003chttps://resend.com/domains\u003e before sending the first message.\n\n- **Container exits immediately with \"Invalid environment\".** A required env\n  var is missing. The fatal log line lists every missing or invalid var name.\n\n- **`EACCES: permission denied, open '/data/bot.db'`.** The bind-mounted host\n  directory is owned by the wrong UID. Run `sudo chown 1000:1000 data` on the\n  host.\n\n- **Bot never responds to `/start`.** Double-check `TELEGRAM_BOT_TOKEN`. The\n  container logs a `{\"msg\":\"bot online\"}` line on successful login.\n\n- **Approved user can't actually send anything.** Confirm the admin tapped\n  Approve (look for `Approved @username ✓` in your own admin DM). If the\n  status got stuck in `PENDING_APPROVAL`, fix it directly:\n\n  ```bash\n  docker compose exec telemach-bot \\\n    sqlite3 /data/bot.db \"UPDATE users SET status='APPROVED' WHERE telegram_id=\u003cid\u003e;\"\n  ```\n\n- **Disable / un-approve a user (no command for this yet).**\n\n  ```bash\n  docker compose exec telemach-bot \\\n    sqlite3 /data/bot.db \"UPDATE users SET status='REJECTED' WHERE telegram_id=\u003cid\u003e;\"\n  ```\n\n- **See recent activity for a user.**\n\n  ```bash\n  docker compose exec telemach-bot \\\n    sqlite3 /data/bot.db \\\n    \"SELECT created_at, event, details FROM audit_log\n       WHERE telegram_id=\u003cid\u003e ORDER BY id DESC LIMIT 20;\"\n  ```\n\n## Updating\n\n```bash\ngit pull\ndocker compose up -d --build\n```\n\nThe SQLite file in `./data/bot.db` survives rebuilds.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomusdrw%2Ftelemach-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftomusdrw%2Ftelemach-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftomusdrw%2Ftelemach-bot/lists"}