How Slack conversations map to Apus sessions, and where replies land.

Threading, sessions, and reply tags

Reply threading controls:

Manual reply tags are supported:

For explicit Slack thread replies from the message tool, set replyBroadcast: true with action: "send" and threadId or replyTo to ask Slack to also broadcast the thread reply to the parent channel. This maps to Slack's chat.postMessage reply_broadcast flag and is only supported for text or Block Kit sends, not media uploads.

When a message tool call runs inside a Slack thread and targets the same channel, Apus normally inherits the current Slack thread according to the effective account, chat-type, or per-channel replyToMode. Automatic replies and same-channel send or upload-file calls use the same per-channel override. Set topLevel: true on action: "send" or action: "upload-file" to force a new parent-channel message instead. threadId: null is accepted as the same top-level opt-out.

replyToMode="off" disables optional outbound Slack reply threading, including explicit [[reply_to_*]] tags. Agent View and Assistant View are Slack-managed threaded experiences, so their replies and status remain on the visible root regardless of this setting. It does not flatten other inbound Slack thread sessions. This differs from Telegram, where explicit tags are still honored in "off" mode. Slack threads hide messages from the channel while Telegram replies stay visible inline.

Agent View DMs

Slack Agent View (features.agent_view) is Slack's messaging experience for AI apps. Slack marks the app as an agent, and in the app's Messages tab each message typed in the top-level composer starts a new root that Slack threads on its own; follow-ups belong inside that root's thread. Apus treats every root as a separate conversation:

Slack never states which experience an app uses, so Apus records Agent View from the first of these signals it sees: an app_context_changed event, a DM that carries app_context, or the threadless assistant.threads.setSuggestedPrompts call Apus makes when a member opens the Messages tab. Slack answers that call with ok or internal_error for Agent View apps and with not_agent_app for Assistant View apps, so both ok and internal_error count as evidence; transport failures stay inconclusive and are retried on the next open. A DM whose thread_ts equals its own ts is recognized as a Slack-managed root on its own. Until one of these signals has been seen, a plain DM root follows ordinary DM routing.

The marker is durable and keyed by account, workspace, and Slack app ID, so Agent View survives Gateway restarts once the app ID is known. Socket Mode reads the app ID from the app token at startup. HTTP mode learns it from the first signed event after startup and logs slack app id <id> learned from signed event once. Relay mode has no app ID source, so its marker lives only in the running process. Existing apps on features.assistant_view keep Assistant View threads instead; see Additional manifest settings.

Recent room history

Admitted channel and group turns fetch a recent window from Slack, including after a Gateway restart. channels.slack.historyLimit bounds the window (default 50, with messages.groupChat.historyLimit as a fallback). Account overrides apply. Automatic observed-message windows are capped at 200 messages; the JSON integer maximum (9007199254740991) selects the 50-message default.

For observed DM context, dmHistoryLimit and dms.<userId>.historyLimit use a default of 0 (disabled) and a maximum of 200 messages. The JSON integer maximum selects that disabled default, including for a per-DM override.

These saved fields also control embedded session transcript trimming in user turns, where 0 means no trimming and the existing eviction cushion still applies. Doctor preserves the configured values; the observed-message ceiling does not impose a new transcript-turn ceiling. With requireMention: true, messages that do not satisfy the configured mention or implicit-mention gates do not start agent turns or automatic history reads.

Slack remains authoritative: edits, deletions, retention, token scopes, and availability govern retrieval. There is no separate Apus message archive. Recovery does not rewrite prior agent transcripts. New recent windows respect the active session boundary; initial thread seeding keeps its existing thread.initialHistoryLimit behavior. The current message, debounced source messages, and later messages are excluded from the recent window. Initial thread history uses its existing rendering path once. With thread.historyScope: "channel", the recent window uses the channel timeline while initial thread seeding remains separate.

Thread-scoped history reads only that thread. Slack returns thread replies oldest first, so automatic thread recovery stops after three pages. If that cannot reach the recent end, Apus logs an omission rather than presenting an old prefix as recent. Filtering and Slack page limits can also produce a shorter window. A read failure omits automatic history but does not discard the addressed message. Recent-window media recovery attempts at most four image attachments, including failed attempts. Current-message and explicit-reply media keep their separate limits.

Set historyLimit: 0 to disable automatic room history, including initial room thread history. Explicit reply and thread-starter context remain separate. The existing message(action="read") tool can page through older Slack messages after restarts or session resets, subject to Slack access and retention.