Channels¶
A channel tentacle holds one platform connection open, translates its events into messages, and draws a run back onto the platform in whatever that platform can show. Keyed by instance, so two Lark apps are two keys, two separate sets of threads, and two bots.
Enable a channel¶
Follow the app setup for Slack, Lark / Feishu or
Discord, connect the NapCat bridge, or build
Trunkline for browser access.
Add its block to tentacles.yaml, supply the required credentials, and name
at least one enabled agent in agents. Set enabled: true if the generator
left it disabled. Check the configuration, restart Octomate and send a message
to verify the connection. See the shared enablement steps.
tentacles:
slack:
type: slack
app_id: A0123456789
agents: [inkling, claude]
mention_only: true
stream:
flush_interval: 0.2
recap:
messages: 16
characters: 1000
Supply secrets in YAML or environment variables named
OCTOMATE__TENTACLES__<KEY>__<FIELD>. A .env file is optional; remove matching
YAML placeholders if using it, because YAML takes precedence.
Shared settings¶
| Key | Default | Meaning |
|---|---|---|
agents |
required | Agent ids, entry order. The first answers new conversations; every one is a route. |
enabled |
true |
A disabled channel keeps its block and its routes are still validated. |
mention_only |
true |
On a surface others can read, the bot answers only when addressed. |
stream |
per platform | Live rendering: enabled, flush_interval, min_chars, max_chars, fold_threshold. |
recap |
16 messages, 1000 chars each | How much of a chat room a kick is shown, since a kick there starts with an empty context. |
mcp |
false |
Whether this channel serves its own MCP tools to the agents on it. Slack only. |
Streaming defaults differ: Slack, Lark and Trunkline stream by default; Discord
coalesces edits and is off until you set stream.enabled: true.
NapCat sends completed messages and has no streaming transport.
Within a stream: block you set only what you change and keep the
platform's other defaults.
Being addressed¶
The mention gate looks at whether the surface is shared, not at its type. A direct message, a thread in a Slack DM, or a Lark one-to-one chat is never gated. On a shared surface the bot answers when:
- the message
@-mentions it, - the message replies to one of its messages, which Discord reports; Slack, Lark and NapCat do not supply the reply-author information used by this gate, or
- the message lands in a thread an agent already owns, because a handoff pinned it.
A group's main channel is never pinned to an owner, so there a mention stays the
rule even after a long exchange. Set mention_only: false to answer everything on
that channel.
A message sent to a thread or chat room while a turn is running there waits: it is in the history, and the turn the next message starts answers it too.
Identity¶
The first time someone speaks, the channel records a visitor profile: a platform identity owned by nobody. The agent still answers. What a visitor lacks is everything that follows the person across channels: history search, moves into their direct messages elsewhere, their MCP connectors. Linking the profile to an account fixes that; see Accounts and tokens.
What each channel renders¶
| Slack | Lark | Discord | NapCat | Trunkline | |
|---|---|---|---|---|---|
| Streaming text | Native stream | Streaming card | Message edits | No; completed messages | Every event, live |
| Thinking and tool cards | Folding plan | Cards that fold | No | No | Yes |
| MCP app artifacts | Card with viewer button | Card with viewer button | Card with viewer button | Text overview and link | Inline cards and standalone pages |
| Todo checklist | Plan tasks | Card | No | Text with the final reply | Yes |
| Approval cards | Buttons, paged | One card each | Buttons, one each | Text only | Yes |
| Question cards | One message | One card | Buttons and a modal | Text only | Yes |
| Sub-threads | Yes | Yes | Public threads from a text channel | No | No; top-level threads only |
| Direct messages | Yes | Yes | Yes | Yes | No |
| Profile linking | From chat, or Slack OAuth | From chat, or Lark OAuth | From chat, or Discord OAuth | From chat | Not needed |
Subagents get a timeline of their own on Slack, Lark and Discord. Every channel posts a one-line error with a trace id when a turn fails, and ignores a message the platform delivers twice.
A channel draws each thread's runs in order, apart from the run itself. A slow platform call holds up only its own thread, and a message the platform refuses costs that message, not the turn: the reply is in the ledger regardless. Cards answered on another surface stay as they are on IM channels for now; Trunkline marks them answered.
The threads page explains what each platform's chats and threads become inside Octomate, and where a reply lands.
Artifact overviews¶
Slack, Lark, Discord and NapCat can post a saved artifact's title, provider and viewer link in the conversation where it was created. Separate invocations get separate messages, including during a run. The overview contains no app HTML or tool arguments and does not rerun the tool.
Set the existing Trunkline host in octomate.yaml to enable these overviews:
This uses your existing viewer deployment. The artifact settings also let you choose its path. Without a viewer origin, IM channels keep their normal replies and do not post artifact overviews. Trunkline's inline cards still work independently of this setting.
Opening a link requires access to that host and signing in as the artifact's owner. Posting a link in a group does not grant its members access. The interactive app still needs the separate sandbox setup; the overview itself needs no connection to the app provider.