# Telegram Approval [Back to setup guide](setup-guide.md) Telegram integration provides remote approval, completion notifications, and an optional reply path for live local sessions. When a supported agent asks for tool permission, Clawd keeps the local desktop bubble and also sends an approval card to your Telegram bot. The first explicit Allow or Deny decision resolves the same pending permission. The approval path does not create a remote shell or silently submit prompts. Completion notifications and **Reply to completion notifications** are separate opt-in Telegram features; their formatting does not change the approval decision policy described here. When **Reply to completion notifications** is enabled, replying directly to a completion notification selects the exact session that produced that message. This is a bounded prompt-delivery path, not a general Telegram chat bridge or remote shell. ## Supported Paths - Claude Code and CodeBuddy normal permission requests. - Codex CLI official `PermissionRequest` hooks when Codex permission handling is in intercept mode. - AskUserQuestion elicitation prompts (beta) — rendered as an interactive card with option buttons and a quote-safe Other reply. Telegram cards are not sent for DND/native-fallback cases, disabled agents, hidden permission bubbles, opencode, passive notifications, or headless sessions. ## Setup Each Telegram card has three layers: a header with one status sentence and the **Enable** switch, a body that is either the two-step setup block or the connection / notification groups, and a footer with **Send test card**. Before the token and recipient are saved, the card only shows the setup block; the switch, the groups and the test link appear once setup is complete. 1. **Bot token.** Create a dedicated bot with [@BotFather](https://t.me/botfather) using `/newbot`. Open Clawd Settings → **Permissions & approval** → **IM channels** → expand the **Telegram** card and paste the token into the first setup row. Do not reuse the token from an existing Telegram bridge. Telegram allows only one active `getUpdates` owner per bot token, so sharing a token can make one integration miss updates. The token is stored outside `clawd-prefs.json` in Clawd's user-data `telegram-approval.env` file. After saving, the input collapses to a masked preview (`:……`) so you can tell two saved tokens apart without seeing the raw secret. The raw token never crosses the IPC boundary back to the UI. 2. **Recipient.** Open [@userinfobot](https://t.me/userinfobot) in Telegram and send `/start` to get your numeric user id. Paste that number into the second setup row and save. Clawd uses this one number both as the allowed approver (only this user can tap Allow/Deny) and as the chat to deliver approval cards (private chat `chat_id` is the same as the user's id). Before testing, send `/start` to your own bot at least once so it can initiate the private chat. 3. **Enable & verify.** Turn on the switch in the **Telegram** card header. Clawd sends a standalone verification card. Tap either Allow or Deny in Telegram within 60 seconds. It is not attached to any agent permission request. A successful callback activates the native Telegram transport. After activation, the card footer offers **Send test card** for an ordinary connectivity check. ### Verification failures For a new or currently disabled setup, a failed verification returns the header switch to off and leaves an actionable failed status sentence on the Telegram card. Legacy-upgrade users instead remain on the migration-required panel described below. Neither path silently enables Telegram or revives the retired transport. Use the status message to choose the next check: - `401`: re-check or replace the bot token. - `403`: send `/start` to the bot from the configured user, make sure the bot is not blocked, and re-check the recipient. - `400` or a missing chat: use the numeric Telegram user id and start a private chat with the bot before retrying. - `409`: remove an existing webhook or stop the process on another machine, another Clawd profile, or another bot integration that polls the same token. A dedicated bot avoids both conflicts. - `429`: wait before retrying. - Network failure: check Telegram reachability, the system proxy, and any `CLAWD_TG_PROXY` override. - Timeout: tap the standalone verification card within 60 seconds. If it was already tapped, also check the network or proxy because Clawd may not have received the callback. `telegram proxy resolved` in `permission-debug.log` only records the selected proxy route before the Bot API request. It does not prove that Telegram accepted the token or request. Terminal verification failures are logged with allowlisted outcome and error-class fields; those terminal lines do not include tokens, chat ids, proxy addresses, or Telegram response bodies. 4. **Enable replies (optional).** Native Telegram must be active. Turn on **Reply to completion notifications** in the **Notifications** group. Recent completion notifications from the current Clawd run can be used as reply targets. Upgrading from the earlier paste-only Direct Send beta turns this setting off once because replies now include Enter and submit automatically. Review the new delivery behavior below before enabling it again. In Telegram, use the normal **Reply** action on the relevant completion notification and send one line of text. Clawd uses Telegram's `reply_to_message.message_id` to resolve the full session id, so concurrent Codex or other agent sessions do not rely on titles or shortened ids. ## Reply Delivery - The reply mapping is created only after Telegram confirms the completion notification was sent. Clawd keeps at most 1,000 mappings in memory for up to 24 hours, so notifications from before a Clawd restart are no longer reply targets. A confirmed or indeterminate automatic submission retires every older notification for that session; a completion notification created after that submission remains replyable. Changing the bot token, recipient, or resolved chat also clears existing mappings. - Known local Codex Desktop and Codex CLI sessions use Codex's durable thread queue instead of Console input. Clawd extracts the exact thread UUID or saved thread name from the mapped completion session and runs `codex queue --thread --message `; the reply is then picked up by that exact conversation and submitted by Codex itself. This avoids shared app-server processes, composer paste-burst handling, and local keyboard input interleaving with an injected Enter. Codex CLI 0.154.0 or newer is required; when the queue command is unavailable or unsupported, Clawd copies the reply to the clipboard without injecting text or Enter. If Clawd cannot derive the session's Codex store, a Windows CLI session retains the Console path instead, while a Codex Desktop session uses clipboard fallback rather than guessing an ambient store. An existing saved thread that is not currently loaded may accept the durable queue entry without starting a turn until the thread is opened or resumed; the queued acknowledgement means the queue accepted the reply, not that a turn has started. While at least one current completion mapping remains replyable, Clawd retains the completed Codex session beyond the normal idle-session cutoff. Mapping expiry, submission, route changes, or disabling Direct Send restores normal cleanup behavior. - For other eligible local Windows sessions, Clawd uses the session's agent PID to attach to its Windows Console/ConPTY input and writes the single-line Unicode reply followed by Enter. Successful delivery does not switch the foreground window and does not read or write the system clipboard. Reply deliveries are serialized so concurrent Telegram messages cannot interleave. - Terminal tabs or panes backed by independent ConPTY instances have separate consoles and can be targeted independently. If another live Clawd session shares the same Console as the target, Clawd treats the target as ambiguous, skips automatic submission, and copies the reply to the clipboard for manual paste. Text already present in the target terminal composer, or typed locally at the same time, may be combined with the injected reply before Enter. - Outside the Codex queue path, WSL, remote, headless, and non-Windows sessions use clipboard fallback, as do sessions without a usable agent PID and replies containing multiple lines. A Codex CLI session whose store cannot be derived keeps the Windows Console path when available; a Codex Desktop session whose store cannot be derived uses clipboard fallback. Clipboard fallback never injects paste or Enter. - Before writing input, Clawd rechecks that the mapped session is still the same live, completed local session and is not waiting for an interactive permission decision. A reused session id or changed session state is not submitted to a newer run. - Only the single configured Telegram user in the configured chat is accepted; multi-user and multi-chat routing are not configured separately. A plain message that is not a reply to a mapped completion notification is not routed to any session. - Reply to a newly delivered completion notification from the current Clawd run. A Clawd restart, bot token/recipient change, polling restart, or Direct Send toggle change clears the in-memory mapping, so an older Telegram card may still look like a completion notification while no longer selecting a session. ## Runtime Behavior - The desktop permission bubble remains the local fallback. - Telegram timeout or network failure does not deny the tool. The local bubble stays usable and the agent's existing fallback behavior remains unchanged. - If the desktop bubble resolves first, Clawd aborts the in-flight Telegram approval request. - Repeated Telegram taps after a request is already handled do not resolve the permission twice. - Clawd logs redact Telegram tokens, chat ids, and token-like values. ## Message Formatting - Completion notifications render Assistant output through a conservative Markdown subset using Telegram-safe HTML. Clawd metadata such as the session title, agent, folder, and host is escaped as plain dynamic text rather than interpreted as Markdown. - Approval, session-trust, and AskUserQuestion cards use Clawd-owned structure. Agent/tool/question values are redacted and escaped; they cannot add Telegram tags, links, mentions, or status lines. - Secret redaction runs before Markdown parsing. Unsupported HTML, unsafe link schemes, credentialed links, and image syntax degrade to visible text; Clawd does not fetch or embed the referenced media. - Username-like agent prose outside code uses a full-width `@` to avoid an unintended Telegram mention. Code keeps ASCII `@` for copy fidelity. - If Telegram rejects the generated HTML as an entity-parse error, Clawd retries the already-rendered plain version once without a parse mode. Other Telegram errors keep their existing retry/fallback behavior. - Formatting is the default transport correction and has no Settings toggle. It does not split long messages, upload documents, or use Rich Messages. ## Legacy Upgrade (v0.14.0) The old Go sidecar transport is retired in v0.14.0. It is no longer started, shipped, or offered as a fallback. Existing users whose preferences still select the old transport see a blocking **Legacy Telegram mode was retired** panel in Settings. Choose **Verify native and switch**. Clawd reuses the existing bot token, allowed user id, and target chat; no Telegram fields need to be entered again. The token stays in the same `telegram-approval.env` file and the migration does not rewrite or delete it. Only the real nonce callback from the configured Telegram user completes the switch. If verification fails or times out, Clawd remains in the migration-required state and does not revive the retired runtime. **Turn off Telegram approval** is available when you do not want to migrate yet. Users already on verified native transport continue without interruption. If verification reports a Telegram `409` conflict, another process is polling the same bot token. Fully exit the integration on the other machine or in the other independent Clawd profile, wait a few seconds for Telegram to release `getUpdates`, then retry. One bot token can have only one active poller. ## Release Verification Packaged builds must contain neither the retired executable nor its runtime source modules. Inspect each unpacked target with: ```bash node scripts/assert-no-retired-telegram-sidecar.js \ --resources-root ```