Yoke.sh
Reference

Ops Bridge

Rust ↔ Deno JSON-RPC reference — stream_append, state_cas, dispatch_process, and conversation ops.

The ops bridge connects user TypeScript (via @yoke/sdk) to the Rust kernel. The embedded Deno worker communicates over a unix socket using newline-delimited JSON-RPC.

TypeScript → Rust (host ops)

User code calls SDK methods; the worker forwards to Rust:

OpPurpose
stream_appendPublish event to global stream (Zod-validated in worker)
instances_createCreate actor instance with queue policy + filter
instances_destroyTear down instance (onDestroy, delete rows)
sqlite_execActor SQLite query with bound params
state_getRead typed state document + version
state_setOverwrite typed state
state_casCompare-and-swap with expected version
portal_callInvoke portal interface method
schedule_upsertCreate/replace keyed schedule
schedule_cancelCancel schedule by instance + key
schedule_listList schedules for instance
conversation_create_actorCreate chat identity
conversation_createCreate conversation
conversation_add_participantAdd participant stint
conversation_leave_participantEnd stint
conversation_post_messageInsert message + stream append
conversation_create_branchSoft fork
conversation_list_messagesTranscript read
conversation_list_participantsParticipant list
conversation_create_blobRegister blob metadata
conversation_get_blobFetch blob metadata

The atomic state op is state_cas, not state_update. ctx.state.update() in the SDK wraps state_cas with retry logic.

Rust → TypeScript (worker RPC)

RPCPurpose
eval_filterFunction filter check on fan-out slow path
eval_queue_selectCustom queue selector over pending events
dispatch_processRun actor process(ctx, event); dequeue on success
get_actor_specsQueue policy, default state, filter hints for boot
portal_invokeExecute portal interface method from portal_call

Execution flow

Rust scheduler
  → dispatch_process(instanceId, event)
  → Deno: await definition.process(ctx, event)
  → ctx.append() → stream_append → Postgres → fan-out
  → ctx.portals.* → portal_call → portal_invoke
  → return
  → Rust: dequeue on success, requeue on throw

state_cas detail

// Worker RPC (simplified)
const updated = await callHost("state_cas", {
  storeId: sqliteStoreId,
  expectedVersion: record.version,
  state: newData,
});

The runtime implements version check in a SQLite transaction. Conflict → worker retries ctx.state.update() up to MAX_STATE_RETRIES (32).

Custom queue selection

Rust: list_pending(instance, group)
  → eval_queue_select { events, config, definitionName }
  → Deno: queueSelectFromConfig(config)(events) or inline select
  → return event_id
  → Rust: claim_next(instance, group, policy, event_id)

Validation boundary

Validated in worker (Deno)Validated in Rust
Event payload (Zod)Instance config schema
Append input shapeSQL params binding
Tool parametersTenant scoping

Rust serializes payloads; it does not interpret business logic.

System endpoints (Rust HTTP, not ops)

EndpointPurpose
GET /healthok
GET /metricsPrometheus text

Type flow

User TS (defineRuntime)
  → loaded by DenoHost on start
  → definitions registered in kernel
  → instances via instances_create
  → fan-out → queues
  → dispatch_process → process(ctx, event)
  → stream_append → Fanout

On this page