Skip to content

Gateway

The Gateway is Triggerfish's central control plane -- a long-running local service that coordinates sessions, channels, tools, events, and agent processes through a single WebSocket endpoint. Everything that happens in Triggerfish flows through the Gateway.

Architecture

  WhatsApp / Telegram / Slack / Discord / WebChat / Email / CLI
                          |
                          v
              +-----------------------+
              |       Gateway         |
              |    (control plane)    |
              |  ws://127.0.0.1:PORT  |
              +-----------+-----------+
                          |
          +---------------+---------------+
          |               |               |
          v               v               v
    +----------+   +----------+   +----------+
    |  Agent   |   |   CLI    |   | Companion|
    |  (RPC)   |   | Commands |   |   Apps   |
    +----------+   +----------+   +----------+

The Gateway listens on a configurable port (default 18789) and accepts connections from channel adapters, CLI commands, companion apps, and internal services. All communication uses JSON-RPC over WebSocket.

Gateway Services

The Gateway provides these services through its WebSocket and HTTP endpoints:

ServiceDescriptionSecurity Integration
SessionsCreate, list, retrieve history, send between sessions, spawn background tasksSession taint tracked per-session
ChannelsRoute messages, manage connections, retry failed deliveries, chunk large messagesClassification checks on all output
CronSchedule recurring tasks and trigger wakeups from TRIGGER.mdCron actions pass through policy hooks
WebhooksAccept inbound events from external services via POST /webhooks/:sourceIdInbound data classified at ingestion
RippleTrack online status and typing indicators across channelsNo sensitive data exposed
ConfigHot-reload settings without restartAdmin-only in enterprise
Control UIWeb dashboard for gateway health and managementToken-authenticated
Tide PoolHost agent-driven A2UI visual workspaceContent subject to output hooks
NotificationsCross-channel notification delivery with priority routingClassification rules apply

WebSocket JSON-RPC Protocol

Clients connect to the Gateway over WebSocket and exchange JSON-RPC 2.0 messages. Each message is a method call with typed parameters and a typed response.

typescript
// Client sends:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "sessions.list",
  "params": { "filter": "active" }
}

// Gateway responds:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": [
    { "id": "sess_abc", "taint": "CONFIDENTIAL", "channel": "telegram" },
    { "id": "sess_def", "taint": "PUBLIC", "channel": "cli" }
  ]
}

The Gateway also serves HTTP endpoints for webhook ingestion. When a SchedulerService is attached, POST /webhooks/:sourceId routes are available for inbound webhook events.

Server Interface

typescript
interface GatewayServerOptions {
  /** Port to listen on. Use 0 for a random available port. */
  readonly port?: number;
  /** Authentication token for connections. */
  readonly authToken?: string;
  /** Optional scheduler service for webhook endpoints. */
  readonly schedulerService?: SchedulerService;
}

interface GatewayAddr {
  readonly port: number;
  readonly hostname: string;
}

interface GatewayServer {
  /** Start the server. Returns the bound address. */
  start(): Promise<GatewayAddr>;
  /** Stop the server gracefully. */
  stop(): Promise<void>;
}

Authentication

Gateway connections are authenticated with a token. The token is generated during setup (triggerfish dive) and stored locally.

SECURITY

The Gateway binds to 127.0.0.1 by default and is not exposed to the network. Remote access requires explicit tunnel configuration. Never expose the Gateway WebSocket to the public internet without authentication.

Session Management

The Gateway manages the full lifecycle of sessions. Sessions are the fundamental unit of conversation state, each with independent taint tracking.

Session Types

TypeKey PatternDescription
MainmainPrimary direct conversation with the owner. Persists across restarts.
Channelchannel:<type>:<id>One per connected channel. Isolated taint per channel.
Backgroundbg:<task_id>Spawned for cron jobs and webhook-triggered tasks. Starts at PUBLIC taint.
Agentagent:<agent_id>Per-agent sessions for multi-agent routing.
Groupgroup:<channel>:<group_id>Group chat sessions.

Session Tools

The agent interacts with sessions through these tools, all routed through the Gateway:

ToolDescriptionTaint Implications
sessions_listList active sessions with optional filtersNo taint change
sessions_historyRetrieve transcript for a sessionTaint inherits from referenced session
sessions_sendSend message to another sessionSubject to write-down check
sessions_spawnCreate background task sessionNew session starts at PUBLIC taint
session_statusCheck current session state, model, costNo taint change

INFO

Inter-session communication via sessions_send is subject to the same write-down rules as any other output. A CONFIDENTIAL session cannot send data to a session connected to a PUBLIC channel.

Channel Routing

The Gateway routes messages between channels and sessions through the channel router. The router handles:

  • Classification gate: Every outbound message passes through PRE_OUTPUT before delivery
  • Retry with backoff: Failed deliveries are retried with exponential backoff via sendWithRetry()
  • Message chunking: Large messages are split into platform-appropriate chunks (e.g., Telegram's 4096-char limit)
  • Streaming: Responses stream to channels that support it
  • Connection management: connectAll() and disconnectAll() for lifecycle management

Notification Service

The Gateway integrates a first-class notification service that replaces ad-hoc "notify owner" patterns across the platform. All notifications flow through a single NotificationService.

typescript
interface NotificationService {
  notify(recipient: UserId, notification: Notification): Promise<void>;
  getPreferences(userId: UserId): Promise<NotificationPreference>;
  setPreferences(userId: UserId, prefs: NotificationPreference): Promise<void>;
  getPending(userId: UserId): Promise<Notification[]>;
}

Priority Routing

PriorityBehavior
CRITICALBypass quiet hours, deliver to ALL connected channels immediately
HIGHDeliver to preferred channel immediately, queue if offline
NORMALDeliver to active session, or queue for next session start
LOWQueue, deliver in batches during active sessions

Notification Sources

SourceCategoryDefault Priority
Policy violationssecurityCRITICAL
Threat intelligence alertssecurityCRITICAL
Skill approval requestsapprovalHIGH
Cron job failuressystemHIGH
System health warningssystemHIGH
Webhook event triggersinfoNORMAL
The Reef updates availableinfoLOW

Notifications are persisted via StorageProvider (namespace: notifications:) and survive restarts. Undelivered notifications are retried on next Gateway startup or session connection.

Delivery Preferences

Users configure notification preferences per-channel:

yaml
notifications:
  preferred_channel: telegram
  quiet_hours:
    start: "22:00"
    end: "07:00"
    timezone: "America/Chicago"
  overrides:
    security: all_channels
    approval: preferred_channel
    info: active_session

Scheduler Integration

The Gateway hosts the scheduler service, which manages:

  • Cron tick loop: Periodic evaluation of scheduled tasks
  • Trigger wakeups: Agent wakeups defined in TRIGGER.md
  • Webhook HTTP endpoints: POST /webhooks/:sourceId for inbound events
  • Orchestrator isolation: Each scheduled task runs in its own OrchestratorFactory with isolated session state

TIP

Cron-triggered and webhook-triggered tasks spawn background sessions with fresh PUBLIC taint. They do not inherit the taint of any existing session, ensuring that autonomous tasks start with a clean classification state.

Health and Diagnostics

The triggerfish patrol command connects to the Gateway and runs diagnostic health checks, verifying:

  • Gateway is running and responsive
  • All configured channels are connected
  • Storage is accessible
  • Scheduled tasks are executing on time
  • No undelivered critical notifications are stuck in the queue

Released under the MIT License.