Yoke.sh
Conversations

Forum & Monologue

Two conversation roles — public forum for participants and private monologue per agent join stint.

Forum and monologue are product roles, not separate database tables. Both use the same conversations, participants, and messages schema — they differ in who participates and how agents route between them.

Forum (public chat)

A forum is a conversation with multiple participants — humans and agent personas:

FORUM F

  human_alice
  human_bob
  agent_support (stint p3)

  messages visible to all active participants

Create via Chat SDK:

const room = await chat.createRoom({ title: "support" });
await chat.addMember(room.id, humanActorId);

Monologue (agent internal)

When an agent joins a forum, bootstrap creates a separate conversation — the monologue — with typically system + the agent actor:

MONOLOGUE M (agent support's stint)

  system
  agent_support (stint p4)

  messages visible only to monologue participants
  (ingestion copies, tool calls, reasoning, replies)

Humans in the forum do not see monologue traffic unless egress publishes a type: "reply" back to the forum.

Pairing

FORUM F                          MONOLOGUE M
  │                                    ▲
  │  ingestion (per join)              │
  └────────────────────────────────────┘
                │
         processor + egress
LayerStorageScope
Canonicalparticipants.metadata.monologueId on forum stintOne monologue per forum join stint
Optional registryCoordinator actor ctx.stateJoinHandle per forum id
Runtime routingEgress ctx.state.joinsforumId → { monologueId, forumParticipantId }

createAgent does not create a monologue. Each joinConversation creates a fresh monologue and writes monologueId onto the forum participant stint.

Per-join instances

Each joinConversation call spins up:

InstanceRole
ingestionCopy forum messages into monologue (external shadow actors per author)
processorLLM + tools on monologue traffic
egress (one per agent)Route type: "reply" from any monologue stint to correct forum

Ingestion without mirror relations

Ingested copies carry routing metadata in body.meta:

{
  "meta": {
    "sourceConversationId": "forum-id",
    "sourceMessageId": "original-message-id",
    "sourceActorId": "forum-author-actor-id"
  }
}

No message_relations mirror table — egress uses sourceConversationId to pick the forum.

Compaction swap

When compaction changes the transcript, the forum participant's metadata.monologueId is updated to point at a new monologue. Ingestion resolves the active monologue from participant metadata on each event.

Event agent.monologue.compacted notifies egress to update its joins map.

1:1 is just a small forum

A direct message between system and agent is a forum with two participants — same bootstrap path as multi-party support rooms.

On this page