# Tg Hub

> A skill for reading and writing Telegram data with Python and UV. It depends only on Telethon and uses a local-first architecture: messages are synced to SQLite and then queried offline. On first use, you must log in from the terminal with a phone number verification code. After that, the session is persisted and you do not need to log in again. Supports syncing group and channel messages locally, keyword search, multi-keyword filtering, today's messages, recent messages, speaker rankings, timeline statistics, and more. This skill must be triggered whenever the user mentions "Telegram", "TG", "Telegram", "tg-hub", "sync Telegram messages", "search TG groups", "Telegram keywords", "get TG messages", or any scenario that requires programmatically reading or writing Telegram data.

- Skill: `openminis/tg-hub` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add openminis/tg-hub`
- Raw SKILL.md: https://api.skillmd.com/api/skills/openminis/tg-hub/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: openminis (https://skillmd.com/u/openminis)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/openminis/tg-hub

---


# tg-hub

> **Based on**: [jackwener/tg-cli](https://github.com/jackwener/tg-cli) (Apache-2.0)
>
> This skill simplifies the original repository as follows:
> - Removed the `click` / `rich` / `python-dotenv` / `pyyaml` dependencies
> - Kept only `telethon` as a third-party dependency
> - Removed the CLI layer and encapsulated all functionality as a synchronous Python API
> - Changed the default session/db path to `/var/minis/workspace/tg-hub/`
> - Changed configuration to read environment variables directly, with no `.env` file required

---

## Architecture: Local-First

```
Telegram MTProto (telethon)
    ↓  sync / refresh (incremental)
Local SQLite  ~/.tg-hub/messages.db
    ↓  search / today / recent / filter (offline)
Structured data
```

- **Read operations** (search/today/recent): query the local SQLite database, with **no network access**, and respond in milliseconds
- **Write operations** (sync/refresh): connect to Telegram to fetch new messages and write them incrementally to SQLite
- Session file: `~/.tg-hub/tg_hub.session`

---

## File Structure

```
/var/minis/skills/tg-hub/
├── SKILL.md
├── pyproject.toml          # telethon only
└── scripts/
    ├── __init__.py
    ├── config.py           # Configuration (environment variables / default paths)
    ├── db.py               # SQLite message storage
    ├── exceptions.py       # Structured exceptions
    └── client.py           # TGClient core class (all APIs)
```

---

## First-Time Login (Must Be Done in Terminal)

tg-hub uses the **MTProto protocol** (not the Bot API), so you need to log in with your Telegram account.

> **Recommendation**: Use your own `TG_API_ID` / `TG_API_HASH` whenever possible.
> I have synced the upstream tg-cli anti-risk-control implementation: it uses a Telegram Desktop 5.x fingerprint and prints a warning if you continue using the default `api_id=2040`. The public app ID is only a fallback. Using your own credentials is still recommended for long-term use.

```
1. Open Terminal
2. (Recommended) Set your own TG_API_ID / TG_API_HASH first
3. cd /var/minis/skills/tg-hub
4. uv run python -c "
   import sys; sys.path.insert(0,'.')
   from scripts.client import TGClient
   me = TGClient().login()
   print('Login successful:', me)
   "
5. Enter your phone number when prompted (in +86XXXXXXXXXX format)
6. Enter the verification code received in the Telegram app
7. After login succeeds, the session is saved automatically and future logins are not required
```

> If you do not have your own credentials for now, you can log in with the built-in public credentials first. If you encounter login or fetch errors, switch to your own APP ID first.

[Open Terminal to log in](minis://open_terminal?init_command=cd%20%2Fvar%2Fminis%2Fskills%2Ftg-hub%20%26%26%20uv%20run%20python%20-c%20%22import%20sys%3B%20sys.path.insert(0%2C'.')%3B%20from%20scripts.client%20import%20TGClient%3B%20TGClient().login()%22)

---

## Quick Start

### Environment Setup

```bash
cd /var/minis/skills/tg-hub
uv sync
```

### Python Usage

```python
import sys
sys.path.insert(0, "/var/minis/skills/tg-hub")
from scripts.client import TGClient

client = TGClient()

# View the current account
me = client.whoami()
print(me["name"], me["phone"])

# List all conversations (fetched from TG in real time)
chats = client.list_chats()
for c in chats[:10]:
    print(f"  [{c['type']}] {c['name']}  Unread: {c['unread']}")

# Incrementally sync a single group
n = client.sync("Group name or username", limit=1000)
print(f"Added {n} messages")

# Quickly refresh all groups (up to 500 new messages per group)
# Slight throttling is enabled by default; you can also limit this round to only the first 30 chats
result = client.refresh(delay=1.0, max_chats=30)
for name, count in result.items():
    if count > 0:
        print(f"  {name}: +{count}")

# Search by keyword
msgs = client.search("Python", hours=48)
for m in msgs:
    print(f"[{m['chat_name']}] {m['sender_name']}: {m['content'][:80]}")

# Multi-keyword filtering (OR logic)
msgs = client.filter("hiring,remote,part-time", hours=24)

# Today's messages
msgs = client.today()

# Messages from the last 12 hours
msgs = client.recent(hours=12, limit=200)

# Speaker rankings
top = client.top_senders(hours=24)
for t in top[:5]:
    print(f"  {t['sender_name']}: {t['msg_count']} messages")

# Timeline statistics
tl = client.timeline(granularity="hour", hours=48)

# Local database statistics
stats = client.stats()
print(f"{stats['total']} local messages across {len(stats['chats'])} groups")
```

---

## API Quick Reference

### Authentication

| Method | Description |
|------|------|
| `login()` | Interactive login (first time, requires terminal) |
| `whoami()` | Get current account information |

### Sync (Online)

| Method | Description |
|------|------|
| `list_chats(chat_type=None)` | List all conversations (real time) |
| `sync(chat, limit=5000)` | Sync a single group to local SQLite |
| `sync_all(limit_per_chat=5000, delay=1.0, max_chats=None)` | Sync all groups (with throttling/count limit) |
| `refresh(limit_per_chat=500, delay=1.0, max_chats=None)` | Quick incremental refresh (recommended for daily use) |

### Query (Local, Offline)

| Method | Description |
|------|------|
| `search(keyword, *, chat, sender, hours, regex, limit)` | Keyword/regex search |
| `filter(keywords, *, chat, hours)` | Multi-keyword OR filtering |
| `today(chat=None)` | Today's messages |
| `recent(hours=24, *, chat, sender, limit)` | Messages from the last N hours |
| `top_senders(chat, hours, limit)` | Speaker rankings |
| `timeline(chat, hours, granularity)` | Timeline statistics |
| `stats()` | Database statistics |
| `local_chats()` | List of locally synced groups |
| `delete_chat(chat)` | Delete local messages for a group |

---

## Environment Variables

| Variable | Default Value | Description |
|------|--------|------|
| `TG_API_ID` | `2040` (fallback only) | **Recommended: replace with your own** API ID |
| `TG_API_HASH` | Built in (fallback only) | **Recommended: replace with your own** API Hash |
| `TG_SESSION_NAME` | `tg_hub` | Session filename |
| `TG_DATA_DIR` | `~/.tg-hub` | Data directory |
| `TG_DB_PATH` | `{TG_DATA_DIR}/messages.db` | SQLite path |
| `TG_DEVICE_MODEL` | `Desktop` | Telethon client device model |
| `TG_SYSTEM_VERSION` | `macOS 15.3` | Telethon client system version |
| `TG_APP_VERSION` | `5.12.1` | Telethon client version |
| `TG_LANG_CODE` | `en` | Client language code |
| `TG_SYSTEM_LANG_CODE` | `en-US` | System language code |

---

## Account Security Recommendations

1. **Use your own API credentials whenever possible**: Go to `https://my.telegram.org`, create an application, and then set `TG_API_ID` / `TG_API_HASH`.
2. **Control sync frequency**: Avoid repeatedly running `refresh()` at high frequency.
3. **Use `delay` and `max_chats`**: For daily incremental refreshes, we recommend limiting the number of chats synced per round and keeping an interval between chats.
4. **Do not be too aggressive with the first full sync**: tg-hub automatically applies a lower fetch limit for the first sync of each chat.
5. **Prefer read operations**: Local queries such as search and statistics do not use the network, so they are much lower risk than frequent syncs.

---

## Notes

- The first login must be completed in an interactive terminal (a verification code is required).
- **Using your own `TG_API_ID` / `TG_API_HASH` is strongly recommended** to avoid risk-control issues caused by abuse of the public APP ID.
- tg-hub is aligned with the upstream tg-cli Telegram Desktop 5.x client fingerprint and retains environment variable overrides to reduce the risk of abnormal fingerprints.
- If you are still using the default `api_id=2040`, a warning is printed during connection to remind you to switch to your own `TG_API_ID` / `TG_API_HASH`.
- The session file is stored at `/var/minis/workspace/tg-hub/tg_hub.session`. Keep it safe.
- The first run of `sync_all` may take a long time, depending on the number of groups and the amount of historical messages.
- We recommend using `refresh()` for daily incremental updates and `sync(chat, limit=10000)` for the initial full sync.
- Telegram applies rate limits to API requests. During large syncs, Telethon automatically handles flood waits.

