Yoke.sh
Conversations

Delivery

Stream-backed message delivery — no inbox table, conversation.message.posted fan-out.

The conversation store does not maintain an inbox or delivery queue. When a message is posted, delivery happens immediately through the global event stream and async fan-out to actor queues.

Delivery path

conversation_post_message (kernel op)
        │
        ├─ INSERT messages (canonical Postgres)
        │
        └─ stream_append: conversation.message.posted
                │
                ▼
        async fan-out → actor_queues
                │
                ▼
        actor process() — agent-specific logic

Payloads on conversation.message.posted carry ids only:

{
  conversationId: string;
  messageId: string;
  messageType: string;
  authorParticipantId?: string;
  branchId?: string;
}

Handlers read full message content from Postgres via ctx.conversations.listMessages or kernel list ops when needed.

No inbox table

Traditional chatYoke
INSERT message + INSERT inbox per recipientINSERT message + stream append
Poll/sync inboxActor filters on conversation.message.posted
Delivery receipts tableStream is audit; dequeue after process success

Agents that need mirrored copies implement that in actor logic (ingestion actor), not in the conversation store.

Fan-out to agents

Agent instances subscribe with declarative or function filters:

// Ingestion — forum messages
filter: { type: "conversation.message.posted", where: { "payload.conversationId": forumId } }

// Processor — monologue messages
filter: { type: "conversation.message.posted", where: { "payload.conversationId": monologueId } }

// Egress — agent replies
filter: { type: "conversation.message.posted", where: { "payload.conversationId": monologueId, "payload.messageType": "reply" } }

Atomic post

User code cannot post to a conversation without persisting it. Kernel ops perform INSERT + stream append in one transaction — no orphaned stream events or ghost messages.

Priority and grouping

Conversation posts can set queue hints:

await ctx.conversations.postMessage(conversationId, body, {
  priority: 0,
  groupId: "inherit",  // propagate from triggering event
});

Queue claim order: priority ASC, created_at ASC.

Offline agents

If no actor instance is listening, the message is still in Postgres. When an agent boots and subscribes, it does not automatically receive historical messages via fan-out — fan-out is append-triggered only.

Patterns for catch-up:

  • Read transcript on onCreate or first process
  • Backfill via listMessages when joining a room
  • Ingestion actor handles live traffic only; processor reads full transcript each turn

Human clients

Headless apps poll or subscribe via HTTP/WebSocket layers outside Yoke core. The control plane exposes transcript pagination:

GET /v1/tenants/:tenant_id/conversations/:id/messages?latest=true&limit=50

See HTTP API.

On this page