Files
mesh-catalog/modules/telegram/README.md
T
jochen 35c4de7d08
mesh/merge-gate pass: builds messenger, telegram → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer head of the same pull request
messenger, telegram: a second tap on the recorded answer is said as recorded, and the fallback claims nothing (issue 372 review)
The review found that a double tap while the phone's spinner turned would be
answered 'That answer was not taken', reading as if the approval failed; it is
now 'You already chose Approve at 13:30: recorded.' and does nothing more. The
fallback toast no longer promises a change that may not come (a stranger's
tap), the wait outlasts the router's 10 s wait for the controller's root word,
the channel's own refusals stay in the chat too, and the store's error words
stay in the journal.
2026-10-10 14:05:41 +02:00

6.6 KiB

telegram

A channel of the operator's conversation: kind telegram of the channel and intake benches the router (messenger) declares (novox/hq ADR 0234, ADR 0259). It reaches the operator away from the machines, and it proves who answered: Telegram authenticates the sender, and the router compares it with the account linked as the operator.

  • Shows what the router sends (its kind's worker on the channel queue): a message, a question with buttons — each button carries only the router's one-time ticket — or an edit of a message shown before. It sends to the account the router names as linked, or, before one is, to the chat a /start came from.
  • Says what the operator chose on intake under its own kind: a tapped button (choice), with the sender as Telegram authenticated it; /start (link); a message it could not deliver (failed); and whether it can send (standing). Only a private chat with the account itself counts.
  • A tap is acknowledged on the phone with the router's word on it (issue 372): the router answers a choice with a message in reply to it — "You chose Approve: recorded, and claude-code was told.", or why it was not taken — and this channel shows that as the tap's own acknowledgement, the short line Telegram shows over the chat. A word with more to it (a refusal's reason, Details) is also said in the chat, where it stays. Nothing is acknowledged before the router's word, so the phone never says "recorded" for what was not; without a word in 13 seconds the tap is acknowledged with words that claim nothing, and the word when it comes is said in the chat. A secret is never an acknowledgement.
  • A code (six digits, the one shown on the desk when linking) is asked of the router as a proof, by request and reply: never in an event, never kept, and deleted from the chat at once.
  • Judges nothing. Whether the sender is the operator, and what an answer may do, is the router's.

The defects of the client it replaces (novox/hq to-be 46 §12)

fixed here
D1 up to 4096 characters arrive whole; longer is cut and the cut said
D4 a warning or a clearing arrives without sound; an urgent message or a question rings
D5 a rate limit is waited out as told
D6 a refusal is a permanent failure, said to the router and not retried; an edit to the same text is a success
D7 the deprecated preview flag is gone
D8 a request that cannot be written is said
D10 standing checks the token with Telegram (getMe), not only that a value is present

D2 and D3 (a reopening said by an edit; a clearing edits the first message) are the router's, and D9 the watcher's.

How it keeps the token from the agents (novox/hq ADR 0259 §8, as revised)

  • It runs as the account telegram, in a runtime of its own, on a bus account of its own (runs-as). The machine's runtime runs as the operator's account — which every agent runs as — and never carries it; the controller refuses to compose it there.
  • Its state directory, its bot token and its bus credential belong to telegram, 0700 and 0600 (secrets-owner). The operator's account reads none of them, and cannot attach to its process.
  • Only this kind's holder says this kind's choices, links and codes: the bus grants those subjects to its own account alone.
  • The router believes it proves its sender only so placed, and only while the controller's self-check finds no agent able to become root without a person on its machine or the router's (agent-root).
  • If an agent holds root on the machine, none of this holds: root reads the token and every credential.
  • A tap counts only on a message showing the words it put there. It keeps a digest of what each message shows; a tap on one whose words differ — changed by another holder of the token — or on one it never showed is refused on the phone and never said to the router.

Where an approval from Telegram means something (a known gap, accepted by the operator on 2026-10-09)

The router does not measure or enforce what follows, and does not hold approvals back for it: the operator accepted the gap for now, and novox/hq issue 344 records it with what closes it.

An approval from Telegram proves only that the linked account tapped. It is meaningful where nothing working for the operator can tap in their name, which on a machine where agents run needs all three of:

  1. The agents run under an account of their own, without sudo (novox/hq ADR 0266), so they cannot become root or the operator.
  2. That account has no access to the operator's X display — no Xauthority cookie for it. X11 has no isolation between the clients of one display: a program on it reads every key typed and can click any window, the Telegram client's buttons among them.
  3. The operator's Telegram Desktop data is readable by the operator alone (~/.local/share/TelegramDesktop/tdata, 0700). Found 0755 with its files 0644: any account on the machine can copy the session and be the operator on Telegram from elsewhere.

Until agents have their own account on a machine, the operator's Telegram client on that machine is not counted as safe: approve from the phone. No module of the catalogue installs Telegram Desktop today, so nothing of the mesh keeps tdata 0700 yet; the operator sets it by hand (chmod -R go-rwx on it) until one does.

Where it runs

Held once for the mesh: assign it to the control node, the stably reachable one. Long polling is outbound only, so no route into the mesh is needed, and a stolen token can read updates (a conflict says so) but never inject one.

What the operator gives

  1. A bot: in Telegram, talk to @BotFather, /newbot, a name and a username. BotFather answers with the bot's token. Keep it on the phone; never paste it into a chat with an agent.
  2. The token, to the vault, as this module's own secret telegram-token: the vault's verb for a secret given at the desk, or secret accept <control node> telegram telegram-token at a terminal on the control node, which reads it without echoing it. Then push the control node.
  3. The link: send the bot /start. A six-digit code appears on the desk; send it to the bot within ten minutes. The account answers acknowledgements at once and approves an hour later; every channel says so. messenger_identities shows it. messenger_unlink asks the linked account itself whether to unlink it.

Tools

tool does
telegram_status whether it can send and why not (never the token), the bot's name, when updates last arrived, the last delivery and error, counts since start, and its rules