Inbound channels
An inbound channel is an external conversation bound to a folder — a Telegram chat, a Slack channel, an email thread — that a plugin relays into Filer as if it were a chat message, and relays results back out of.
The relay pattern
Section titled “The relay pattern”A channel plugin typically starts its own polling or webhook loop from an onAppReady hook, receives a message from the external service, and hands it to Filer with ctx.triggerInbound. This requires the hostTrigger permission — see Permissions. The payload’s fields are channelId, sourcePlugin, messageId and content, plus an optional attachments array of { filename, contentBase64 }.
// hooks/initialize.js — registered as "onAppReady" in the manifestexport default async function onAppReady(event, ctx) { startPolling(async (channelId, nativeId, messageText) => { await ctx.triggerInbound({ channelId, sourcePlugin: 'my-plugin', messageId: `my-plugin-${nativeId}`, content: messageText, }); });}messageId
Section titled “messageId”The convention is <plugin>-<nativeId> — your plugin’s name, then whatever id the external service already uses for that message, so the pairing is stable and reproducible if the same message arrives twice:
| Service | Native id | Status |
|---|---|---|
| Telegram | update.update_id |
official plugin |
the Message-ID header, used as-is (it is already globally unique); email-<uid> when a message has none |
official plugin | |
| Slack | event.ts |
suggested convention |
| Discord | message.id |
suggested convention |
The official Telegram and Email plugins relay inbound messages this way; the Slack and Discord rows are the ids those services expose that fit the same pattern, not something an official plugin sends.
Mapping senders to channels
Section titled “Mapping senders to channels”ctx.listChannels() returns the channels currently registered, which a plugin uses to build a sender → channel map — for example, mapping a Telegram chat id to the Filer channel it’s bound to. ctx.channels.getIntegrationConfig(channelId, pluginName) reads per-channel configuration your plugin previously stored with setIntegrationConfig.
Relaying results back out
Section titled “Relaying results back out”Once a message has been triggered into a folder and the agent responds, use the onSessionMessage hook (see Hooks and events) to catch that response and relay it back to the external service — posting a reply to the same Telegram chat, for instance.
Human-in-the-loop relay
Section titled “Human-in-the-loop relay”If the agent raises a HITL approval request mid-turn, the onAgentHitlRequest hook fires with { agentId, executionId, requestId, action, target, description, channelId }. A channel plugin can relay that description out to the external service (asking the human on the other end to approve or deny) and then call ctx.respondToHitl(agentId, requestId, approved, reason) with their answer.
Worked example
Section titled “Worked example”The official Telegram plugin implements this whole pattern end to end — polling, messageId construction, onSessionMessage relay, and HITL relay. See github.com/iyulab/filer-official-plugins.
- Permissions —
hostTriggerandchannels - Hooks and events —
onSessionMessage,onAgentHitlRequest,onChannelChanged
