中文 | English
A third-party Web frontend for OpenCode.
This project is entirely built with AI-assisted programming (Vibe Coding) — from the first line of code to the final release, all features were developed through conversations with AI.
Disclaimer: This project is for learning and communication purposes only. We are not responsible for any issues arising from the use of this project. The project is in its early stages and may contain bugs and instabilities.
- Full Chat Interface — Message streaming, Markdown rendering, code highlighting (Shiki)
- Built-in Terminal — Web terminal based on xterm.js with WebGL rendering
- File Browsing & Diff — Browse workspace files, multi-file diff comparison
- Theme System — 3 built-in themes (Eucalyptus / Claude / Breeze), light/dark mode toggle and custom CSS
- PWA Support — Installable as a desktop/mobile app
- Mobile Friendly — Safe area handling, touch optimization, responsive layout
- Browser Notifications — Push notifications when AI replies are complete
- @ Mentions & / Slash Commands — Quickly reference files and execute commands in conversations
- Custom Shortcuts — Configurable key bindings
- Docker Deployment — Containerized frontend and backend separation, ready to use out of the box
- Desktop App — Native client based on Tauri (macOS / Linux / Windows)
- Dynamic Port Routing — Auto-discovery of dev services inside containers, generates preview links
| Category | Technology |
|---|---|
| Framework | React 19 + TypeScript |
| Build | Vite 7 |
| Styling | Tailwind CSS v4 |
| Code Highlighting | Shiki |
| Terminal | xterm.js (WebGL) |
| Markdown | react-markdown + remark-gfm |
| Desktop | Tauri 2 |
| Deployment | Docker (Caddy + Python Router) |
No deployment needed — after starting the OpenCode backend locally, access the hosted frontend directly:
opencode serve --cors "https://lehhair.github.io"Then open https://lehhair.github.io/OpenCodeUI/
For scenarios where opencode serve is already running, you only need a frontend UI container to connect to the existing backend.
git clone https://github.com/lehhair/OpenCodeUI.git
cd OpenCodeUI
# Start (connects to host's opencode serve :4096 by default)
docker compose -f docker-compose.standalone.yml up -dVisit http://localhost:3000.
Connect to a remote backend:
BACKEND_URL=your-server.com:4096 PORT=8080 docker compose -f docker-compose.standalone.yml up -d| Environment Variable | Default | Description |
|---|---|---|
BACKEND_URL |
host.docker.internal:4096 |
opencode serve address (without protocol prefix) |
PORT |
3000 |
Frontend listening port |
The deployment consists of three services, unified through the Gateway:
| Service | Port | Description |
|---|---|---|
| Gateway | 6658 (GATEWAY_PORT) |
Unified entry point, reverse proxy for all requests |
| Gateway | 6659 (PREVIEW_PORT) |
Dev service preview |
| Frontend | 3000 (internal) | Static frontend |
| Backend | 4096 (internal) | OpenCode API |
| Router | 7070 (internal) | Dynamic port routing (built into Gateway) |
Requests on port 6658 are forwarded according to these rules:
| Path | Target | Description |
|---|---|---|
/api/* |
Backend :4096 | OpenCode API, supports SSE |
/routes |
Router :7070 | Dynamic route management panel |
/preview/* |
Router :7070 | Preview port switching API |
| Other | Frontend :3000 | Frontend static assets |
Port 6659 is used to access dev services inside the container. The Router automatically scans ports 3000-9999 and generates preview links via the /p/{token}/ path.
git clone https://github.com/lehhair/OpenCodeUI.git
cd OpenCodeUI
# Copy and edit environment variables, fill in at least one LLM API Key
cp .env.example .env
# Start
docker compose up -dVisit http://localhost:6658.
The backend now retains only one core persistent volume: opencode-home (mounted at /root).
The backend entry script automatically verifies and supplements opencode / mise on startup to prevent toolchain loss after container rebuilds.
- OpenCode configuration and session cache
- npm / cargo / pip and other user-space caches
- Node / Python multi-version runtimes installed via
mise
All of the above will be preserved after container rebuilds — no need to split into multiple small volumes.
When upgrading from older versions, the original opencode-data/opencode-config/opencode-cache/opencode-npm/opencode-cargo/opencode-local/opencode-opt volumes become orphaned and can be manually cleaned up after confirming data has been migrated.
First time entering the backend container, you can install and persist runtime versions directly:
docker compose exec backend mise use -g node@22 python@3.12
docker compose exec backend node -v
docker compose exec backend python -VThe gateway still retains a separate volume opencode-router-data for storing dynamic routing state.
Edit the .env file with the key configuration:
# LLM API Key (fill in at least one)
ANTHROPIC_API_KEY=
OPENAI_API_KEY=
# Ports
GATEWAY_PORT=6658
PREVIEW_PORT=6659
# Working directory (mounted to /workspace in the container)
WORKSPACE=./workspace
# Must be set for public deployment
OPENCODE_SERVER_USERNAME=opencode
OPENCODE_SERVER_PASSWORD=your-strong-password
# Router service
ROUTER_SCAN_INTERVAL=5
ROUTER_PORT_RANGE=3000-9999
ROUTER_EXCLUDE_PORTS=4096Docker listens on 127.0.0.1 by default; public deployment requires a reverse proxy in front.
Nginx:
server {
listen 443 ssl;
server_name opencode.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:6658;
proxy_http_version 1.1;
# SSE (required)
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
# WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400s;
}
}
# Preview (optional, recommended to use a separate domain)
server {
listen 443 ssl;
server_name preview.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://127.0.0.1:6659;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_read_timeout 86400s;
}
}Caddy:
opencode.example.com {
reverse_proxy 127.0.0.1:6658 {
flush_interval -1
}
}
preview.example.com {
reverse_proxy 127.0.0.1:6659
}Important: SSE requires buffering to be disabled. Nginx needs
proxy_buffering off, Caddy needsflush_interval -1.
Requires a running OpenCode backend.
opencode serve
# In another terminal
git clone https://github.com/lehhair/OpenCodeUI.git
cd OpenCodeUI
npm install
npm run devVite starts at http://localhost:5173, /api is automatically proxied to http://127.0.0.1:4096.
Before opening a PR, run the same validation steps locally that CI uses:
npm run validateThis command runs TypeScript validation, ESLint, unit tests, and a production build in sequence.
If you prefer the hyphenated name, this alias is also available:
npm run type-checkGitHub Actions runs the same checks in the Build Validation workflow for every PR and every push to main.
For a real release, prefer the command below. It runs the full validation suite first, then updates versions and the changelog:
npm run release:prepare -- 0.2.0After it finishes, follow the printed git commit, git tag, and git push steps.
Download the installer from Releases, or build locally:
npm install
npm run tauri buildsrc/
├── api/ # API request wrappers
├── components/ # Common components (Terminal, DiffView, etc.)
├── features/ # Business modules
│ ├── chat/ # Chat interface
│ ├── message/ # Message rendering
│ ├── sessions/ # Session management
│ ├── settings/ # Settings panel
│ ├── mention/ # @ mentions
│ └── slash-command/ # Slash commands
├── hooks/ # Custom Hooks
├── store/ # State management
├── themes/ # Theme presets
└── utils/ # Utility functions
src-tauri/ # Tauri desktop app (Rust)
docker/ # Docker config (Gateway / Frontend / Backend)
Some UI styles are inspired by the Claude interface design.
This project is driven by Vibe Coding. If you're also interested in AI-assisted programming, feel free to connect.