Yoke

Getting started

Install Yoke and serve your first runtime.

Requirements

  • Bun >= 1.x — Yoke is TypeScript on Bun. No Node, no npm, no Rust.

Installation

bun add yoke @yoke/provider-openai

This monorepo ships provider packages as workspaces:

  • yoke — the framework and all interfaces (packages/core)
  • @yoke/provider-openai — OpenAI via the AI SDK
  • @yoke/provider-openrouter — OpenRouter via @ai-sdk/openai-compatible
  • @yoke/provider-mock — deterministic, scripted responses for tests

Your first runtime

Create a file main.ts:

import { Runtime, inferenceStack, userMessage } from "yoke";
import { mockProvider } from "@yoke/provider-mock";

const runtime = Runtime({
  inference: inferenceStack({
    providers: [mockProvider()],
    models: [{ id: "mock", provider: "mock", model: "mock" }],
  }),
}).agent({
  name: "assistant",
  initialState: {},
  async run(ctx, input) {
    const reply = await ctx.inference.chat({
      model: "mock",
      messages: [userMessage(input.text)],
    });
    return { answer: reply.message.content };
  },
});

await runtime.serve({ port: 3000 });

Run it:

bun run main.ts

The runtime boots, subscribes actors, and starts listening. You can now publish an event and watch the actor forward it to the agent:

curl -X POST http://localhost:3000/api/events \
  -H 'content-type: application/json' \
  -d '{
    "topic": "messages.incoming",
    "type": "user.message",
    "source": "curl",
    "payload": { "text": "hello from curl" }
  }'

What just happened?

  1. Runtime(...) created the app and wired an InferenceStack with one mock model.
  2. .agent(...) registered the assistant agent — now reachable as the typed ctx.agents.assistant.
  3. .actor(...) registered message-forwarder, subscribed to the messages.incoming topic, and forwards every matching event to the agent.
  4. runtime.serve({ port }) started everything, Express-style.

Development

bun test            # run the test suite
bun run typecheck   # tsc --noEmit, including type-level assertions

Typed from prior registrations

Runtime() is a type-accumulating builder. Each .agent(...), .tool(...), or .toolchain(...) call extends the type of ctx, so inside .actor(...) you get a ctx whose agents / tools are exactly what you registered — with their input and output types. Reference an agent you never registered and it's a compile-time error.

Next up: the runtime in depth.

On this page