Skip to main content

tgforwarder (tgf)

A modular, uv-installable Telegram MTProto media-forwarder (Telethon) with:

  • ๐Ÿ“จ Native forwarding of messages/media from any channel, group, or deleted-account chat you still have access to โ€” to one or more destinations (including your Saved Messages).
  • ๐Ÿ” Rust-powered OCR via kreuzberg (precompiled Rust library with a Python API) for automatic file renaming.
  • ๐Ÿ’พ Local-first SQLite dedup cache โ€” resume safely, never re-send.
  • ๐Ÿ“Š Emoji logging โ€” count, per-type breakdown, 5-minute window, file names.
  • ๐Ÿงฉ Oldest / newest ordering, interactive menu, and a --all mode that scales to 5000+ files using O(1) data structures.

Refactored from a monolithic telbot.py/bota.py, inspired by jackwener/tg-cli (local-first, Click CLI, structured output, externalized rate-limiting).

๐Ÿ“ˆ Architecture diagram: see docs/architecture.md (Mermaid).


โš ๏ธ Security: no secrets in git

This repo never commits credentials. TELEGRAM_API_ID, TELEGRAM_API_HASH, session files, and *.db are gitignored. You put them in a local .env file that is never pushed. Always confirm with git status --short | grep '.env' before committing.


Install

Requires uv (same mechanism as tg-cli). Pick one:

uv โ€” pinned release (recommended, reproducible, no clone):

uv tool install "git+https://github.com/dbillion/tgforwarder.git@v0.1.0"
# -> installs the global `tgf` command (~/.local/bin/tgf)

uvx โ€” run without installing (CI / one-off):

uvx --from "git+https://github.com/dbillion/tgforwarder.git@v0.1.0" tgf --help

npx skills โ€” install the agent skills (no npm publish needed):

npx skills add dbillion/tgforwarder -y

This clones the repo and installs both tgf-agent-install and tgf-telegram-forwarder-setup into .agents/skills/ (works with Claude Code, Codex, Cursor, Cline, Antigravity, OpenClaw, +more). (Note: the skills CLI uses add <owner/repo>, not --skill โ€” that flag is from an older write-up and is not valid in current skills.)

npx wrapper โ€” installs tgf via uv (alt): npx -y tgf-forwarder (see installer/).

From a clone:

git clone https://github.com/dbillion/tgforwarder.git && cd tgforwarder
uv tool install . --no-cache
which tgf                          # -> ~/.local/bin/tgf

For local development:

uv venv .venv && . .venv/bin/activate
uv pip install -e .
uv pip install kreuzberg           # fast Rust OCR (optional but recommended)

Verify:

tgf --help
tgf status                        # "api configured: yes" when .env is present

Configure

Create tgforwarder/.env (gitignored โ€” do not commit it):

TELEGRAM_API_ID=your_api_id
TELEGRAM_API_HASH=your_api_hash
TG_SESSION_NAME=forwarder_session1
SOURCE_CHANNELS=-1000000000000        # source channel(s), comma-separated
DEST_CHANNELS=-1000000000001,-1000000000002   # destination(s), comma-separated
FORWARD_PATH=downloads               # local download dir for the OCR fallback

You need a logged-in user session (MTProto cannot use a bot token for this). Copy your existing .session file to ~/.local/share/tg-cli/forwarder_session1.session, or generate one with a Telethon login helper. One session at a time (a concurrent sync holds the DB lock).

Tip: to forward to your Saved Messages, use your own user ID as the destination, e.g. --dest <YOUR_USER_ID> (your Saved Messages user id from tgf score/get_me).


Usage

# Interactive (prompts source/dest/order/mode):
tgf forward

# Explicit, oldest-first (default), 10 messages:
tgf forward --source <SOURCE_CHANNEL> --dest <YOUR_USER_ID> --limit 10

# Forward EVERYTHING, chronological from the channel start:
tgf forward --source <SOURCE_CHANNEL> --dest <YOUR_USER_ID> --all --delay 1 --batch 25

# Resume a previous run (continues from saved last-message id):
tgf forward --resume

# Newest-first:
tgf forward --order newest --limit 50

# Chat usefulness scoring (needs tg-cli's messages.db):
tgf score --db ~/.local/share/tg-cli/messages.db --topic "rust,devops,ai" --top 5

# OCR-only check (read-only, needs a numeric channel ID):
tgf test-ocr --source <SOURCE_CHANNEL>

Options (tgf forward --help)

Option Meaning
--source Source channel/user ID or @handle (or SOURCE_CHANNELS in .env)
--dest Destination (repeatable; or DEST_CHANNELS) โ€” Saved Messages = your user ID
--path Local download dir for the OCR fallback (default ./downloads)
--order oldest (default) or newest
--all Process the entire channel
--limit N Cap messages (ignored with --all)
--resume Continue from last forwarded message id
--start Start from the beginning (ignore saved progress)
--delay S Seconds between batches (anti-ban; default 1.0)
--batch N Messages per forward API call โ€” one call moves the whole batch (default 25). Raise for speed, lower if rate-limited

Throughput

tgf batches N messages into a single forward_messages API call, so throughput is N files per call. With --batch 25 --delay 1 you move ~25 files/second of wall-clock (one call + 1s pause). Telegram's copy endpoint can sustain far more; if you're not rate-limited, raise --batch (e.g. 50โ€“100) and drop --delay toward 0. The dedup cache and O(1) set lookup keep per-message overhead flat at 5000+ files.

Deleted-account chats

If a chat belongs to a deleted account you can still read, resolve_entity falls back to the session's cached InputPeer, so forwarding still works (native forward_messages preserves the original file exactly).


Upgrade

cd tgforwarder
git pull                 # or copy updated sources
uv tool uninstall tgforwarder
uv build --wheel --no-cache
uv tool install . --no-cache

Add a dependency (e.g. a new OCR backend):

uv pip install some-pkg
# then add it to dependencies in pyproject.toml and rebuild

Run the test suite (offline, no network/API):

uv run pytest -q        # 14 tests

For agents (npx-style install)

Agents can install and operate tgf without manual setup. Load the tgf-agent-install skill (Hermes) which runs the uv tool install flow and a verification checklist. Minimum the agent must do:

# 1. ensure uv
command -v uv || curl -LsSf https://astral.sh/uv/install.sh | sh
# 2. install tgf from this repo
uv tool install . --no-cache
# 3. write a local .env (NEVER commit it) with API id/hash + session
# 4. verify
tgf status

Agents should treat .env as a secret: write it locally, gitignore it, and never paste values into shared logs.


Project layout

tgforwarder/
โ”œโ”€โ”€ pyproject.toml          # setuptools build, [project.scripts] tgf
โ”œโ”€โ”€ tgforwarder/
โ”‚   โ”œโ”€โ”€ client.py           # TelegramClient + resolve_entity (+ deleted-account fallback)
โ”‚   โ”œโ”€โ”€ cache.py            # ForwardCache (SQLite dedup, load_done_set, mark_many)
โ”‚   โ”œโ”€โ”€ forward.py          # kreuzberg (Rust) OCR primary, Tesseract fallback
โ”‚   โ”œโ”€โ”€ state.py            # resume persistence (last_id + direction)
โ”‚   โ”œโ”€โ”€ report.py           # ForwardLogger (deque/Counter, O(1) at 5000+ files)
โ”‚   โ”œโ”€โ”€ cli.py              # Click CLI
โ”‚   โ””โ”€โ”€ __init__.py
โ”œโ”€โ”€ tests/test_offline.py   # 14 offline tests
โ”œโ”€โ”€ docs/architecture.md    # Mermaid diagram + data-flow
โ””โ”€โ”€ README.md

License

MIT.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tgforwarder-0.2.1.tar.gz (37.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tgforwarder-0.2.1-py3-none-any.whl (32.2 kB view details)

Uploaded Python 3

File details

Details for the file tgforwarder-0.2.1.tar.gz.

File metadata

  • Download URL: tgforwarder-0.2.1.tar.gz
  • Upload date:
  • Size: 37.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tgforwarder-0.2.1.tar.gz
Algorithm Hash digest
SHA256 67487b342faa016fd9cfbfa675aee6feb28a32b7e350437c17dbcc65344dd1f3
MD5 c2a6c89489127289b44e702aa47641fc
BLAKE2b-256 d0dfa730ef82e3fbd5802fdee083e08b411204da5ee35110d7bfe969e13ca777

See more details on using hashes here.

File details

Details for the file tgforwarder-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: tgforwarder-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 32.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for tgforwarder-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 48e727cdb719c4914a5b4a8ebd7b1bad23ae1d88034654e65c5d6eeee870d770
MD5 74492ba96e796587a9d61917b2e38f15
BLAKE2b-256 5174fe3e1ef9e110c3de2cd024a43e2a7422125116e0325d37023a18277c1724

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.2.1 This release

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page