RepoPilotOpen in app β†’

iyear/tdl

πŸ“₯ A Telegram toolkit written in Golang

Mixed

Mixed signals β€” read the receipts

weakest axis
Use as dependencyConcerns

copyleft license (AGPL-3.0) β€” review compatibility

Fork & modifyHealthy

Has a license, tests, and CI β€” clean foundation to fork and modify.

Learn fromHealthy

Documented and popular β€” useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture β€” runnable as-is.

  • βœ“Last commit 6d ago
  • βœ“7 active contributors
  • βœ“AGPL-3.0 licensed
Show all 7 evidence items β†’
  • βœ“CI configured
  • βœ“Tests present
  • ⚠Concentrated ownership β€” top contributor handles 63% of recent commits
  • ⚠AGPL-3.0 is copyleft β€” check downstream compatibility
What would change the summary?
  • β†’Use as dependency Concerns β†’ Mixed if: relicense under MIT/Apache-2.0 (rare for established libs)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README β€” live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/iyear/tdl?axis=fork)](https://repopilot.app/r/iyear/tdl)

Paste at the top of your README.md β€” renders inline like a shields.io badge.

β–ΈPreview social card (1200Γ—630)

This card auto-renders when someone shares https://repopilot.app/r/iyear/tdl on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: iyear/tdl

Generated by RepoPilot Β· 2026-05-09 Β· Source

πŸ€–Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale β€” STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI Β· unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/iyear/tdl shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything β€” but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT β€” Mixed signals β€” read the receipts

  • Last commit 6d ago
  • 7 active contributors
  • AGPL-3.0 licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership β€” top contributor handles 63% of recent commits
  • ⚠ AGPL-3.0 is copyleft β€” check downstream compatibility

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

βœ…Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live iyear/tdl repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale β€” regenerate it at repopilot.app/r/iyear/tdl.

What it runs against: a local clone of iyear/tdl β€” the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in iyear/tdl | Confirms the artifact applies here, not a fork | | 2 | License is still AGPL-3.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≀ 36 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> β€” paste this script from inside your clone of <code>iyear/tdl</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of iyear/tdl. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/iyear/tdl.git
#   cd tdl
#
# Then paste this script. Every check is read-only β€” no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of iyear/tdl and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "iyear/tdl(\\.git)?\\b" \\
  && ok "origin remote is iyear/tdl" \\
  || miss "origin remote is not iyear/tdl (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(AGPL-3\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"AGPL-3\\.0\"" package.json 2>/dev/null) \\
  && ok "license is AGPL-3.0" \\
  || miss "license drift β€” was AGPL-3.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "core/tclient/tclient.go" \\
  && ok "core/tclient/tclient.go" \\
  || miss "missing critical file: core/tclient/tclient.go"
test -f "core/downloader/downloader.go" \\
  && ok "core/downloader/downloader.go" \\
  || miss "missing critical file: core/downloader/downloader.go"
test -f "core/uploader/uploader.go" \\
  && ok "core/uploader/uploader.go" \\
  || miss "missing critical file: core/uploader/uploader.go"
test -f "core/dcpool/dcpool.go" \\
  && ok "core/dcpool/dcpool.go" \\
  || miss "missing critical file: core/dcpool/dcpool.go"
test -f "app/login/login.go" \\
  && ok "app/login/login.go" \\
  || miss "missing critical file: app/login/login.go"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 36 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~6d)"
else
  miss "last commit was $days_since_last days ago β€” artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) β€” safe to trust"
else
  echo "artifact has $fail stale claim(s) β€” regenerate at https://repopilot.app/r/iyear/tdl"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

⚑TL;DR

tdl is a high-performance Telegram client toolkit written in Go that downloads files from chats (including protected ones), forwards messages with intelligent fallback routing, uploads files, and exports chat data to JSON. It's faster than official Telegram clients by leveraging the gotd/td TDLib bindings and saturates available bandwidth for bulk operations. Modular command structure: app/ directory contains feature domains (dl/, up/, forward/, chat/, login/, migrate/) each with independent iter.go (streaming logic), elem.go (data structures), and progress.go (UI feedback). app/internal/tctx/ provides shared Telegram context. CLI entry points likely in cmd/ (not shown in file list but inferred from Makefile presence).

πŸ‘₯Who it's for

DevOps engineers, data archivists, and automation specialists who need to bulk-download Telegram media and messages, migrate chat data, or programmatically interact with Telegram through a CLI without the overhead of the official client.

🌱Maturity & risk

Production-ready and actively maintained. The project has comprehensive GitHub Actions workflows (master.yml, release.yml, docker.yml), uses golangci-lint for code quality, and includes end-to-end tests (e.g., app/dl/iter_test.go). Single maintainer (@iyear) with active releases and sponsor support; Go 1.25.8 baseline indicates modern maintenance.

Low risk for core download/upload operations, but moderate dependency risk: 6 direct dependencies (gotd/td, gotd/contrib, samber/lo, yaml, backoff, mimetype) with deep transitive deps (~40 indirect). The single-maintainer model (iyear) is a concentration risk for critical bugs. AGPL-3.0 license may restrict commercial use without code disclosure.

Active areas of work

Active release pipeline via .github/workflows/release.yml and Docker image builds (docker.yml). Dependabot auto-updates configured (dependabot-fix.yml) suggesting regular dependency maintenance. The presence of serve.go.tmpl (app/dl/) suggests recent work on HTTP serving features. No explicit issue data provided, but docs.yml indicates documentation is kept current.

πŸš€Get running

git clone https://github.com/iyear/tdl.git
cd tdl
go mod download
make build  # inferred from Makefile presence
./tdl --help

Daily commands: Build: make build (Makefile exists but not shown; inferred from GitHub workflows). Run: ./tdl [command] [flags] (CLI-driven, see .github/workflows/master.yml for CI commands). Local testing: go test ./... for iter_test.go and likely other test files.

πŸ—ΊοΈMap of the codebase

  • core/tclient/tclient.go β€” Core Telegram client wrapper that abstracts gotd/td library; all Telegram API interactions funnel through here
  • core/downloader/downloader.go β€” Primary download orchestrator managing bandwidth, concurrency, and media retrieval from Telegram; entry point for dl command
  • core/uploader/uploader.go β€” File upload handler managing streaming uploads to Telegram; critical for up command flow
  • core/dcpool/dcpool.go β€” Data center connection pooling and middleware orchestration; manages low-level Telegram transport
  • app/login/login.go β€” Authentication logic handling phone/code/QR flows; required for all subsequent operations
  • cmd/root.go β€” Cobra CLI root command initialization and global flag setup; entry point for CLI execution
  • core/storage/storage.go β€” Session persistence and state management; maintains user authentication and peer data across runs

πŸ› οΈHow to make changes

Add a new download format filter

  1. Define filter logic in core/downloader/downloader.go by adding a FilterFn type and applying it to iter.Next() (core/downloader/downloader.go)
  2. Expose filter option in app/dl/dl.go Download() function signature (app/dl/dl.go)
  3. Add CLI flag in cmd/dl.go and parse it into the app layer call (cmd/dl.go)

Add a new chat export format (e.g., CSV)

  1. Create export enum in app/chat/export_enum.go with new format constant (app/chat/export_enum.go)
  2. Implement format marshaler in app/chat/export.go Export() function with conditional encoding (app/chat/export.go)
  3. Add CLI --format flag in cmd/chat.go and route to app layer (cmd/chat.go)

Add a new authentication method

  1. Create auth flow function in app/login/login.go following QR/Phone/Code pattern (app/login/login.go)
  2. Add login enum variant in app/login/login_enum.go (app/login/login_enum.go)
  3. Add CLI flag in cmd/login.go and route to new auth handler (cmd/login.go)
  4. Store session in core/storage/storage.go if state differs from standard (core/storage/storage.go)

Add a new middleware for request handling

  1. Create middleware file in core/middlewares/{name}/ with func(ctx context.Context, req T, invoker gotd.Invoker) (R, error) (core/middlewares/recovery/recovery.go)
  2. Register middleware in core/dcpool/middlewares.go in the middleware chain (core/dcpool/middlewares.go)

πŸ”§Why these technologies

  • Go 1.25.8 β€” Concurrent download/upload, lightweight binary distribution, fast compilation for cross-platform targets
  • gotd/td (Telegram MTProto client library) β€” Pure Go Telegram client without TDLib C dependency; allows custom middleware and connection pooling for performance
  • Cobra (CLI framework) β€” Mature flag parsing and subcommand routing; integrates well with Go's idiomatic patterns
  • uber/zap (structured logging) β€” High-performance structured logging with context propagation; minimal overhead during heavy I/O
  • SQLite (session storage) β€” Single-file persistence of Telegram sessions without external dependencies; portable across platforms
  • cenkalti/backoff (retry logic) β€” Exponential backoff with jitter for resilient Telegram API calls under rate-limiting

βš–οΈTrade-offs already made

  • Direct gotd/td usage instead of TDLib wrapper

    • Why: Avoid C dependency for cross-platform binary distribution and enable custom networking (connectproxy for proxy support)
    • Consequence: Must manually handle Telegram MTProto specifics (DC pooling, middleware), but gains transparency and control
  • Concurrent download with bandwidth awareness instead of simple queue

    • Why: Maximize throughput to saturate user's connection (advertised feature: 'take up all your bandwidth')
    • Consequence: Increased complexity in progress tracking and memory buffering; requires careful chunking to avoid OOM on large files
  • SQLite for session storage instead of in-memory

    • Why: Persist sessions across CLI invocations; avoid re-authentication on every run
    • Consequence: Filesystem I/O overhead, but acceptable for CLI tool with sparse invocation frequency
  • Middleware-based architecture for retry/recovery/takeout

    • Why: Cleanly separate cross-cutting concerns from core business logic; reuse across download/upload/forward
    • Consequence: Extra abstraction layer; requires understanding gotd invoker pattern to add new middleware

🚫Non-goals (don't propose these)

  • Real-time chat UI (CLI-only tool)
  • End-to-end encrypted chat support (only public chats and user's own accounts)
  • Windows subsystem for Linux native support (Go binary works on WSL but no special WSL integration)
  • Automatic upload scheduling or daemon mode (single-run operations via CLI)
  • Streaming media transcoding (media downloaded as-is from Telegram)

πŸͺ€Traps & gotchas

No explicit .env or config schema found in file list: auth likely stored in home directory (typical for Telegram clients; check docs for schema). AGPL-3.0 license: using or modifying tdl in closed-source projects requires making your code public or obtaining a waiver. Dependabot auto-merge: security patches may land unexpectedly; watch gotd/td closely for breaking API changes. go.mod in repo root indicates single module: no internal dependency graphs to worry about, but package structure implies CLI binary in undisclosed location (likely cmd/tdl or cmd/main).

πŸ—οΈArchitecture

πŸ’‘Concepts to learn

  • MTProto (Mobile Transport Protocol) β€” The Telegram wire protocol that gotd/td implements; understanding MTProto encryption and message framing explains why tdl can bypass rate limits and access protected chats
  • Iterator Pattern (Streaming) β€” tdl uses iter.go files throughout (dl/iter.go, forward/iter.go, up/iter.go) to stream large datasets without loading into memory; critical for handling massive chat exports
  • Context-based Concurrency Control β€” app/internal/tctx wraps context.Context for Telegram session management and cancellation; Go's context package is essential for graceful shutdown and timeout handling in distributed operations
  • Exponential Backoff with Jitter β€” cenkalti/backoff/v4 is imported for retry logic; prevents thundering herd when download workers hit rate limits, enabling tdl to 'take up all your bandwidth' without crashing the API
  • MIME Type Detection β€” gabriel-vasile/mimetype is used (likely in elem.go files) to classify downloaded media without relying on file extensions, enabling correct export metadata and re-upload categorization
  • Structured Logging with Correlation IDs β€” uber/zap is the logging framework; combined with tctx, this enables tracing download/forward/upload operations across goroutinesβ€”essential for debugging multi-worker bulk operations
  • Message Fallback Routing β€” app/forward/forward.go implements intelligent retry and fallback when forwarding to protected chats or closed groups; understanding Telegram's forward API constraints is key to extending this feature
  • gotd/td β€” Direct upstream dependency providing Telegram MTProto bindingsβ€”tdl wraps this library for CLI ergonomics
  • gotd/contrib β€” Sibling library in the gotd ecosystem providing retry, rate-limit, and streaming helpers that tdl depends on
  • telegramdesktop/tdesktop β€” Official Telegram client; tdl attempts to match or exceed its download/forward performance while offering CLI automation
  • iyear/connectproxy β€” Proxy helper library by the same maintainer; used in tdl for connection routing through custom proxies
  • yapingcat/gomedia β€” Media parsing library vendored in tdl dependencies; handles codec detection for uploaded/downloaded files

πŸͺ„PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for app/dl/iter.go download iterator

The iter.go file handles critical download iteration logic but only has iter_test.go with limited coverage. Add comprehensive integration tests covering edge cases like resumed downloads, corrupted partial files, concurrent downloads, and network interruptions. This is high-value because download reliability is core to tdl's value proposition.

  • [ ] Expand app/dl/iter_test.go with table-driven tests for different file sizes and chunk combinations
  • [ ] Add mock Telegram connection tests simulating network failures and timeouts
  • [ ] Test concurrent download scenarios with multiple files to verify progress.go synchronization
  • [ ] Add regression tests for known issues around incomplete file handling in iter.go

Add CI workflow for cross-platform binary testing

The repo has docker.yml, release.yml, and master.yml workflows, but lacks a workflow specifically testing built binaries on Windows, macOS, and Linux before release. Given tdl is a CLI tool with platform-specific concerns (file paths, terminal colors, websocket handling via coder/websocket), this prevents catching platform-specific bugs early.

  • [ ] Create .github/workflows/cross-platform-test.yml that builds binaries for linux/amd64, darwin/arm64, darwin/amd64, windows/amd64
  • [ ] Run basic smoke tests on each platform (login command, --version, help output)
  • [ ] Test app/dl/serve.go template rendering (serve.go.tmpl) on each OS to catch path separator issues
  • [ ] Ensure the workflow runs on pull requests and reports failures

Add unit tests for app/chat/export_enum.go and ls_enum.go enum generation

The codebase has export_enum.go and ls_enum.go files that appear to be code-generated enum utilities (similar pattern to cmd/gen.go), but there are no tests validating that enum mappings are correct or that export/list operations handle all enum variants. Missing test coverage here could cause silent failures in message export and chat listing.

  • [ ] Create app/chat/export_enum_test.go with tests for all export format enums and their string representations
  • [ ] Create app/chat/ls_enum_test.go validating all ls filter enums match Telegram API expectations
  • [ ] Add test cases validating enum round-trip conversions (string β†’ enum β†’ string)
  • [ ] Add tests ensuring missing or misspelled enum values fail with clear error messages

🌿Good first issues

  • Add integration tests for app/forward/iter.go similar to app/dl/iter_test.goβ€”currently only download iteration is tested; forward and upload iterators lack test coverage
  • Create OpenAPI/Swagger docs from existing CLI enums (app/dl/dl_enum.go, app/chat/ls_enum.go, app/login/login_enum.go) to auto-generate command referenceβ€”currently only markdown docs exist
  • Add graceful shutdown hooks to app/dl/serve.go (HTTP server template)β€”no context cancellation or timeout handling visible in the .tmpl file

⭐Top contributors

Click to expand

πŸ“Recent commits

Click to expand
  • d4c59b1 β€” chore(deps): bump github.com/go-playground/validator/v10 (#1206) (dependabot[bot])
  • 6d1b069 β€” chore(deps): bump actions/configure-pages from 5 to 6 (#1205) (dependabot[bot])
  • 6b17e53 β€” chore(deps): bump tdl submodules to v0.20.2 (iyear)
  • b54c8c9 β€” chore(deps): bump tdl/core to v0.20.2 (iyear)
  • 75b4160 β€” chore(deps): update gotd/td to v0.140.0 (#1204) (iyear)
  • 9e814f0 β€” chore(deps): bump golang.org/x/net from 0.51.0 to 0.52.0 in /core (#1191) (dependabot[bot])
  • d61eed8 β€” chore(deps): bump golang.org/x/net from 0.51.0 to 0.52.0 (#1190) (dependabot[bot])
  • 8964e91 β€” chore(deps): bump github.com/klauspost/compress from 1.18.4 to 1.18.5 (#1200) (dependabot[bot])
  • 4139ba4 β€” chore(deps): bump actions/deploy-pages from 4 to 5 (#1202) (dependabot[bot])
  • 9ba804d β€” chore(deps): bump github.com/fatih/color from 1.18.0 to 1.19.0 (#1198) (dependabot[bot])

πŸ”’Security observations

  • High Β· Outdated Go Version in Dockerfile β€” Dockerfile, line 2. The Dockerfile uses Go 1.25-alpine which does not exist. Go versions follow semantic versioning (1.21, 1.22, 1.23, etc.). This suggests the Dockerfile may not build correctly or uses an invalid version tag. Using non-existent or improperly pinned versions can lead to unexpected behavior and security patches being missed. Fix: Use a valid, supported Go version such as golang:1.23-alpine or golang:1.24-alpine. Pin to a specific patch version for reproducibility (e.g., golang:1.23.4-alpine).
  • High Β· Outdated Go Module Version β€” core/go.mod, line 2. The core/go.mod file declares 'go 1.25.8' which is not a valid Go version. Valid versions are 1.21.x, 1.22.x, 1.23.x, etc. This misconfiguration could cause build failures and module resolution issues across the project. Fix: Update to a valid Go version such as 'go 1.23' or 'go 1.24'. Ensure consistency between Dockerfile and go.mod declarations.
  • Medium Β· Outdated Dependency: golang.org/x/crypto β€” core/go.mod, indirect dependency. The dependency golang.org/x/crypto is pinned to v0.49.0, which is significantly outdated. Current versions are v0.24.0+. Older cryptographic libraries may contain known vulnerabilities and lack security patches. Fix: Update golang.org/x/crypto to the latest stable version. Run 'go get -u golang.org/x/crypto' and test thoroughly.
  • Medium Β· Outdated Dependency: golang.org/x/net β€” core/go.mod, line 11. The dependency golang.org/x/net is pinned to v0.52.0. While relatively recent, network libraries should be kept current to address potential protocol-level vulnerabilities and DoS issues. Fix: Review and update golang.org/x/net to the latest version. Run 'go get -u golang.org/x/net' and validate no breaking changes affect the application.
  • Medium Β· Missing Security Headers in Docker Configuration β€” Dockerfile, line 16. The Dockerfile uses 'alpine:latest' as the base image without pinning to a specific version. This could result in pulling a different image on subsequent builds, potentially including security patches or regressions. Additionally, there are no security-related configurations (e.g., read-only filesystem, user privilege dropping). Fix: Pin alpine to a specific version (e.g., alpine:3.19). Add security best practices: use 'RUN adduser -D -u 1000 tdl' to create a non-root user and 'USER tdl' to drop privileges.
  • Medium Β· Potential Sensitive Data in Logs β€” core/logctx, app modules. The application uses logging libraries (go.uber.org/zap) and handles Telegram API interactions. There is a risk of logging sensitive data (authentication tokens, file contents, user IDs) if logging is misconfigured. Review of actual logging implementation was not possible from file names alone. Fix: Implement structured logging with careful sanitization. Ensure no sensitive credentials, tokens, or personal user data are logged. Use log levels appropriately (DEBUG for development only).
  • Low Β· Build-Time Version Injection via LDFLAGS β€” Dockerfile, lines 14-15. The Dockerfile injects version information via ldflags during build. While this is a standard practice, ensure the VERSION, COMMIT, and COMMIT_DATE variables come from trusted CI/CD sources only and cannot be manipulated by unauthorized users. Fix: Ensure CI/CD pipeline validates and controls these build-time variables. Document the source of truth for VERSION and COMMIT variables.
  • Low Β· Missing HEALTHCHECK in Dockerfile β€” Dockerfile. The Dockerfile does not define a HEALTHCHECK instruction, which is important for orchestration platforms like Kubernetes or Docker Compose to monitor application health and restart unhealthy containers. Fix: Add a HEALTHCHECK instruction that

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals β€” see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals Β· iyear/tdl β€” RepoPilot