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 logicPayloads 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 chat | Yoke |
|---|---|
| INSERT message + INSERT inbox per recipient | INSERT message + stream append |
| Poll/sync inbox | Actor filters on conversation.message.posted |
| Delivery receipts table | Stream 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
onCreateor firstprocess - Backfill via
listMessageswhen 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=50See HTTP API.