@ekairos/channel

Channel domain library.

Unified multichannel communication for agent threads: one canonical message model across web, email, whatsapp, slack, teams and more — persisted on InstantDB.

install @ekairos/channel@betaroot channel_messagessurface channel_state

Schema

channel_messages

Canonical message crossing any channel: kind, direction, role, text/parts, status, externalId, participant — linked to event_contexts and event_items.

channel_state

Internal runtime key/value state with TTL for platform delivery (caches, lists).

channel_locks

Per-conversation delivery locks (token + TTL) so one handler runs at a time.

channel_subscriptions

Conversations the runtime is subscribed to, durable across restarts.

channel_queues

Pending inbound entries per conversation while a handler is running.

Actions

createChannels

Boots the multichannel runtime: configured platforms feed one inbound pipeline and expose one webhook handler each.

inbound.reply

Posts a reply on the same platform conversation and persists the outbound message.

ChannelRegistry.send

Sends an outbound message through a registered channel adapter by kind.

createChannelMessage

Constructs a canonical message record ready to persist and link.

useThread (agent)

The agent hook queries channel_messages alongside context items, so timelines span every channel for free.

Configure platforms. Everything else is domain state.

Apps configure platform credentials and two callbacks; messages, subscriptions, locks and queues persist on InstantDB through the channel domain.

import { createChannels } from "@ekairos/channel";

const channels = await createChannels({
  db,
  userName: "ekairos",
  platforms: {
    slack: { botToken: process.env.SLACK_BOT_TOKEN!, signingSecret: process.env.SLACK_SIGNING_SECRET! },
    telegram: { botToken: process.env.TELEGRAM_BOT_TOKEN! },
  },
  resolveContextId: async ({ channel, threadKey }) =>
    ensureThreadContext(`${channel}:${threadKey}`),
  react: async (inbound) => {
    const reaction = await agentThread(inbound.contextId).react(inbound.message);
    return reaction.text;
  },
});

// app/api/channels/[platform]/route.ts
export const POST = (req: Request, { params }) =>
  channels.webhooks[params.platform](req);
database…