channels/
Channels normalize external events into Assembly Line turns and deliver replies back to the provider. Add a channel file when the agent should receive HTTP, Slack, Discord, Teams, Telegram, Photon, or custom events.
Minimal Example
// channels/http.ts
import { defineChannel } from "@assemblyline-agents/core";
export default defineChannel({
description: "Receive a local HTTP message.",
transport: "http",
route: "/message",
methods: ["POST"]
});
The raw HTTP shape is intended for local development or authenticated host
integrations. In production, a generic HTTP channel without normalizeHttp()
is rejected: the runtime returns
403 Channel <name> requires normalizeHttp() or trusted host authorization in production.
unless the request is host-trusted.
Full Options
| Field | Type / values | Default | Effect |
|---|---|---|---|
description | string | — | Human and manifest metadata. |
transport | "http" | "local" | "webhook" | "queue" (required) | — | How events reach the channel. |
route | string | — | HTTP route the runtime serves for this channel. |
methods | string[] | — | Accepted HTTP methods. |
connection | string | — | Connection this channel uses for provider credentials. |
ingress | { requiredSecretEnv: string[][] } | — | Ingress-auth secrets required in production. |
metadata | JSON object | — | Structured app-specific metadata. |
ingress.requiredSecretEnv is a list of any-of groups of env var names:
production ingress auth is satisfied when every var in at least one group is
set. [["TELEGRAM_WEBHOOK_SECRET"]] requires that one var;
[["PHOTON_WEBHOOK_SIGNING_SECRET"], ["PHOTON_INGRESS_TOKEN"]] accepts either.
Provider Helpers
Provider helpers keep common webhook wiring to one file:
// channels/slack.ts
import { defineSlackChannel } from "@assemblyline-agents/slack";
export default defineSlackChannel();
Assembly Line ships helpers for Slack, Discord, Telegram, Microsoft Teams, and Photon/Spectrum. Provider helpers stamp route, required env, ingress, normalization, and delivery behavior.
assembly-line add installs a channel plugin and scaffolds the channel file for
Slack, Discord, Telegram, and Teams, then prints the required env vars;
existing channel files are left untouched:
assembly-line add slack agent
Photon channel files are written by hand with definePhotonChannel().
GitHub repository access remains available through
defineGitHubConnection() or defineGitHubMcpConnection() in
connections/; GitHub is not an inbound channel.
Normalization And Ingress
A channel module can export normalizeHttp to verify and normalize the
provider request before a turn starts:
normalizeHttp?: (request: ChannelHttpRequest, ctx: ChannelContext) =>
Promise<ChannelHttpResult> | ChannelHttpResult;
A normalized turn is a ChannelTurn:
interface ChannelTurn {
eventId: string;
channel: string;
conversationId: string;
userId?: string;
model?: string;
message: string;
attachments?: JsonObject[];
delivery?: JsonObject;
metadata?: JsonObject;
recentHistory?: string[];
}
Channel modules can also export startIngress(ctx, emit) for long-lived
provider listeners such as Discord Gateway. The Node host starts these listeners
beside the scheduler and stops them on server shutdown.
conversationId is the concurrency boundary as well as the transcript key.
Normalize it to the smallest provider object that users experience as one
session: a Slack thread root, Discord DM/channel/thread (or one interaction
command when no thread exists), Telegram chat/forum topic, Teams conversation,
or Photon space. Namespace raw provider IDs so unrelated channels cannot
collide. The runtime then permits one running or parked turn for that
normalized conversation, queues later turns FIFO, and leases other
conversations in parallel.
Conventions
Channel files own provider event semantics:
- Verify signatures, tokens, and route-auth secrets.
- Normalize provider payloads into
ChannelTurn. - Use stable provider delivery IDs for idempotency.
- Use a stable, provider-namespaced conversation boundary.
- Return fast ACKs for retrying webhook providers when needed.
- Deliver replies through provider APIs.
- Keep provider routing here, not in tools.