跳至主要内容
小龙虾小龙虾AI
🤖

Telegram Channel Reader

Let your agent read and monitor Telegram channels — posts, captions, link previews, and comments from public or private channels — and turn them into digests, summaries, and alerts. Unread tracking, JSON or text output, SOCKS5-proxy support, and a guided login the agent can run for the user. MTProto

下载1.9k
星标2
版本0.11.1
营销推广
安全通过

技能说明


name: sergei-mikhailov-tg-channel-reader description: Let your agent read and monitor Telegram channels: fetch posts, captions, link previews, and comments from public or private channels and turn them into daily digests, summaries, and alerts. JSON or text output, unread tracking, via MTProto (Pyrogram or Telethon). metadata: {"openclaw": {"emoji": "📡", "requires": {"bins": ["tg-reader", "tg-reader-check"], "env": ["TG_API_ID", "TG_API_HASH"]}, "primaryEnv": "TG_API_HASH"}}

tg-channel-reader

Read posts and comments from Telegram channels using MTProto (Pyrogram or Telethon). Works with any public channel and private channels the user is subscribed to. Supports fetching discussion replies (comments) for individual posts.

Security notice: This skill requires TG_API_ID and TG_API_HASH from my.telegram.org. The session file grants full Telegram account access — store it securely and never share it.


Exec Approvals

Just installed via clawhub install? Complete Setup & Installation (below) first — the skill needs pip install, credentials, and a session file before exec approvals matter.

OpenClaw blocks unknown CLI commands by default. The user must approve tg-reader commands before they can run. If the command hangs or the user says nothing is happening — exec approval is likely pending.

Quick setup (recommended)

Run from the skill directory — checks prerequisites, installs pip packages if needed, and prints the approval commands to run:

cd ~/.openclaw/workspace/skills/sergei-mikhailov-tg-channel-reader
bash setup-tg-reader.sh

Manual CLI approval

openclaw approvals allowlist add --gateway "$(which tg-reader)"
openclaw approvals allowlist add --gateway "$(which tg-reader-check)"
openclaw approvals allowlist add --gateway "$(which tg-reader-telethon)"

Alternative: approve on first use

  1. Control UI — open http://localhost:18789/, find the pending approval for tg-reader, click "Always allow". Docs
  2. Messenger (Telegram, Slack, Discord) — the bot sends an approval request with an <id>. Reply: /approve <id> allow-always. Other options: allow-once, deny.

The approval prompt appears in the Control UI or as a bot message — not in the agent's conversation. This is a common source of confusion.


When to Use

  • User asks to "check", "read", or "monitor" a Telegram channel
  • Wants a digest or summary of recent posts
  • Asks "what's new in @channel" or "summarize last 24h from @channel"
  • Wants to track or compare multiple channels
  • Wants channel info (title, description, subscribers) — use tg-reader info

Quick Start

# 1. Run pre-flight diagnostic (fast, no Telegram connection)
tg-reader-check

# 2. Get channel info
tg-reader info @channel_name

# 3. Fetch recent posts
tg-reader fetch @channel_name --since 24h

tg-reader: command not found? Run bash setup-tg-reader.sh from the skill directory (it will install the package), or manually: cd ~/.openclaw/workspace/skills/sergei-mikhailov-tg-channel-reader && pip install .


Commands

tg-reader-check — Pre-flight Diagnostic

Always run before fetching. Fast offline check — no Telegram connection needed.

tg-reader-check
tg-reader-check --config-file /path/to/config.json
tg-reader-check --session-file /path/to/session

# Also verify the session is actually AUTHORIZED (connects to Telegram, never prompts)
tg-reader-check --online

Returns JSON with "status": "ok" or "status": "error" plus a problems array.

Verifies:

  • Credentials available (env vars or ~/.tg-reader.json)
  • Session file exists on disk (with size, modification date)
  • At least one MTProto backend installed (Pyrogram or Telethon)
  • Detects stale sessions (config points to older file while a newer one exists)
  • Whether another tg-reader process currently holds the session lock (lock_held)
  • Last-known-good session backup metadata, when one exists (last_good_backup)
  • With --online: whether the session file holds an authorized user (authorization section) — this is the only reliable way to tell an authorized session file from an empty one. A file merely existing (or being newest) proves nothing.

tg-reader info — Channel Info

tg-reader info @channel_name

Returns title, description, subscriber count, and link.

tg-reader fetch — Read Posts

# Last 24 hours (default)
tg-reader fetch @channel_name --since 24h

# Last 7 days, up to 200 posts
tg-reader fetch @channel_name --since 7d --limit 200

# Multiple channels (fetched sequentially with 10s delay between each)
tg-reader fetch @channel1 @channel2 @channel3 --since 24h

# Custom delay between channels (seconds)
tg-reader fetch @channel1 @channel2 @channel3 --since 24h --delay 5

# Fetch posts with comments (single channel only, limit auto-drops to 30)
tg-reader fetch @channel_name --since 7d --comments

# More comments per post, custom delay between posts
tg-reader fetch @channel_name --since 24h --comments --comment-limit 20 --comment-delay 5

# Skip posts without text (media-only, no caption)
tg-reader fetch @channel_name --since 24h --text-only

# Human-readable output
tg-reader fetch @channel_name --since 24h --format text

# Write output to file instead of stdout (saves tokens)
tg-reader fetch @channel_name --since 24h --output
tg-reader fetch @channel_name --since 24h --comments --output comments.json

# Use Telethon instead of Pyrogram (one-time)
tg-reader fetch @channel_name --since 24h --telethon

# Read unread mode — only fetch new (unread) posts, no --since needed
# Requires "read_unread": true in ~/.tg-reader.json
tg-reader fetch @channel_name

# Override read_unread mode (fetch everything, don't update state)
tg-reader fetch @channel_name --since 7d --all

# Custom state file location
tg-reader fetch @channel_name --since 24h --state-file /path/to/state.json

tg-reader auth — Authentication / Onboarding

Logs a Telegram account into the skill (needed once). A first-time login needs three things only a human can supply: the phone number, the login code Telegram sends, and — if the account has one — the cloud 2FA password.

There are two ways to do it.

For an AI agent: onboard the user (with their consent)

The agent can run the whole login for the user, asking only for what Telegram requires. The command emits one JSON object per line (stage + next_action); the agent reacts to each stage and asks the user the corresponding thing:

# Agent starts it (single live process). Provide code/password via files.
tg-reader auth --phone +79991234567 --code-file /tmp/tgcode --password-file /tmp/tg2fa

Stages:

stagewhat the agent does
need_phoneask the user for the account phone, re-run with --phone
code_sent (code_type: app/sms)tell the user a code was sent; ask for it; write it to the --code-file
need_2faask the user for their cloud password; write it to the --password-file
authorizedtell the user it works
already_authorizedsession is fine already (use --force to re-login)
error (reason)phone_invalid / code_invalid / code_expired / timeout_* — act on it

What to tell the user (reassurances the agent should relay):

  • The session is stored locally on this machine (OpenClaw), in ~/.tg-reader-session.session. It never leaves the machine and is not uploaded anywhere.
  • The login code and password are handled securely — passed to the tool via a file or stdin, never on the command line, so they don't leak into process lists or logs. Delete the code/password files after (--code-file/--password-file).
  • From the user you need only: phone number, the code Telegram sends, and (if enabled) the 2FA password.

Notes: never passes secrets on argv; reads the code/password from --code-file / --password-file (polled) or stdin. An existing session is backed up first (.bak-*, last 3 kept); a dead/unauthorized one is moved aside (.dead-*, never deleted) so the fresh login starts clean. Runs under the session lock. TG_AUTH_PROGRESS=/path also mirrors stages to a file if stdout is buffered through wrapper layers.

For the user: do it yourself

If the user would rather not have the agent drive it, print step-by-step instructions they can follow in their own terminal:

tg-reader auth --guide

Then the user runs tg-reader auth --phone +7… themselves and enters the code (and 2FA password) when asked.

Never run auth from a scheduled/background task — it needs live input.

tg-reader restore-session — Recover a Broken Session

tg-reader restore-session

After every successful authorized run the skill snapshots the session file to {session}.session.last-good (with a manifest recording when it was verified and for which user). If the live session file gets emptied, corrupted, or overwritten, this command puts the last-good copy back: the broken file is moved aside to a timestamped .bak-* (never deleted), the backup is checksum-verified before install, and the restored session is verified against Telegram (get_me()).

Run it only interactively, with the user's confirmation — never from a scheduled/background task (see Session Safety Rules below).


Read Unread Mode

Only return new (unread) posts — the skill remembers what you've already seen. Useful for daily digests and monitoring workflows.

Setup

Option A — config file (~/.tg-reader.json):

{
  "api_id": 12345,
  "api_hash": "...",
  "read_unread": true
}

Option B — env var (works with ~/.openclaw/openclaw.json):

export TG_READ_UNREAD=true

Env vars take priority over the config file. This lets you enable read_unread via openclaw.json Docker env alongside TG_API_ID/TG_API_HASH.

State is stored in ~/.tg-reader-state.json (configurable via "state_file" in config, TG_STATE_FILE env var, or --state-file flag).

SOCKS5 proxy (for hosts that block direct MTProto)

Some networks/hosts filter direct MTProto (TCP 443 to Telegram DCs), which shows up as Connection timed out even when the internet works. Route the client through a local SOCKS5 proxy:

{
  "api_id": 12345,
  "api_hash": "...",
  "socks_proxy": "127.0.0.1:1080"
}

Accepted forms: host:port (SOCKS5 by default), socks5://host:port, or socks5://user:pass@host:port. Env var TG_PROXY overrides the config value (handy for setting the proxy via openclaw.json without editing the file). When unset, the client connects directly (unchanged behavior). Applies to both backends (Pyrogram/Telethon) and to tg-reader-check, which reports the resolved proxy in credentials.proxy.

Behavior

  • --since is not needed when read_unread is enabled — the skill automatically returns all unread posts regardless of time
  • First run (no prior state for channel): --since applies as usual (default 24h); state file created
  • Subsequent runs: only posts newer than the last read are returned; --since is ignored
  • --all flag: bypasses read_unread mode — fetches everything by --since without updating state (preserves your position)
  • New channel: behaves like a first run (no prior state)
  • No new posts: state unchanged, count: 0 returned

Examples

# With read_unread enabled — just fetch, no --since needed
tg-reader fetch @channel_name

# First run for a new channel — --since determines initial window
tg-reader fetch @new_channel --since 7d

# Override: fetch everything, don't update tracking state
tg-reader fetch @channel_name --since 7d --all

Output

When read_unread mode is active, the JSON output includes a read_unread field:

{
  "channel": "@channel_name",
  "read_unread": {"enabled": true},
  "count": 5,
  "messages": [...]
}

With --all: "read_unread": {"enabled": true, "overridden": true}

Limitations

  • Tracking is post-level only — new comments on already-read posts are not caught
  • If a channel changes its username, tracking resets (state is keyed by username)
  • Concurrent runs for the same channel are safe but last writer wins

Diagnostic

tg-reader-check reports tracking status:

{
  "tracking": {
    "read_unread": true,
    "state_file": "~/.tg-reader-state.json",
    "state_file_exists": true,
    "tracked_channels": 3
  }
}

Output Format

info

{
  "id": -1001234567890,
  "title": "Channel Name",
  "username": "channel_name",
  "description": "About this channel...",
  "members_count": 42000,
  "link": "https://t.me/channel_name"
}

fetch

{
  "channel": "@channel_name",
  "fetched_at": "2026-02-22T10:00:00Z",
  "since": "2026-02-21T10:00:00Z",
  "count": 12,
  "messages": [
    {
      "id": 1234,
      "date": "2026-02-22T09:30:00Z",
      "text": "Post content...",
      "views": 5200,
      "forwards": 34,
      "link": "https://t.me/channel_name/1234",
      "has_media": true,
      "media_type": "MessageMediaType.PHOTO"
    }
  ]
}

Optional web_page field — present only when a post carries a Telegram link-preview card (e.g. Instant View articles, link shares). Photos / videos / documents are reported via has_media + media_type, not here.

{
  "id": 9876,
  "text": "Card title\n\nCard description...\n\nhttps://example.com/article",
  "has_media": false,
  "web_page": {
    "url": "https://example.com/article",
    "display_url": "example.com/article",
    "title": "Card title",
    "description": "Card description...",
    "site_name": "Example Site"
  }
}

When the message has no text of its own (a common pattern for channels publishing via Instant View), the text field is synthesized from title + description + url so the post still surfaces. The web_page object carries the original structured data for agents that want them separately.

fetch with --comments

{
  "channel": "@channel_name",
  "fetched_at": "2026-02-28T10:00:00Z",
  "since": "2026-02-27T10:00:00Z",
  "count": 5,
  "comments_enabled": true,
  "comments_available": true,
  "messages": [
    {
      "id": 1234,
      "text": "Post content...",
      "has_media": false,
      "comment_count": 2,
      "comments": [
        {
          "id": 5678,
          "date": "2026-02-28T09:35:00Z",
          "text": "Great post!",
          "from_user": "username123"
        }
      ]
    }
  ]
}

Notes:

  • comments_available: false — channel has no linked discussion group (no comments possible)
  • comments_error on a message — rate limit hit for that post's comments
  • from_user may be null for anonymous comments
  • Images/videos in comments are not analyzed — only text is captured
  • Default post limit drops to 30 when --comments is active (override with --limit)

After Fetching

  1. Parse the JSON output
  2. Posts with images/videos have has_media: true and a media_type field. Their text is in the text field (from the caption). Do not skip posts just because they have media — they often contain important text.
  3. Images and videos are not analyzed (no OCR/vision) — only the text/caption is returned.
  4. Posts with a Telegram link-preview card carry a web_page object (URL, title, description, site name). For Instant-View articles the text field is synthesized from the card, so these posts surface in summaries just like text posts — do not skip them even when has_media: false.
  5. Summarize key themes, top posts by views, notable links
  6. If comments_enabled: true, analyze comment sentiment and key themes alongside the main posts
  7. Save summary to memory/YYYY-MM-DD.md if user wants to track over time

Saving to File (Token Economy)

Use --output when the result is large (especially with --comments) and you don't need to analyze it immediately. The full data goes to a file, and stdout returns only a short confirmation — this saves tokens.

Periodic updates pattern: set up a cron task that runs tg-reader fetch @channel --comments --output comments.json on schedule. The file gets updated regularly. When the user asks to analyze comments — read the file instead of re-fetching. This avoids consuming tokens on every fetch.

When --output is used without a filename, the default is tg-output.json. Stdout confirmation:

{"status": "ok", "output_file": "/absolute/path/to/tg-output.json", "count": 12}

Saving Channel List

Store tracked channels in TOOLS.md:

## Telegram Channels
- @channel1 — why tracked
- @channel2 — why tracked

Error Handling

Errors include an error_type and action field to help agents decide what to do automatically.

Channel Errors

error_typeMeaningaction
access_deniedChannel is private, you were kicked, or access is restrictedremove_from_list_or_rejoin — ask user if they still have access; if not, remove the channel
bannedYou are banned from this channelremove_from_list — remove the channel, tell the user
not_foundChannel doesn't exist or username is wrongcheck_username — verify the @username with the user
invite_expiredInvite link is expired or invalidrequest_new_invite — ask user for a new invite link
flood_waitTelegram rate limitwait_Ns — waits ≤ 60 s are retried automatically; longer waits return this error
comments_multi_channel--comments used with multiple channelsremove_extra_channels_or_drop_comments — use one channel at a time

Session Errors

error_typeMeaningaction
not_authorizedSession file holds no authorized user — empty, corrupted, overwritten, or (only when the message names a specific Telegram error like AuthKeyUnregistered/SessionRevoked) actually rejected by Telegramoffer_restore when a last-good backup exists (propose tg-reader restore-session to the user), otherwise run_auth_interactive (interactive tg-reader auth — needs the user)
busyAnother tg-reader process holds the session lockretry_later
networkCould not reach Telegram — says nothing about session validityretry_later — do NOT treat as an auth problem

Never invent causes. Do not tell the user the session "expired" or "was revoked by Telegram" unless the error message names a concrete Telegram error (AuthKeyUnregistered, SessionRevoked, ...). A not_authorized on a local file usually means the file is bad, while the session on Telegram's side is still alive — recoverable via restore-session without a new login.

Session Safety Rules (agents, read carefully)

  1. Never delete, move, rename, or overwrite session files. Recovery goes through tg-reader restore-session (which preserves the broken file) or interactive tg-reader auth — nothing else.
  2. From a scheduled/background run: on not_authorized or busy, notify the user and exit. No auth attempts, no restore, no config edits, no file surgery. Auth needs a login code only the user can receive.
  3. Never switch --session-file to another found file blindly — verify it first: tg-reader-check --online --session-file <path>. An existing or newer file may be an empty, never-authorized session.
  4. One session path everywhere. All cron/background commands must use the same --session-file (or the same default). Concurrent access is guarded by a lock (busy error), but path drift creates orphan sessions.

System Errors

ErrorAction
Session file not foundRun tg-reader-check — if other session files were found, verify with tg-reader-check --online --session-file <path> before switching
Missing credentialsGuide user through Setup (Step 1-2 below)
tg-reader: command not foundRun bash setup-tg-reader.sh from the skill directory, or manually: pip install . Fallback: python3 -m tg_reader_unified

Auth Code Not Arriving

Use the verbose debug script for full MTProto-level logs:

python3 debug_auth.py

Warning: debug_auth.py deletes existing session files before re-authenticating. It will ask for confirmation first.


Library Selection

Two MTProto backends are supported:

BackendCommandNotes
Pyrofork (default)tg-reader or tg-reader-pyrogramDrop-in fork of Pyrogram with current Telegram TL schema. Installs as the pyrogram package. The CLI command keeps the pyrogram name for backwards compatibility.
Telethontg-reader-telethonAlternative backend with separate implementation

Why pyrofork instead of pyrogram: the upstream pyrogram package on PyPI (2.0.106, Aug 2023) does not parse Telegram Message TL constructor IDs introduced in May 2026, so recent posts come through with empty message/media/entities. pyrofork is a community fork that ships the current schema. Sessions are format-compatible — switching does not require re-authentication.

Switch persistently: export TG_USE_TELETHON=true Switch one-time: tg-reader fetch @channel --since 24h --telethon


Setup & Installation

Full details in README.md.

Step 1 — Get API Credentials

Go to https://my.telegram.orgAPI Development Tools → create an app → copy api_id and api_hash.

Step 2 — Save Credentials

Recommended (works in agents and servers):

cat > ~/.tg-reader.json << 'EOF'
{
  "api_id": YOUR_ID,
  "api_hash": "YOUR_HASH"
}
EOF
chmod 600 ~/.tg-reader.json

Alternative (interactive shell only):

export TG_API_ID=YOUR_ID
export TG_API_HASH="YOUR_HASH"

Set these in your current shell session. Avoid writing TG_API_HASH to shell profiles (~/.bashrc) — use ~/.tg-reader.json instead for persistent storage.

Note: Agents and servers don't load shell profiles. Use ~/.tg-reader.json (the recommended method above) for non-interactive environments.

Step 3 — Install & Configure

npx clawhub@latest install sergei-mikhailov-tg-channel-reader
cd ~/.openclaw/workspace/skills/sergei-mikhailov-tg-channel-reader
bash setup-tg-reader.sh

The setup script: installs Python packages (pip install .), checks credentials and session, runs tg-reader-check, and prints the exec approval commands for you to run manually.

On Linux with managed Python (Ubuntu/Debian), use a venv before running the setup script:

python3 -m venv ~/.venv/tg-reader
echo 'export PATH="$HOME/.venv/tg-reader/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc
<details> <summary>Manual install (without setup script)</summary>
cd ~/.openclaw/workspace/skills/sergei-mikhailov-tg-channel-reader
# pyrofork replaces pyrogram; uninstall pyrogram first if it was already installed
pip uninstall pyrogram -y 2>/dev/null
pip install pyrofork tgcrypto telethon && pip install .
openclaw approvals allowlist add --gateway "$(which tg-reader)"
openclaw approvals allowlist add --gateway "$(which tg-reader-check)"
</details>

Step 4 — Authenticate

tg-reader auth

Pyrogram will ask to confirm the phone number — answer y. The code arrives in the Telegram app (not SMS).

Step 5 — Verify

tg-reader-check

Should return "status": "ok". If not — fix the reported issues and re-run bash setup-tg-reader.sh.


Scheduled Tasks & Cron

This skill needs network access (MTProto connection to Telegram servers) and a session file. How you configure OpenClaw cron depends on the session target.

Important: When setting up a scheduled task that uses tg-reader, tell the user which approach you're using and what it means — so they can make an informed choice.

Option A — sessionTarget: "main" (recommended)

The cron task sends a reminder to the main agent session. The agent then runs tg-reader in the main environment where the skill, credentials, and session file are already available.

Pros: No extra configuration — everything works out of the box. Cons: Not fully autonomous — the task sends a system event, the agent picks it up and executes. Requires payload.kind: "systemEvent" (OpenClaw cron API limitation for main target).

How to set up:

  1. Create a cron task with sessionTarget: "main" and payload.kind: "systemEvent"
  2. In the task description, include the exact tg-reader command to run
  3. The agent receives the reminder and executes the command in its main session

Option B — sessionTarget: "isolated" (autonomous, complex setup)

The cron task runs in a Docker container — fully autonomous, no agent interaction needed. However, the container starts empty: no skill, no credentials, no session file.

Pros: Fully autonomous — runs on schedule without agent involvement. Cons: Requires Docker setup; session file must be mounted into the container (may not work reliably — session files are tied to the machine and Telegram may invalidate them in a new environment).

Required configuration in ~/.openclaw/openclaw.json:

{
  "agents": {
    "defaults": {
      "sandbox": {
        "docker": {
          "setupCommand": "clawhub install sergei-mikhailov-tg-channel-reader && cd ~/.openclaw/workspace/skills/sergei-mikhailov-tg-channel-reader && pip uninstall pyrogram -y 2>/dev/null; pip install pyrofork tgcrypto telethon && pip install .",
          "env": {
            "TG_API_ID": "YOUR_ID",
            "TG_API_HASH": "YOUR_HASH",
            "TG_READ_UNREAD": "true"
          }
        }
      }
    }
  }
}

Session file caveat: The Telegram session file (~/.tg-reader-session.session) must also be available inside the container. This may require Docker volume mounting and might not work reliably — Telegram can invalidate sessions when they appear from a different environment. If you encounter AUTH_KEY_UNREGISTERED errors in isolated mode, switch to Option A.

Explicit paths (both options)

When ~/ is not available or points to a different location, use explicit paths:

tg-reader-check \
  --config-file /home/user/.tg-reader.json \
  --session-file /home/user/.tg-reader-session

tg-reader fetch @channel --since 6h \
  --config-file /home/user/.tg-reader.json \
  --session-file /home/user/.tg-reader-session

Both flags work with all subcommands and both backends.


Security

  • Session file (~/.tg-reader-session.session) grants full account access — keep it safe
  • The skill maintains sibling files next to the session: .session.lock (concurrency guard), .session.last-good + .session.last-good.json (verified backup + no-secrets manifest), .session.bak-* (timestamped backups, last 3 kept). The backup copies grant the same full account access as the session itself — all are created with 0600 permissions and must never be shared or committed
  • Never share or commit TG_API_HASH or session files
  • TG_API_HASH is a secret — store in env vars or config file, never in git

如何使用「Telegram Channel Reader」?

  1. 打开小龙虾AI(Web 或 iOS App)
  2. 点击上方「立即使用」按钮,或在对话框中输入任务描述
  3. 小龙虾AI 会自动匹配并调用「Telegram Channel Reader技能完成任务
  4. 结果即时呈现,支持继续对话优化

相关技能