Menu da documentação

Documentação

Slack and Telegram

Chat-driven intake and remote approvals.

Nesta página

Two chat surfaces, two different jobs

Slack and Telegram both put TDE where the conversation already is, but they solve different problems. Slack is team intake: your colleagues raise things in channels and TDE turns the ones addressed to you into work. Telegram is a private remote control: your own bot, in your own chat, so you can approve a guarded action from a phone on a train.

Slack

Two apps, and only one of them is yours to install

TDE TriageTDE Assistant
What it isYour own Slack account for Bot and the native TDE Slack clientA workspace bot, mentioned as @tde
Who sets it upYou, from a project's IntegrationsA Slack administrator, once, from the marketplace
TokenA user token (xoxp-), in your local vaultA bot token, held server-side and never delivered to a desktop
ScopesUser read/history/profile scopes plus chat:writeapp_mentions:read, chat:write, commands, channel and group history
How it runsLocal Bot plus a native Rust client that talks directly to SlackA hosted events router, in real time
Identity(TDE user, team, Slack user)(team, Slack user) mapped to a TDE user

Triage has no bot, no Events API subscription and no workspace-wide command surface. It sees exactly what your Slack account sees. Assistant is the opposite: it is the visible @tde in channels, and the desktop never installs, configures or links it.

The same Triage authorization powers TDE Slack, the native mouse-first Desktop client. It browses channels, DMs, history and threads and lets the human compose messages without a second login. The client talks directly to Slack's Web API; no TDE server proxies chat traffic. Its cache and drafts are isolated per (workspace, Slack user) on each device, while Slack remains the source of truth. The write scopes do not let Triage Bot post automatically — only a human submit action in TDE Slack sends a message.

Existing Triage installs created before the native client must reconnect once to grant chat:write. When Slack reports missing_scope, TDE Slack shows a Reconnect action. Disconnecting Triage immediately invalidates the live client and removes that identity's local message cache.

Linking is order-independent. Because Triage already establishes (team, Slack user), installing Assistant later backfills the eligible Triage users, and connecting Triage after an install links immediately. There is no second OAuth. The two are separate entitlements even though the current rollout grants both together.

Connecting Triage

From Project → Integrations, pick Slack. TDE calls a hosted OAuth broker with your license as a bearer token, renders the returned authorization URL as a QR code in TDE Browser, and polls until Slack redirects. The license never appears in a URL, and the broker URL is validated — no embedded credentials, no query, no fragment, HTTPS unless it is loopback.

The result is stored as connector slack-triage:<team>:<user> with the team name and Slack user id as metadata. Only a xoxp- user token is accepted; a bot token is rejected with Slack Triage requires a user token. See Connectors.

How a Slack message becomes a task

The triage bot runs every 15 minutes and walks every conversation your token can see, in order: DMs, group DMs, private channels, then public channels.

  • The first time it sees a DM or group DM it triages a bounded window of 15 recent messages. The first time it sees a channel it only records a cursor — it never triages a channel's backlog.
  • Afterwards it fetches incrementally, up to 50 messages, from the stored cursor.
  • Bot posts, your own messages and blank messages are filtered out.
  • An agent decides whether each new thread is a demand. There is a cap of ten agent calls per run; over budget it falls back to a keyword heuristic.

A new demand becomes a task with tracker id slack:<team>:<channel>:<thread_root_ts>, filed into the Context stage. Later messages in the same thread do not create a second task — while the task is still in Context they are appended as activity comments authored slack, with the body New Slack activity in #channel: followed by the message.

The run log lands in ~/.tde/log/bot-slack.log, ending each run with a line counting tasks created, threads updated, conversations scanned, agent rejections and API errors.

The @tde surface

When Assistant is installed, mentioning @tde in a channel it was invited to starts a real-time exchange. Follow-ups in the same thread need no mention. Direct messages are deliberately unsupported — the App Home messages tab is off.

Your device runs a small daemon that registers with TDE's events router (https://events.tde.sh, overridable with TDE_EVENTS_URL) using your license, receives a short-lived token that exists only in memory, and holds a WebSocket. The router is authoritative about which device is live: only the newest connection holds a lease, and a stale machine cannot acknowledge, post, or pass the final board mutation guard. A registration failure with 403 means Assistant is not entitled or not installed yet, and the daemon keeps retrying with backoff.

Each mention is classified into exactly one of four actions:

ActionWhat happens
replyA read-only answer posted in the thread. No task, no approval
read_only_runAn investigation in a provider-enforced read-only sandbox, with no connector credentials injected, posted back to the thread
clarifyOne clarification question. The board is untouched
changeOne task for the thread, carrying an explicit plan and blocked until a human approves that exact plan

Slack text is treated as data, never as instructions. Replies are capped at 4000 bytes, plans at eight steps, thread context at 30 messages.

Approving a plan

Two surfaces reach the same atomic gate:

  • Buttons. The plan is posted as Block Kit with Aprovar plano and Rejeitar. Each button carries the task and plan ids, so a stale button from an old message is an idempotent no-op. After a decision the original message is replaced through Slack's interaction callback URL — pinned to hooks.slack.com, redirects disabled — so the buttons visibly disappear.
  • A typed reply in the same thread, parsed by a strict whole-message matcher, never by the model. approve, approved, approve plan, yes approve and their Portuguese equivalents count; anything else does not.

A message that mentions a human colleague is never rewritten into a bare approval: the daemon deliberately does not strip a leading mention before parsing. And an unrecognized Slack user's mention is silently acknowledged with no reply at all, so the existence of your private TDE connection is not disclosed to the workspace.

A genuine processing error is retried twice; the third gives up with a single message rather than looping. Everything the daemon does is logged to ~/.tde/log/slack-events.log.

Telegram

Setup

Telegram is a personal connector — one bot, one chat, one machine. It takes two values, in this order:

  1. A bot token from @BotFather. TDE shape-checks it and then verifies it live with getMe, recording the bot's username and id.
  2. Your chat id. Message the bot first, then get the id from @userinfobot.

TDE rejects the common mistakes explicitly: pasting the bot token again where the chat id goes, or pasting the bot's own id instead of yours. On success it sends TDE inbox mirror connected. and mirrors your last 20 inbox rows.

The bridge then long-polls getUpdates with a 25-second timeout, persisting its cursor to ~/.tde/telegram_offset so a restart does not replay or skip updates. Updates from any chat other than the configured one are dropped before they are classified.

Message to task

Any message that is not a /command becomes a task with tracker id telegram:<update_id>. The title is the first line, truncated to 80 characters; the body is the whole message. It goes through the same external intake path as Linear sync, so an agent decides the project, the agent and persona, the labels and the priority. TDE replies 📥 Task criada: <title>.

Approvals from a phone

Two different button flows exist, and they are not the same thing.

Guard approvals fire whenever an agent action hits a guard rule:

Telegram
🔐 Approval needed
run: rm -rf ./build
Guard rule: rm -rf (recursive delete)

[ ✅ Approve ]  [ ❌ Deny ]

Parked questions fire when an agent asks something with real options. Each option becomes a button labelled with the option's own text — never a label guessed from prose. Tapping one records the answer and re-runs the stage.

In both cases the desktop shows the same prompt, whichever surface answers first wins, and the loser reports Already handled. A tap whose nonce no longer matches a live request is inert. See Human gates.

The progress mirror

Tasks whose tracker id starts with telegram: mirror stage transitions only to your chat:

EventMessage
Stage started▶️ <title>: <stage>
Finished✅ <title>: done
Failed❌ <title>: <error>
Blocked⛔ <title>: <blocker>

Individual log lines, traces and subtask updates are deliberately not streamed — a phone would drown. This has a design consequence worth knowing when you write prompts or skills: anything the human must decide should surface as a blocker or a guarded action, not as a log line, because a log line will never reach the phone.

Bot commands

Three, all read-only:

Telegram
/tasks    list current board tasks by stage
/status   task counts per stage
/help     this message

/start is an alias for /help, and /command@yourbot works too. Anything else is Unknown command. Try /help.

The bundled skills

Two shipped skills teach agents how to work the tasks these bridges create, and they are provisioned automatically when the matching integration is configured.

  • slack-triage — recognizes a task whose tracker id starts with slack: or whose activity contains New Slack activity. It tells the agent that comments keep accumulating while the task sits in Context, so the latest comments win over the description, and that the deliverable is a reviewer-ready draft reply, never a posted message.
  • telegram-triage — recognizes telegram: tasks and, more usefully, explains the phone-side constraints above: guarded targets must be self-explaining because the approver has no context, stage names must be legible because they are all that gets mirrored, and there is no token streaming.

See Skills, prompts and deliverables.