opencode-bridge
$
npx mdskill add different-ai/openwork/opencode-bridgeEnables communication between OpenWork UI and OpenCode runtime for seamless interaction
- Solves the problem of integrating UI prompts with code execution environments
- Uses CLI invocation, SQLite databases, and MCP for real-time communication
- Routes prompts to OpenCode, tracks sessions, and streams responses
- Returns structured JSON results and updates session state in real time
SKILL.md
.github/skills/opencode-bridgeView on GitHub ↗
---
name: opencode-bridge
description: Bridge between OpenWork UI and OpenCode runtime
---
## Overview
OpenWork communicates with OpenCode via three mechanisms:
1. **CLI invocation**: Spawn `opencode` with prompts and get JSON responses.
2. **Database access**: Read OpenCode's SQLite database for sessions and messages.
3. **MCP bridge**: Real-time bidirectional communication for streaming and permissions.
## CLI Invocation
### Non-interactive mode
```bash
opencode -p "your prompt" -f json -q
```
Returns JSON with the response content.
### Flags
| Flag | Description |
|------|-------------|
| `-p` | Prompt to execute |
| `-f` | Output format (`text`, `json`) |
| `-q` | Quiet mode (no spinner) |
| `-c` | Working directory |
| `-d` | Debug mode |
### Example response
```json
{
"content": "Here is the result...",
"session_id": "abc123"
}
```
## Database Access
### Location
```
~/.opencode/opencode.db
```
Or project-local:
```
.opencode/opencode.db
```
### Schema (key tables)
#### sessions
```sql
CREATE TABLE sessions (
id TEXT PRIMARY KEY,
parent_session_id TEXT,
title TEXT,
message_count INTEGER,
prompt_tokens INTEGER,
completion_tokens INTEGER,
summary_message_id TEXT,
cost REAL,
created_at INTEGER,
updated_at INTEGER
);
```
#### messages
```sql
CREATE TABLE messages (
id TEXT PRIMARY KEY,
session_id TEXT,
role TEXT, -- 'user', 'assistant', 'tool'
parts TEXT, -- JSON array of content parts
model TEXT,
created_at INTEGER,
updated_at INTEGER
);
```
### Querying from Rust (Tauri)
```rust
use tauri_plugin_sql::{Migration, MigrationKind};
#[tauri::command]
async fn list_sessions(db: tauri::State<'_, Database>) -> Result<Vec<Session>, String> {
let sessions = sqlx::query_as::<_, Session>(
"SELECT * FROM sessions ORDER BY updated_at DESC"
)
.fetch_all(&db.pool)
.await
.map_err(|e| e.to_string())?;
Ok(sessions)
}
```
### Querying from SolidJS
```tsx
import Database from "@tauri-apps/plugin-sql";
const db = await Database.load("sqlite:~/.opencode/opencode.db");
const sessions = await db.select<Session[]>(
"SELECT * FROM sessions ORDER BY updated_at DESC"
);
```
## MCP Bridge (Advanced)
OpenWork can register as an MCP server that OpenCode connects to.
### Configuration (opencode.json)
```json
{
"mcpServers": {
"openwork": {
"type": "stdio",
"command": "openwork-mcp-bridge"
}
}
}
```
### Use cases
- Real-time permission prompts surfaced in OpenWork UI.
- Streaming progress updates.
- Custom tools exposed from OpenWork (e.g., native file picker).
## Message Content Parts
Messages contain a `parts` JSON array with different content types:
### TextContent
```json
{ "type": "text", "text": "Hello world" }
```
### ToolCall
```json
{
"type": "tool_call",
"id": "call_123",
"name": "bash",
"input": "{\"command\": \"ls\"}"
}
```
### ToolResult
```json
{
"type": "tool_result",
"tool_call_id": "call_123",
"content": "file1.txt\nfile2.txt",
"is_error": false
}
```
### Finish
```json
{
"type": "finish",
"reason": "end_turn",
"time": 1704067200
}
```
## Common Gotchas
- Database is SQLite; use read-only access to avoid conflicts with running OpenCode.
- Message parts are JSON-encoded strings; parse them in the UI.
- Session IDs are UUIDs; tool call IDs are also UUIDs.
- Cost is in USD; tokens are raw counts.
## First-Time Setup
### Verify OpenCode is installed
```bash
which opencode
opencode --version
```
### Verify database exists
```bash
ls ~/.opencode/opencode.db
```
### Test CLI invocation
```bash
opencode -p "Hello" -f json -q
```
More from different-ai/openwork
- browser-setup-devtoolsGuide users through browser automation setup using Chrome DevTools MCP only. Use when the user asks to set up browser automation, Chrome DevTools MCP, browser MCP, or runs the browser-setup command.
- daytona-electron-testTest the real Electron app on Daytona: create sandbox, start services, connect via CDP, create workspaces, drive sessions, and verify settings. Use when the user says 'test on Daytona', 'run the app on Daytona', 'Daytona dry run', 'test Electron remotely', or 'reproduce on Daytona'.
- get-startedGuide users through the get started setup and Chrome DevTools demo.
- opencode-mirrorMaintain the local OpenCode mirror for self-reference
- opencode-primitivesReference OpenCode docs when implementing skills, plugins, MCPs, or config-driven behavior.
- openwork-coreCore context and guardrails for OpenWork native app
- openwork-debugDebug OpenWork sidecars, config, and audit trail
- openwork-orchestrator-npm-publish|
- run-evalsRun OpenWork UI evals on a Daytona sandbox or local Electron instance. Handles sandbox creation, service startup, and eval execution via CDP browser tools.
- shadcnManages shadcn components and projects — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset".