Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.agentfront.dev/llms.txt

Use this file to discover all available pages before exploring further.

Overview

ChannelRegistry extends RegistryAbstract and manages all channel instances in a scope. It advertises experimental: { 'claude/channel': {} } in server capabilities when channels are registered.

Methods

getChannels

Get all channel entries.
getChannels(): ChannelEntry[]

getChannelInstances

Get all concrete channel instances.
getChannelInstances(): ChannelInstance[]

findByName

Find a channel by its declared name.
findByName(name: string): ChannelInstance | undefined

hasAny

Check if any channels are registered.
hasAny(): boolean

size

Get the number of registered channels.
get size(): number

getCapabilities

Get MCP server capabilities contributed by channels.
getCapabilities(): Partial<ServerCapabilities>
Returns { experimental: { 'claude/channel': {} } } when channels exist, empty object otherwise.

subscribe

Subscribe to channel registry changes.
subscribe(
  opts: { immediate?: boolean },
  cb: (e: ChannelChangeEvent) => void
): () => void
Returns an unsubscribe function.

ChannelChangeEvent

type ChannelChangeEvent = {
  kind: 'added' | 'updated' | 'removed' | 'reset';
  changeScope: 'global' | 'session';
  sessionId?: string;
  version: number;
  snapshot: readonly ChannelEntry[];
};

Accessing the Registry

The channel registry is available on the scope after initialization:
// From a tool context
const scope = this.scope as unknown as { channels?: ChannelRegistry };
const channels = scope.channels;

if (channels?.hasAny()) {
  const allChannels = channels.getChannels();
  const chatBridge = channels.findByName('chat-bridge');
}

Session-Scoped Subscriptions

Channel notifications are session-scoped. Sessions must be subscribed to a channel to receive its notifications. This prevents data from leaking between connected agents. Subscription methods are on NotificationService (accessed via scope.notifications):

subscribeChannel

scope.notifications.subscribeChannel(sessionId: string, channelName: string): boolean
Subscribe a session to a specific channel. Returns true if this is a new subscription.

unsubscribeChannel

scope.notifications.unsubscribeChannel(sessionId: string, channelName: string): boolean
Remove a session’s subscription to a channel.

subscribeAllChannels

scope.notifications.subscribeAllChannels(sessionId: string, channelNames: string[]): void
Bulk subscribe a session to multiple channels. Called automatically during MCP initialize when the client has claude/channel capability.

isChannelSubscribed

scope.notifications.isChannelSubscribed(sessionId: string, channelName: string): boolean

getSubscribersForChannel

scope.notifications.getSubscribersForChannel(channelName: string): string[]
Returns all session IDs subscribed to a channel.

getChannelSubscriptions

scope.notifications.getChannelSubscriptions(sessionId: string): string[]
Returns all channel names a session is subscribed to.
Auto-subscription: When a session initializes with experimental: { 'claude/channel': {} } capability, it is automatically subscribed to all available channels. Channel subscriptions are cleaned up automatically when a session disconnects.

Session-Targeted Delivery

Events from session-scoped sources (agent completion, job completion) carry the originating sessionId and are delivered ONLY to that session:
// ChannelInstance.pushNotification() with targetSessionId
channel.pushNotification('Job completed', { job: 'daily-report' }, targetSessionId);
//                                                                  ^^^^^^^^^^^^^^^^
//                                                            only this session receives it
Global events (webhooks, file changes, app events) have no targetSessionId and go to all subscribed sessions.

Replay Buffer

Channels with replay: { enabled: true } buffer events for later delivery:

replayBufferedEvents

channel.replayBufferedEvents(sessionId: string): number
Replay all buffered events to a session. Returns the number of events replayed. Replayed events include replayed: "true" in their meta.

clearReplayBuffer

channel.clearReplayBuffer(): void
Session-targeted events are NOT buffered (they’re ephemeral to the session). Only global events are stored in the replay buffer.

ChannelNotificationService

The companion service for sending notifications (session-scoped):
const scope = this.scope as unknown as {
  channelNotifications?: ChannelNotificationService;
};

// Send to all sessions subscribed to 'status' channel
scope.channelNotifications?.send('status', 'Deployment complete');

// Send to a specific session only
scope.channelNotifications?.sendToSession(sessionId, 'Job result', { source: 'jobs' });

ChannelEventBus

The in-process event bus for app-event sources:
const scope = this.scope as unknown as { channelEventBus?: ChannelEventBus };

// Emit an event that channels with matching app-event source receive
scope.channelEventBus?.emit('app:error', {
  message: 'Connection refused',
  level: 'critical',
});