tgzero
Zero-dependency, stdlib-only Telegram bridge for two-way CLI automation. Simple alerts or interactive command-and-control using nothing but the Python standard library.
| Command | What it does |
|---|---|
send |
One-way alert |
ask |
Block a script until you tap a button |
run |
Run a command locally, send its output |
tail |
Stream a log file |
daemon |
Run allow-listed commands sent from Telegram |
bridge / hook |
Answer Claude Code sessions from your phone |
ping / version |
Check connectivity / print version |
Quick start
pip install tgzero
Create telegram.env in your working directory (or export the variables):
TELEGRAM_TOKEN=1234567890:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghi
TELEGRAM_CHAT_ID=987654321
chmod 600 telegram.env
tgzero ping # a test message should arrive
TELEGRAM_CHAT_IDis your user ID, not the bot's. Send any message to your bot, then openhttps://api.telegram.org/bot<TOKEN>/getUpdatesand copymessage.chat.id(or ask@userinfobot). Using the bot's own ID fails with403: the bot can't send messages to the bot.
Commands
tgzero send
tgzero send -m "✅ Weekly backup uploaded to S3."
tgzero send -m "Server load is high (85%)" --silent # no sound
tgzero send -m "Done" --json
# → {"status": "success", "action": "send", "exit_code": 0, "latency_ms": 312}
tgzero ask
Pauses your script until you tap a button. First button → exit 0.
if tgzero ask -p "Deploy to production?" -b "Deploy,Abort" --timeout 300; then
./deploy.sh
fi
# Multiple choices — read the label from JSON
ENV=$(tgzero ask -p "Environment?" -b "Staging,Prod,Dev" --json \
| python3 -c "import sys,json; print(json.load(sys.stdin)['reply_string'])")
| Exit | Meaning |
|---|---|
0 |
First button |
1 |
Other button (label printed to stdout) |
2 |
Timeout |
3 |
Network / API failure |
4 |
Another ask holds the lock |
5 |
Terminated (SIGTERM / SIGINT) |
tgzero run
Runs a command and sends output, exit code and duration. Default timeout: 300 s.
tgzero run "df -h"
tgzero run --timeout 60 "journalctl -u nginx --since today --no-pager"
No shell. Commands go through
shlex.splitwithshell=False, so pipes, redirects and builtins (|,>,exit) don't work. Use the tool's own flags instead, e.g.pg_dump mydb -f backup.sql.
What arrives in Telegram:
✅ $ df -h
Exit: 0 · Took: 0.1s
Filesystem Size Used Avail Use% Mounted on ← monospace block
/dev/sda1 50G 12G 36G 25% /
Output longer than 40 lines (or Telegram's 4096-char limit) is shown as a
preview (first 15 + last 10 lines) and the full text is attached as output.txt.
| Exit | Meaning |
|---|---|
0 |
Done, result delivered |
1 |
Command not found / config missing |
2 |
Timed out |
3 |
Network / API failure |
tgzero tail
Forwards new lines of a file (starts at the end, batches lines).
tgzero tail /var/log/app.log --filter "error,critical" --label "app"
Stop with Ctrl+C / SIGTERM. A shutdown notice is sent.
tgzero daemon
Runs commands sent from Telegram, but only those on the allow-list. Matching is exact: the message must equal an entry character for character.
tgzero daemon --allow-list "df -h,uptime,systemctl status nginx" --interval 3
Other commands get ⚠️ Command not permitted. Commands are rate-limited (2 s cooldown).
Long output works as in run.
systemd unit
[Unit]
Description=tgzero Telegram daemon
After=network-online.target
[Service]
Type=simple
WorkingDirectory=/opt/myapp
EnvironmentFile=/opt/myapp/telegram.env
ExecStart=tgzero daemon --allow-list "df -h,uptime"
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Claude Code integration
Get a Telegram message when a Claude Code session stops and needs you; reply (Telegram reply) and the text is typed into that terminal.
- Run Claude Code inside tmux (replies are injected via
tmux send-keys). - Add the hook to
~/.claude/settings.json:{ "hooks": { "Stop": [{ "hooks": [{ "type": "command", "command": "tgzero hook" }] }], "UserPromptSubmit": [{ "hooks": [{ "type": "command", "command": "tgzero hook" }] }] } }
- Start one bridge per machine:
tgzero bridge(--ttl SECONDSexpires unanswered prompts, default 6 h).
If you answer on the PC instead, the Telegram message is marked "✅ Answered on PC" and its buttons are removed.
bridgemust be the only process polling this bot. Don't runaskordaemonwith the same token at the same time.
Message icons
| Icon | Meaning |
|---|---|
| ✅ | Exit code 0 |
| ❌ | Non-zero exit code |
| ⏱ | Timeout |
| ⚠️ | Command not found / error / not permitted |
System notices (start, stop, rate limit) never use the $ command header.
Security notes
- Only messages from
TELEGRAM_CHAT_IDare processed; others are logged and ignored. - Never
shell=True. User input is never passed to a shell. - All text sent as HTML is escaped (
&,<,>,"); ANSI colour codes are stripped. telegram.envand its directory are checked for unsafe permissions on startup.- The
asklock lives in a per-user0700directory and ischmod 600. - Output is sent as-is: secrets printed by a command will reach Telegram.
Metadata
Release files for tgzero 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| tgzero-0.3.0.tar.gz | 35.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| tgzero-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 76.2 kB
Release files / tgzero-0.3.0.tar.gz
| Download URL | tgzero-0.3.0.tar.gz |
|---|---|
| Size | 35.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a69eceaa935e675304a183828e13d6d1c21a54e9318c84031a177cd49c77b52b
|
|
BLAKE2b-256 checksum How to use checksums |
e25aa40d8aa273c56f23cbc21fa59c2f2fb9f1f617c74ef4d41ee195389599e9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency logRelease files / tgzero-0.3.0-py3-none-any.whl
| Download URL | tgzero-0.3.0-py3-none-any.whl |
|---|---|
| Size | 40.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e0abfc63489fec9ee1ff14c42fe188b3017415af34ab472e3e19fa1556616ef2
|
|
BLAKE2b-256 checksum How to use checksums |
cdc00750e59173f00891bfa499429c8f90395f1f30e4ee497e75618bf66a5525
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.
Transparency log