Yoke.sh
Agents

Agent overview

Mental model for Yoke agents — actors, forum vs monologue, and the ingestion/processor/egress mesh.

An agent in Yoke is not a built-in runtime loop. It is a composition of ordinary actors that subscribe to stream events and call LLMs when needed.

Core concepts

ConceptWhat it is
Chat room (forum)A conversation you create via the Chat SDK — human-to-human or mixed
AgentAn actor row (persona) + one egress instance (routes replies to forums)
JoinAgent joins a forum → per-stint monologue + forum participant + ingestion + processor
MonologuePrivate conversation for one forum stint — system + agent + external shadow actors
RegistryOptional coordinator ctx.state (SQLite) storing JoinHandle per forum id

Forum vs monologue

Public chat and private agent reasoning share the same conversation store — different participant sets, not different tables.

FORUM F (public)                     MONOLOGUE M (agent stint)

  human                                system
  agent_alice (stint)                  agent_alice (same actor)
  agent_bob

  visible to all participants          visible only to monologue participants

When an agent joins a forum, bootstrap creates a fresh monologue for that stint and stores metadata.monologueId on the forum participant row. See Forum and monologue.

Where monologue IDs live

LayerStorageScope
CanonicalPostgres participants.metadata.monologueIdOne monologue per forum stint
Optional registryCoordinator actor ctx.state (SQLite __yoke_state)JoinHandle per forum id
Runtime routingEgress actor ctx.state.joinsforumId → { monologueId, forumParticipantId }

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

Agent = multiple actor instances

There is no monolithic agent process. A running agent is several actor instances sharing one agent actor identity:

flowchart TB
  subgraph Forum["Forum F"]
    H[Human posts message]
  end

  subgraph Mesh["Agent mesh (per join)"]
    I[Ingestion]
    P[Processor]
  end

  subgraph Monologue["Monologue M"]
    M1[Mirrored forum lines]
    M2[Tool calls / results]
    M3["type: reply"]
  end

  E[Egress — one per agent]

  H -->|conversation.message.posted| I
  I -->|copy with meta| M1
  M1 -->|conversation.message.posted| P
  P -->|infer + tools| M2
  P -->|final output| M3
  M3 -->|conversation.message.posted| E
  E -->|type: reply| Forum
InstanceScopeJob
EgressOne per agentCopy type: "reply" monologue messages back to the correct forum
IngestionOne per forum joinCopy forum messages into the active monologue
ProcessorOne per forum joinRun LLM inference and tool execution on monologue traffic
Follow-upOne per forum join (optional)Schedule a nudge when the agent was last to speak
Guardian subscriptionOne per forum join (optional)Watch monologue, spawn ephemeral guardian runners

Event map

Merge conversationEvents and agentEvents from @yoke/sdk:

EventWhen
conversation.message.postedAny message written to a conversation
agent.forum.joinedAfter joinConversation — egress updates its joins map
agent.monologue.compactedAfter compaction swap — egress repoints routing
assistant.follow_up_dueFollow-up timer fires
guardian.runEphemeral guardian runner starts

Design principles

  • No mirror relations — ingested copies carry body.meta.sourceConversationId for egress routing instead of message_relations.mirror.
  • No agents table — identity lives in actors; routing lives in participant metadata and egress state.
  • Agents are actors — LLM loops are event-driven actor instances, not a special runtime mode.
  • Opaque body — the runtime does not interpret message content; agents use body.parts conventions.

Next steps

  • Bootstrap — createAgent and joinConversation
  • Mesh pattern — detailed ingestion/processor/egress flow
  • Processor — the event-driven inference loop

On this page