chat.*. The same seven tools send messages, read history, download attachments, react, and manage issues across Slack, Discord, Telegram, and Linear — the provider is just a field in the target. This page documents every tool and the addressing model they share. Read it when you are writing prompts that tell an agent how to reply, or deciding which connections an agent needs.
Enabling chat tools
chat.* tools register on a session when the agent declares a kind: local, implementation: chat tool. The tool’s auth binds one connection or several providers under one alias:
.auto/agents/assistant.yaml
auth: { kind: connection, provider: slack, connection: slack } for a single provider. The declared connections are the complete universe the tools can reach: target resolution matches the call’s target against them, and a project must be authorized to use the underlying connection grant. See connections and identities for how connections are created.
Tool names as the harness sees them are flattened — claude-code renders chat.send as mcp__auto__chat_send (see Auto MCP).
Addressing: targets, destinations, recipients
Every tool that touches a conversation takes atarget — a provider-discriminated address:
provider—"slack","discord","telegram", or"linear".destination— where in the provider: a channel plus optional thread. Per provider:- Slack:
workspace?,channel?(id or name,#optional),thread?. - Discord:
workspace?(connection or guild name),channel?(snowflake id or#name),thread?(the canonicaldiscord:<guildId>:<channelId>:<threadId>id from a prior send/history result, or a bare thread id together withchannel). - Telegram:
workspace?(the connection name),channel?(chat id such as"-1001234"or a known group title),thread?. - Linear:
workspace?,team?,issue?(issue comment threads),thread?.
- Slack:
to— a direct-message recipient instead of a destination:{ kind: "user", user: "<provider user id>" }(Slack additionally supports{ kind: "userGroup" }). Telegram users must have started the bot first; Discord users must share a guild with the installed bot.
slack:…, discord:…) — always pass them back exactly as a prior tool result or trigger delivery rendered them. The special selector "current" is accepted where a thread is expected.
target is optional on chat.send: with it omitted, the call resolves against the session’s declared connections and succeeds only when exactly one matches — a session with a single Slack connection can just send, while a multi-provider session must name the provider (an ambiguous target is rejected with an error, not guessed). destination.workspace narrows by connection name or account name when one provider has several connections.
Message content
Message bodies are a plain string, or an explicit format wrapper:The tools
chat.send
Send a message. Returns the address actually used plus provider ids you should keep.
Output:
{ address, messageId, threadId, provider }. Save threadId — a send may open a new thread, and the returned id is the canonical handle for replies, reactions, and history.
Sends are attributed: the platform resolves the agent’s per-agent persona (display name, avatar, bot identity from the agent’s identity) and posts as it. After an attributed send, the platform automatically records a thread-continuation binding keyed on the returned threadId and subscribes provider ingest for it — so unmentioned replies in a thread the agent opened can route back to the same session through a chat.message.subscribed trigger, with no explicit auto.bind call. (Declaring the matching trigger is still the agent author’s job; see Slack events.)
chat.search
Search the session’s available workspaces, channels, and users. Each result includes a ready-madetarget you can pass straight to chat.send or chat.history.
Search results are returned for Slack and Discord workspaces today;
warnings reports providers that could not be searched.
chat.history
Read recent messages from a channel or thread.
Each message carries
messageId, threadId, text, author, and — when files were attached — attachments metadata: { name?, mimeType?, size?, fileId?, url? }. The url is a provider URL that generally requires provider credentials; treat it as a reference, and use chat.attachment_download to actually fetch bytes.
chat.attachment_download
Turn an attachment reference into a short-lived signed URL the agent cancurl from its sandbox. The platform fetches the bytes server-side through the provider connection (Slack url_private with the bot token), stores them privately, and mints the URL — provider credentials never reach the sandbox.
Output:
{ downloadUrl, expiresAt, mimeType, size, filename }. The URL expires 5 minutes after minting — fetch it in the same turn.
Allowed types and per-category size caps: images (png, jpeg, gif, webp) and documents (pdf, markdown, plain text) up to 20 MB; archives (zip, gzip, tar) up to 100 MB; video (mp4, quicktime, webm) up to 200 MB. Over-cap or unsupported types fail with an error naming the limit.
Attachment download is implemented for Slack targets today; other providers’ attachments surface as metadata only.
chat.react
Add an emoji reaction — the cheapest acknowledgement an agent can give.
Output:
{ added, emoji, messageId, threadId }. Reactions are attributed to the agent’s persona bot.
chat.issue.get
Read issue metadata through a chat provider connection. Pass alinear target naming the issue:
id, identifier, title, description, url, priority + priorityLabel, team, state, assignee, parent/children, project, labels, timestamps.
chat.issue.update
Mutate issue metadata on the same target shape:
Output returns the updated issue plus an
updated report of which fields actually changed — an update that names an already-set state reports state: false.
Threading semantics
The rules that make multi-turn conversations work:- Thread ids are canonical and provider-prefixed. Whatever a trigger delivery,
chat.send, orchat.historygives you (slack:…,discord:…) is the id to pass back. Tools validate that a thread id matches its provider and reject mismatches. - A reply is a send with
destination.threadset. To start a thread from a channel message, use that message’s id as the thread root. - Continuation is a binding, not magic. Events route to sessions through bindings. A platform-delivered mention typically binds its thread to the spawned session automatically; an attributed
chat.sendthat opens a new thread binds it too. For any other thread the agent wants follow-ups from, it callsauto.bindwith aslack.threadtarget (the target type covers both Slack and Discord threads). The agent must also declare a trigger forchat.message.subscribed(orchat.message.mentioned) events for the delivery to actually reach it — see triggers. - Sends and reactions are persona-attributed, and messages authored by the agent itself are flagged in event payloads (
$.auto.authored) so trigger filters can keep an agent from replying to itself.
A complete example
The messaging heart of a conversational agent, adapted from a production configuration:.auto/agents/assistant.yaml