Telegram CLI built on top of gotd/td (MTProto), focused on:
- Local message sync with continuous capture
- Fast offline search via SQLite FTS5
- Sending messages and files
- Contact + group management
This is a third-party tool that uses the Telegram MTProto protocol via gotd/td and is not affiliated with Telegram.
Core implementation is in place. See docs/spec.md for the full design notes.
- Go 1.21+
- GCC / build-essential (CGO required for SQLite)
- App credentials from my.telegram.org
git clone https://github.com/GodsBoy/tgcli.git
cd tgcli
make buildRun:
./dist/tgcli --helpmake installDefault store directory is ~/.tgcli (override with --store DIR).
# 1) Get API credentials from https://my.telegram.org
# Create config:
cat > ~/.tgcli/config.json << EOF
{
"app_id": 12345,
"app_hash": "your_api_hash_here",
"phone": "+1234567890"
}
EOF
# 2) Authenticate (phone + OTP + optional 2FA)
tgcli auth
# 3) Sync message history
tgcli sync
# 4) Keep syncing new messages (Ctrl+C to stop)
tgcli sync --follow
# 5) Diagnostics
tgcli doctor
# Search messages (FTS5 full-text search)
tgcli messages search "meeting"
# List recent messages in a chat
tgcli messages list --chat 12345 --limit 20
# Send a message
tgcli send text --to 12345 --message "hello"
# Send a file
tgcli send file --to 12345 --file ./photo.jpg --caption "check this out"
# List chats, contacts, groups
tgcli chats list
tgcli contacts list
tgcli groups list
tgcli groups info --chat 12345Set environment variables:
export TGCLI_APP_ID=12345
export TGCLI_APP_HASH=abcdef1234567890
export TGCLI_PHONE=+1234567890Or create ~/.tgcli/config.json:
{
"app_id": 12345,
"app_hash": "abcdef1234567890",
"phone": "+1234567890"
}Config file values are used as defaults; environment variables take precedence.
tgcli auth # Authenticate (phone + OTP + optional 2FA)
tgcli auth status # Show authentication status
tgcli auth logout # Invalidate sessiontgcli sync # Sync message history to SQLite
tgcli sync --follow # Continuous sync (Ctrl+C to stop)tgcli sync never prompts for authentication - it errors if not logged in. Use tgcli auth first.
tgcli messages list --chat <id> [--limit N] [--after TIME] [--before TIME]
tgcli messages search "query" [--chat <id>] [--limit N]
tgcli messages show --chat <id> --id <msg_id>Search uses SQLite FTS5 for fast full-text matching with result highlighting.
tgcli send text --to <id> --message "hello"
tgcli send file --to <id> --file ./photo.jpg [--caption "hi"]tgcli chats list [--limit N]
tgcli contacts list [--limit N]
tgcli groups list [--limit N]
tgcli groups info --chat <id>tgcli doctor # Check configuration, session, database, FTS5--store DIR Storage directory (default: ~/.tgcli)
--json Output as JSON (structured envelope)
--timeout DURATION Operation timeout (default: 5m)
All commands support --json for machine-readable output:
{
"success": true,
"data": { ... }
}On error:
{
"success": false,
"error": "error message"
}Defaults to ~/.tgcli (override with --store DIR).
~/.tgcli/
βββ config.json # App credentials + settings
βββ session.json # MTProto session data
βββ tgcli.db # SQLite database (messages, chats, FTS5)
βββ LOCK # Instance lock file
Store permissions are set to 0700 (directory) and 0600 (files) for security.
tgcli auth: interactive login (phone + OTP + 2FA), then ready to sync.tgcli sync: non-interactive sync (never prompts for auth; errors if not authenticated).- Output is human-readable by default; pass
--jsonfor scripting. - Progress is written to stderr; primary output goes to stdout.
- Single-instance safety: store locking prevents concurrent access.
cmd/tgcli/ Cobra CLI commands
internal/auth/ MTProto phone + OTP + 2FA auth flow
internal/client/ gotd/td wrapper (connect, auth, API calls)
internal/sync/ Message sync engine (bootstrap + follow)
internal/store/ SQLite storage layer with FTS5 full-text search
internal/format/ Output formatting (JSON, plain text)
internal/lock/ Single-instance safety (flock)
internal/config/ Configuration loading (file + env)
make build # Build binary to dist/
make test # Run tests with race detector
make vet # Run go vet
make lint # Run golangci-lint (requires golangci-lint)
make clean # Remove build artifactsThis project is inspired by the excellent wacli by Peter Steinberger.
MIT - see LICENSE.