A clean, fast web dashboard for browsing, searching, and continuing your OpenCode chat sessions.
- Live Search — Instantly filter sessions by title, preview, or ID
- Session List — See title, date, message count, and preview at a glance
- New Session — Start a fresh OpenCode session in a terminal with one click
- Chat-Style Layout — Messages rendered as bubbles (user / assistant), not raw markdown files
- Rich Message Types — Text, reasoning/thinking blocks, and tool calls with expandable input/output
- Markdown Rendering — Full markdown support with tables, lists, blockquotes, and syntax-highlighted code blocks
- Copy Code — Hover any code block to copy with one click
- Auto-Scroll — Jumps to the latest message when loading or sending
- Send Messages — Type and send directly from the browser; spawns OpenCode in the background
- Live Polling — Automatically refreshes the chat every 3 seconds to show the AI's response
- Visual Feedback — Skeleton loaders while fetching, temporary message preview while sending
- Open in OpenCode — Launch any session in
gnome-terminalwith the OpenCode CLI - Working Directory Aware — Opens in the session's original directory
- Node.js 18+
- OpenCode CLI installed and on your
$PATH gnome-terminal(for the "Open in Terminal" feature)- Linux (tested on Ubuntu; macOS/Windows may need tweaks)
git clone https://github.com/dalpat/opencode-ui.git
cd opencode-ui
npm installStart the server:
npm startOpen http://localhost:3457 in your browser.
| Variable | Default | Description |
|---|---|---|
PORT |
3457 |
HTTP server port |
SESSIONS_DIR |
../opencode-sessions |
Directory where exported .md session files are stored |
- Backend: Express.js with a local read-optimized SQLite cache (
better-sqlite3) - Frontend: Vanilla HTML/CSS/JS — no build step, no framework
- Styling: Custom CSS with Inter + JetBrains Mono fonts
- Markdown: Rendered client-side with
marked.js
The dashboard uses a local cache database for sub-millisecond queries instead of spawning a sqlite3 CLI process on every request.
┌─────────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐
│ opencode.db │────▶│ sync │────▶│ cache.db │────▶│ API │
│ (source) │ │ (startup │ │ (cache) │ │(Express│
│ │ │ + watch) │ │ │ │ │
└─────────────┘ └──────────┘ └──────────┘ └────────┘
│
▼
┌──────────┐
│ FTS5 │
│part_fts │
└──────────┘
Data flow:
- On startup, the server copies all data from
opencode.dbintocache.db - A file watcher monitors
opencode.dbfor changes and incrementally syncs new data - All API endpoints read from
cache.dbviabetter-sqlite3native bindings - Full-text search uses the FTS5 virtual table
part_ftsfor instant results
The cache lives at ~/.local/share/opencode-dashboard/cache.db and mirrors opencode's core tables with denormalized fields and custom indexes.
| Table | Columns | Indexes / Notes |
|---|---|---|
session |
id, title, directory, parent_id, time_created, time_updated, model, agent |
idx_session_time_updated DESC (sidebar ordering) |
message |
id, session_id, time_created, data, role |
idx_message_session_time_created (session messages) |
part |
id, message_id, time_created, data, text_content |
idx_part_message_time_created (message parts) |
part_fts |
text_content |
FTS5 virtual table for full-text search |
_schema_version |
version, applied_at |
Tracks applied migrations |
sync_metadata |
table_name, last_sync_time |
Tracks incremental sync state |
FTS5 triggers (part_fts_insert, part_fts_delete, part_fts_update) keep the search index in sync automatically when rows are inserted, deleted, or updated in the part table.
If the cache becomes corrupt or you want to force a full refresh:
# Stop the server, then delete the cache file
rm ~/.local/share/opencode-dashboard/cache.db
# Restart the server — it will rebuild the cache from opencode.db on startup
npm startThe server also detects corruption automatically on startup and will rebuild the cache without manual intervention.
.
├── public/ # Static frontend
│ ├── index.html # App shell
│ ├── styles.css # Custom CSS design system
│ └── app.js # Vanilla JS app logic
├── server.js # Express API
├── session-persistence.js # Unified session persistence boundary (DB + filesystem)
├── process-runner.js # Terminal spawning and opencode process runner
├── export.js # CLI export script
├── session-persistence.test.js # Boundary tests
└── package.json
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/sessions |
List all sessions |
| GET | /api/session/:id |
Get session details with structured messages |
| POST | /api/session/:id/continue |
Append user message and run OpenCode |
| POST | /api/open/:id |
Open session in a new terminal |
| POST | /api/open-new |
Start a brand-new OpenCode session in a terminal |
MIT