A modern web interface for OpenCode - an AI coding assistant that runs locally. Built with React 19, deployed to Cloudflare Workers edge network.
OpenCode Web is a chat-based web UI for interacting with OpenCode, providing:
- 💬 Real-time streaming responses via Server-Sent Events (SSE)
- 🔄 Live message updates as the AI types
- 🎨 Rich message rendering with markdown, code blocks, reasoning, and tool calls
- 📱 Mobile-first responsive design with drawer navigation
- 🌓 Dark mode support with system preference detection
- 🔌 Direct connection to your local OpenCode server
The app connects to OpenCode running on your machine and provides a polished chat interface for code assistance, file editing, and project management.
- React 19 - Modern UI library with cutting-edge features
- Vite - Lightning-fast build tooling and dev server
- TanStack Query - Powerful data fetching and caching
- Tailwind CSS v4 - Utility-first CSS framework
- shadcn/ui - High-quality, accessible component library
- AI Elements - Pre-built AI chat UI components
- Storybook 9 - Component development and documentation
- Hono - Ultralight, modern backend framework
- Cloudflare Workers - Edge computing platform for global deployment
- OpenCode SDK - Official TypeScript SDK for OpenCode API
- Server-Sent Events (SSE) - Real-time message streaming from OpenCode
- React Query Cache - In-place message updates for instant UI feedback
- Type-safe event handling - Fully typed SSE events from OpenCode SDK
Three separate TypeScript contexts:
- React App (
src/react-app/) - Client-side chat interface - Worker (
src/worker/) - Cloudflare Workers backend (Hono API + SSE proxy) - Shared Code (
src/components/,src/lib/,src/hooks/) - Reusable UI and utilities
The Worker serves the React app as static assets and proxies API requests to your local OpenCode server.
OpenCode Server → Worker (SSE Proxy) → Browser (EventSource) → React Query Cache → UI
- OpenCode emits events -
message.updated,message.part.updated,session.idle - Worker proxies SSE - Forwards events from OpenCode to browser
- Browser receives events -
useOpencodeEventshook manages EventSource connection - Cache updates in-place - Pure functions update React Query cache directly
- UI re-renders - React automatically updates when cache changes
All types derived from OpenCode SDK:
Message,Part,Eventtypes from@opencode-ai/sdk/client- Custom
MessageWithPartsinterface matching API responses - Type guards for safe event handling:
isMessageUpdatedEvent,isTextPart, etc. - Zero
anytypes in production code
Path Aliases: All imports use @/* → src/:
import { Button } from "@/components/ui/button"
import { useOpencodeEvents } from "@/hooks/use-opencode-events"
import { upsertMessage } from "@/lib/message-cache-utils"- OpenCode - Install and run OpenCode locally: opencode.ai
- pnpm - Package manager:
npm install -g pnpm
pnpm installStart the development server:
pnpm devYour app will be available at http://localhost:7777.
By default, local development connects to the OpenCode server running on your machine (localhost:4096). The pnpm dev command automatically starts the OpenCode CLI for you.
If you want to run OpenCode inside a sandboxed container instead:
- Open the Settings drawer in the web UI
- Create a new Workspace
- The system will spin up a Cloudflare Container with its own OpenCode instance
- Select the new workspace to route all requests to the containerized OpenCode
This is useful for testing in an isolated environment that mirrors the production deployment.
Start Storybook for isolated component development:
pnpm storybookStorybook will be available at http://localhost:6006.
src/
├── react-app/ # React application entry and pages
│ ├── pages/ # Page components (ChatPage, etc.)
│ └── *.test.ts # Test files
├── components/ # Reusable UI components
│ ├── ui/ # shadcn/ui components
│ ├── ai-elements/ # AI chat UI components
│ └── chat/ # Chat-specific components
├── hooks/ # React hooks
│ ├── use-opencode.ts # API queries and mutations
│ ├── use-opencode-events.ts # SSE connection management
│ ├── use-streaming-updates.ts # Real-time cache updates
│ └── opencode-event-utils.ts # Event parsing utilities
├── lib/ # Utility functions
│ └── message-cache-utils.ts # Pure cache update functions
├── types/ # TypeScript types
│ ├── opencode-events.ts # SSE event types
│ ├── opencode-messages.ts # Message types
│ └── opencode-schemas.ts # Zod schemas
├── worker/ # Cloudflare Workers backend
│ └── index.ts # Hono API + SSE proxy
└── stories/ # Storybook stories
Run all tests:
pnpm testRun individual test suites:
pnpm test:worker # Backend/API tests
pnpm test:ui # React component unit tests (41 tests)
pnpm test:storybook # Storybook visual/interaction testspnpm checkRuns TypeScript compiler in dry-run mode across all contexts.
pnpm lint- Check existing components - Review
src/components/and Storybook - Search AI Elements - Check aielements.com for chat UI components
- Search shadcn/ui - Check ui.shadcn.com for general components
- Add component:
pnpm dlx shadcn@latest add <component> pnpm dlx ai-elements@latest add <component>
- Create story - Always add Storybook story for new components
- Write tests - Add tests to
src/react-app/ - Run tests -
pnpm test:uiandpnpm test:storybook
Build for production:
pnpm build:productionDeploy to Cloudflare Workers:
pnpm deploy