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
--allmode 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 fromtgf 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
.envas 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
67487b342faa016fd9cfbfa675aee6feb28a32b7e350437c17dbcc65344dd1f3
|
|
| MD5 |
c2a6c89489127289b44e702aa47641fc
|
|
| BLAKE2b-256 |
d0dfa730ef82e3fbd5802fdee083e08b411204da5ee35110d7bfe969e13ca777
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48e727cdb719c4914a5b4a8ebd7b1bad23ae1d88034654e65c5d6eeee870d770
|
|
| MD5 |
74492ba96e796587a9d61917b2e38f15
|
|
| BLAKE2b-256 |
5174fe3e1ef9e110c3de2cd024a43e2a7422125116e0325d37023a18277c1724
|