Deployment
Kuralle agents run anywhere that runs Node.js, Bun, or Cloudflare Workers. The runtime has no external process dependencies — serve it with whatever HTTP framework you prefer.
Hono (Node.js or Bun)
Section titled “Hono (Node.js or Bun)”@kuralle-agents/hono-server mounts a full set of endpoints onto a Hono app with one call.
npm install @kuralle-agents/hono-server hono @hono/node-server @hono/node-wsimport { Hono } from 'hono';import { serve } from '@hono/node-server';import { createNodeWebSocket } from '@hono/node-ws';import { createRuntime, defineAgent } from '@kuralle-agents/core';import { createKuralleChatRouter } from '@kuralle-agents/hono-server';import { openai } from '@ai-sdk/openai';
const agent = defineAgent({ id: 'support', instructions: 'You are a helpful support agent.', model: openai('gpt-4o-mini'),});
const runtime = createRuntime({ agents: [agent], defaultAgentId: 'support' });
const app = new Hono();const { upgradeWebSocket, injectWebSocket } = createNodeWebSocket({ app });app.route('/', createKuralleChatRouter({ runtime, upgradeWebSocket }));
const server = serve({ fetch: app.fetch, port: 3000 });injectWebSocket(server);Bun doesn’t need @hono/node-server or createNodeWebSocket. Use Bun’s built-in WebSocket upgrade instead:
import { upgradeWebSocket } from 'hono/bun';
const app = new Hono();app.route('/', createKuralleChatRouter({ runtime, upgradeWebSocket }));
export default app;Endpoints
Section titled “Endpoints”createKuralleChatRouter mounts these routes:
| Method | Path | Description |
|---|---|---|
| POST | /api/chat | Single-turn JSON response |
| POST | /api/chat/sse | SSE streaming response |
| POST | /api/chat/stream | Chunked text stream |
| GET | /agents/chat/:sessionId | WebSocket widget endpoint |
| GET | /ws/:sessionId | WebSocket turn endpoint |
| GET | /api/session/:id | Fetch session |
| DELETE | /api/session/:id | Delete session |
| GET | /health | Health check |
Cloudflare Workers
Section titled “Cloudflare Workers”@kuralle-agents/cf-agent runs Kuralle agents on Cloudflare Workers with Durable Objects. Subclass KuralleAgent, implement two methods, and Cloudflare handles SQLite persistence, multi-client sync, and stream resumability.
npm install @kuralle-agents/cf-agentimport { KuralleAgent } from '@kuralle-agents/cf-agent';import { defineAgent } from '@kuralle-agents/core';import { createOpenAI } from '@ai-sdk/openai';
interface Env { OPENAI_API_KEY: string;}
export class SupportAgent extends KuralleAgent<Env> { protected getAgents() { const openai = createOpenAI({ apiKey: this.env.OPENAI_API_KEY }); return [ defineAgent({ id: 'support', instructions: 'You are a helpful support agent.', model: openai('gpt-4o-mini'), }), ]; }
protected getDefaultAgentId() { return 'support'; }}
export default SupportAgent;Declare the Durable Object in wrangler.toml:
[[durable_objects.bindings]]name = "SUPPORT_AGENT"class_name = "SupportAgent"
[[migrations]]tag = "v1"new_sqlite_classes = ["SupportAgent"]Flows, tools, and structured routing all work identically on Cloudflare — the same defineAgent primitive, no runtime differences.
HTTP streaming
Section titled “HTTP streaming”Use handle.toResponseStream('sse') to pipe a TurnHandle directly to an HTTP response without createKuralleChatRouter:
app.post('/chat', async (c) => { const { input, sessionId } = await c.req.json(); const handle = runtime.run({ input, sessionId }); return handle.toResponseStream('sse');});createKuralleChatRouter uses this internally and also wires sessions, WebSocket, and the full endpoint set.