Library use¶
tgctl-go is not a Go library you import. It is a binary you exec or
pipe.
The gotd/td-backed client interface lives under internal/, so Go's
visibility rules intentionally prevent external packages from importing
it. The stable integration surface is the CLI contract: JSON envelopes,
exit codes, and append-only audit logs.
JSON envelope¶
Pass --json to force machine output:
Success:
{
"ok": true,
"command": "send",
"request_id": "req-abc12345",
"data": {
"message_id": 30350
},
"warnings": []
}
Failure:
{
"ok": false,
"command": "send",
"request_id": "req-xyz09876",
"error": {
"code": "WRITE_DISALLOWED",
"message": "write requires --allow-write"
}
}
Shell integration¶
Use jq for routing and assertions:
msg_id=$(
tg send 1240314255 "ack" --allow-write --json |
jq -r '.data.message_id'
)
tg get-msg 1240314255 "$msg_id" --json |
jq -e '.ok == true and .data.message.message_id == '"$msg_id"
Subprocess integration¶
Any language can call tg and parse the envelope.
import json
import subprocess
result = subprocess.run(
["tg", "show", "1240314255", "--limit", "5", "--json"],
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
envelope = json.loads(result.stdout)
if result.returncode != 0 or not envelope["ok"]:
raise RuntimeError(envelope.get("error", result.stderr))
Agent subprocess pattern¶
For an agent, make every call explicit: account, JSON output, write gate, and idempotency key.
tg --account test backfill-entities --json
tg --account test backfill 1240314255 --max-messages 100 --allow-write --json
tg --account test search 1240314255 "order" --limit 20 --json
tg --account test send 1240314255 "agent draft reply" \
--allow-write \
--idempotency-key "agent-reply-001" \
--json
Reads do not need --allow-write. Local DB writes (discover,
backfill, sync-contacts, listen) and Telegram writes do. Treat
request_id as the correlation key for logs and audit entries.
Exit codes¶
The process exit code matches the envelope error code family:
| Code | Name |
|---|---|
| 0 | OK |
| 1 | GENERIC |
| 2 | BAD_ARGS |
| 3 | NOT_AUTHED |
| 4 | NOT_FOUND |
| 5 | FLOOD_WAIT |
| 6 | WRITE_DISALLOWED |
| 7 | NEEDS_CONFIRM |
| 8 | LOCAL_RATE_LIMIT |
| 9 | PREMIUM_REQUIRED |
Use both the exit code and .error.code. The numeric code is stable
for shells; the string is better for logs and metrics.
Request IDs¶
Every envelope includes request_id. Write audit entries use the same
ID before and after the Telegram call:
Then correlate in accounts/default/audit.log:
Streaming¶
tg listen --json emits one envelope per update:
For tests, use one update and exit:
Versioning¶
The CLI contract is the API. New commands and fields are additive. Existing exit codes, JSON envelope keys, and safety gates are stable across the Go and Python ports.
See also¶
- Safety model — exit codes and audit log
- Multi-account — isolating agents from your real DMs
- Quickstart — agent-ready first run