Get Started

Basic Usage

Scaffold the standard starter, write a Flow, and inspect it in the Console.

Scaffold an app

Terminal
bunx create-oke@latest my-app
cd my-app
oke dev

The app runs on :6530, the Console on :6533, and MCP on :6535.

Mental model

Every backend behavior has one shape:

on(Trigger) → Effects
  1. Trigger — how work starts (http.post, every("10m"), a signal, …)
  2. Contractsin, out, and typed errors
  3. do — the body; world access goes only through fx
  4. Effects — inferred from the fx calls

Your first Flow

The standard starter includes a health Flow:

import { on, flow, http } from "okengine";
import { z } from "zod";

export const health = on(
  http.get("/health"),
  flow({
    out: z.object({ ok: z.literal(true) }),
    do: () => ({ ok: true as const }),
  }),
);

Open src/flows/main/index.ts, change the route or output, and save. The app and Console update together from the same Manifest.

The invariant

All reads, writes, emits, sends, and external calls belong behind fx. This is what makes effects inspectable and tests deterministic.

Wire the app

The starter adopts the module in src/app.ts:

import { oke } from "okengine";
import * as main from "./flows/main";

export const app = oke({ name: "my-app" }).adopt({ main });
export type App = typeof app;

The namespace becomes the typed-client namespace and each exported Flow becomes a method.

Typed client

import { createClient } from "okengine/client";
import type { App } from "../src/app";

const api = createClient<App>("http://localhost:6530");
const { data, error } = await api.main.health({});

data and error are inferred from the Flow contracts; no separate client schema or code-generation project is required.

Test

Use createTestApp to boot the same app with test drivers:

import { expect, test } from "bun:test";
import { createTestApp } from "okengine/test";
import { app } from "../src/app";

test("health", async () => {
  const t = await createTestApp(app);
  const { data, error } = await t.api.main.health({});
  expect(error).toBeNull();
  expect(data).toEqual({ ok: true });
  await app.stop();
});
Terminal
bun test

Next

On this page