Flow
ServicesCommunications Service

Architecture

Conversation and announcement domains, provider adapters, webhooks, and the Foundry wake.

Binaries

BinaryPathRole
APIcmd/apiHTTP server + outbox publisher; flags -migrate, -openapi
conversationListenercmd/conversationListenerLogs conversation events and retries a Foundry wake
announcementListenercmd/announcementListenerLogs announcement events

Layout

services/communications/
  domains/conversation/events/
  domains/announcement/events/
  internal/
    domains/
    providers/      ← Twilio, Mailgun
    catalog/        ← committed tool list
    wake/           ← HTTP POST to foundry-api
    handlers/
    authz/
    command/
    publisher/
    testdb/
  messageBus/
  migrations/
  db/

Tables use the domain slug, singular (ADR 0015). conversation_message.announcement_id joins the two domains, so there is one sqlc package (ADR 0023).

Inbound path

Webhooks are chi handlers, not Huma, because Twilio and Mailgun post forms. They skip Cedar and verify the provider signature. After commit, if conversation.agent_id is set, the API POSTs /v1/agents/{id}/wake with conversation_id, message_id, and channel. Body text stays in this database. Foundry fetches GET /v1/messages/{id}. A failed wake is retried from the outbox, not rolled back on the inbound row.

Inbound email to ${slug}@ai.flow.life (prod) or ${slug}@dev-ai.flow.life (dev) uses a Mailgun receiving route you create in the dashboard. The route forwards every address on that domain to POST /v1/webhooks/mailgun. The webhook asks Foundry GET /v1/agents/by-slug/{slug} and links the thread before the wake.

Linking is POST /v1/conversations/{id}/link. Foundry stores the same conversation_id on the agent row and calls this path after create or edit.

Channels

sms | email | whatsapp | signal. Phase 1 adapters: Twilio SMS, Mailgun email. The other two are reserved.

See ADR 0045.

On this page