Quickstart
This guide walks you through building a document improvement application. By the end, you’ll have an app where users type text, click a button, and watch AI-improved prose stream in word by word. You’ll also see real-time synchronization in action by opening multiple browser tabs that share the same state.Prerequisites
- Node.js 18 or later
- An API key from an LLM provider (OpenAI, Anthropic, etc.)
Create the Project
systems/ directory is where you write backend code. Each file exports a class that extends AgenticSystem, which the framework transforms into a Durable Object with WebSocket capabilities. The components/ directory contains React components that connect to these systems using the useSystem hook.
Configure Your API Key
Open.dev.vars and add your LLM provider’s API key:
.dev.vars file is automatically gitignored, keeping your credentials on your local machine during development. For production, you configure environment variables through Cloudflare’s dashboard.
The System
Opensystems/DocImprover.ts. This file contains the backend logic for your application:
content property stores whatever text the user types into the input field. The improved property uses stream<string>(), which creates a streaming primitive that can accumulate AI output token by token and broadcast each piece to connected clients. The status property tracks whether the system is processing a request, allowing the frontend to disable the button and show loading indicators.
Two methods are decorated with @action(), which marks them as callable from the client. The setContent method updates the input text whenever the user types. The improve method does the interesting work: it sets status to indicate processing has begun, clears any previous output with reset(), then iterates through the LLM’s response. Each time append(chunk) is called, the framework broadcasts that chunk to all connected clients, creating the word-by-word streaming effect.
The Component
Opencomponents/Editor.tsx. This React component connects to the system and renders the UI:
useSystem hook establishes a WebSocket connection to the backend system and returns both state and actions in a single object. When you call setContent(e.target.value) in the onChange handler, the framework serializes that value and sends it to the server. The server’s setContent method runs, updates this.content, and that update broadcasts back to all connected clients.
The hook knows the correct types because you pass DocImprover as a type parameter. This means your IDE provides autocomplete for state properties and action methods, and TypeScript catches type errors at compile time rather than runtime.
Run the Application
http://localhost:5173 in your browser. Type some rough text into the textarea and click Improve. You should see the improved text begin streaming into the output area token by token within a second or two. A blinking cursor appears during generation to indicate the model is still working.
Test Multi-Client Synchronization
Idyllic synchronizes state across multiple clients automatically. To see this in action:- Open a second browser tab at
http://localhost:5173 - Both tabs display identical content because they connect to the same system instance
- Type in one tab and watch the other update immediately
- Click Improve in one tab and both tabs stream the response simultaneously
Deploy to Production
Summary
| Your Code | What the Framework Does |
|---|---|
@field property = value | Syncs to all clients over WebSocket, persists to durable storage |
stream<T>() | Broadcasts incremental updates as they arrive |
@action() | Exposes the method as a typed RPC endpoint |
useSystem<T>() | Connects to the system with full TypeScript types |