Plank help · updated 2026-10-29

Connecting Telegram (personal account)

Let the assistant read your own Telegram chats and send a message from your account — only after you say «yes» to the exact draft. Uses your own api_id from my.telegram.org; the login stays in your personal space and never appears in the chat.

Agents: fetch the raw markdown of this page at /en/help/connecting-telegram-personal.md

Connecting Telegram (personal account)

This connects your own Telegram account so the assistant can read your chats and send a message from you — only after you say «yes» to the exact text. It is the Telegram twin of personal WhatsApp. It is not the Telegram bot: a bot is a separate account people write to, this is you.

Assistant — right page? A bot, a support line or anything other people message → connecting-telegram. Continue here only for the person's own account, in their own personal space.

Read this before you enable it

1. The login is full access to your Telegram. Linking saves a session in scripts/telegram-personal/session/session.txt. Whoever holds it can read every chat, send as you and log out your other devices. It stays in this personal space only — never a shared or team space. The assistant never prints it, copies it, moves it or puts it anywhere else. Whatever this space's container holds, the assistant holds; that is why the rest of this list exists.

2. You approve every message. The assistant shows you the recipient and the exact text and sends only after your explicit «да». If the text changes, it asks again. A scheduled run never sends — it drafts and asks you.

3. Telegram's rules apply. You use your own api_id. Nothing is done in your name without your knowledge; nothing is marked as read; volume stays human. Mass messaging from a personal account is what Telegram bans accounts for.

What it can and can't do

  • Read — people and small groups (up to 50 members) with activity in the last day by default, up to 7 days back. Channels, bots, archived chats and bigger groups are skipped and counted, unless you name them.
  • Send — one text message, or a reply, to a person or group you approve.
  • Not: channels (no posting), media sending, calls, marking read, an always-on listener. It reads when asked or when a scheduled run you turned on asks.

Setup — you just ask

Say «подключи мой Telegram». You will do three things yourself:

  1. At my.telegram.org → «API development tools», create an app (any name and description, platform «Other») and keep api_id and api_hash.
  2. Give them to the assistant: it shows a form card in the chat — type api_id and api_hash there and they go straight into «Доступы» («Telegram API»), the assistant never sees them. (Pasting «api_id api_hash» in one chat message also works: Plank hides it before the assistant sees it.)
  3. Scan the QR the assistant shows (login/qr.svg) from Telegram → Settings → Devices → Link Desktop Device. No second screen? It asks Telegram for a login code instead — send that code in the chat (it is useless once you are in). If you use a cloud password, the assistant asks for it with the same kind of card; it goes into «Доступы», not into the chat. You never have to open or edit a file.

For the assistant — the recipe

The scripts ship in the telegram-personal kit at scripts/telegram-personal/ (README there is the reference). If the folder is missing, the kit is not installed in this space — ask the person; do not hand-write a client.

0. Get an explicit OK

Before installing or pairing, tell the person in their language: this links their whole Telegram account; the session is stored in this space and gives full access; every send waits for their «да». Do not ask for api_id/api_hash in this message — say that after their yes you will show a form for them (a «нужны api_id и api_hash» in text invites pasting them into the chat). Continue only on a clear yes. Refuse in a space with other members.

1. Install once

cd scripts/telegram-personal && [ -d node_modules/telegram ] || npm install --no-audit --no-fund

2. Credentials

plank_credentials_list for «Telegram API». Missing → send the person to my.telegram.org (step 1 above), then ask with the card: plank_credential_request with label: "Telegram API", kind: "login", release: "container", fields: [{"name": "username", "label": "App api_id"}, {"name": "password", "label": "App api_hash"}] — end the turn and continue when they say it is saved. If they paste it instead and you see [plank:credential pending=…], call plank_credential_save with pending_id, fields: {"username": "<api_id>"}, kind: "login", label: "Telegram API", release: "container". Never write api_id/api_hash into a file. Telegram answers API_ID_INVALID (exit 4) → the pair is wrong: ask again with replaces: "Telegram API" and the same fields — the card gives that item a new value instead of making a second one. Another label → --vault-item "<label>" on every script.

3. Pair

Never ask the person to open or edit a file — not login/code.txt, not login/password.txt.

node pair.mjs qr --wait 180 &             # login/qr.svg, redrawn only when Telegram issues a new token
# show the person login/qr.svg; poll login/status.json; the process exits when linked

need_code from qr → nobody scanned in time: offer the code login — node pair.mjs code --phone +77011234567, ask them to send the code in the chat, then node pair.mjs finish --code <digits>. Exit 10 with need_password (from either path) → two-step verification is on: plank_credential_request with label: "Telegram облачный пароль", kind: "login", release: "container", fields: [{"name": "password", "label": "Облачный пароль Telegram"}], end the turn, and when they say it is saved run node pair.mjs finish --password-item "Telegram облачный пароль". A «пароль: …» they type in the chat is captured too — save it with plank_credential_save and run the same finish. node pair.mjs status says whether it is linked and as whom.

4. Read

node read.mjs --since 24h
node read.mjs --unread
node read.mjs --only "@username,Мама"

One JSON object: chats[] with messages[] (text, who, when, media kind), skipped{reason: count}. A skipped count is not «nothing there» — say what was skipped. Read rarely and once per task; never loop it.

5. Send — only after «да»

printf '%s' '<exact text>' > /tmp/tg-draft.txt
node send.mjs --to "@username" --text-file /tmp/tg-draft.txt                 # draft: recipient + text + confirm code, sends nothing
# show the person: «Отправить <имя> (@username) в Telegram: "<текст>"? (да/нет)»
node send.mjs --to "@username" --text-file /tmp/tg-draft.txt --confirm <code> # only after an explicit «да»

The code is bound to the account, the recipient, the exact text and --reply-to; anything changed is refused (confirm_mismatch) — show a new draft. A code that already sent is refused (confirm_used), so a retry never sends twice. Several chats with one name → ambiguous_recipient with candidates: ask, never pick.

Rules

  • One Telegram script at a time (.lock, exit 6).
  • flood_wait (exit 5): Telegram asked to wait seconds. Tell the person; do not retry sooner.
  • Exit 3 — not linked, or the session was ended from another device: pair again.
  • From another space (the personal assistant): run the scripts in this space's folder (cd /spaces/<slug>), never copy session/.
  • Never cat, print, copy or move session/, login/pending.json or the vault values.

What is kept, and for how long

data/messages.json is the client's rolling 7-day cache, pruned on every read; last-read.json is the last read, dialogs.json the chat list, sent.json which code sent which message id (no text). session/, login/ and data/ each carry a .gitignore, so none of it lands in the space's version history. A lasting history («сохраняй мою переписку») is the person's decision: only when they ask, into an app table keyed by chat_id:message_id with onConflict: 'ignore' — never the session or the api_hash.

See also: Connecting Telegram (bot), Personal WhatsApp, Credentials («Доступы»).