Cloudflare DO Minimal App
Build the smallest Cloudflare Durable Object app that uses the agentOS facade, symbolic LLM material, and one tool.
What You Build
Section titled “What You Build”One Worker module exporting an AgentDO class and a fetch handler. The DO
uses defineAgentDO, one echo tool, one symbolic endpoint, one symbolic
credential, and one openAIChat route.
Prerequisites
Section titled “Prerequisites”-
Install the app-facing packages and peers:
Terminal window bun add @agent-os/backend-cloudflare-do @agent-os/kernel effectbun add -d typescript @cloudflare/workers-types -
Define one tool:
import { defineTool } from "@agent-os/kernel";import { Schema } from "effect";const echo = defineTool({name: "echo",description: "Return the supplied text.",args: Schema.Struct({ text: Schema.String }),authority: "tutorial.local",admit: () => ({ ok: true }),execute: ({ text }) => ({ text }),}); -
Define the Durable Object facade:
import {credential,defineAgentDO,endpoint,openAIChat,type CloudflareAgentEnv,} from "@agent-os/backend-cloudflare-do";interface MaterialEnv extends CloudflareAgentEnv {readonly OPENAI_BASE_URL: string;readonly OPENAI_API_KEY: string;}export const AgentDO = defineAgentDO<MaterialEnv>({bindings: [endpoint<MaterialEnv>("llm").from((env) => env.OPENAI_BASE_URL),credential<MaterialEnv>("llm-key", { provider: "openai", purpose: "chat" }).from((env) => env.OPENAI_API_KEY,),],llms: {default: openAIChat({model: "gpt-4.1-mini",endpoint: "llm",credential: "llm-key",}),},tools: [echo],scopeRefForScope: (scope) => ({ kind: "conversation", scopeId: scope }),}); -
In the Worker
fetchhandler, choose a scope and call the DO stub:type AgentDOInstance = InstanceType<typeof AgentDO>;interface WorkerEnv extends MaterialEnv {readonly AGENT_DO: DurableObjectNamespace<AgentDOInstance>;}export default {async fetch(request: Request, env: WorkerEnv) {const id = env.AGENT_DO.idFromName("tutorial");const agent = env.AGENT_DO.get(id);return Response.json(await agent.submit({intent: "Echo hello",input: { text: "hello" },deliver: "tutorial.echo.ready",}),);},}; -
Add Cloudflare Durable Object binding and migration config before deploying. Keep provider URLs and secrets in environment bindings, not source code.
-
Run local checks before live deployment:
Terminal window bunx tsc -p tsconfig.jsonbun build src/worker.ts --target=browser --outdir dist --external cloudflare:workers
Checkpoint
Section titled “Checkpoint”The app typechecks and bundles while importing only public package entrypoints. This is a local proof. It does not prove a live Cloudflare deployment or a live LLM call.
Bind provider material with provider material binding, or install the same app-facing packages with internal npm consumer app.