Initial OpenWork app

This commit is contained in:
Benjamin Shafii
2026-01-13 17:39:22 -08:00
commit d035b85905
42 changed files with 14932 additions and 0 deletions

View File

@@ -0,0 +1,192 @@
---
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
```

View File

@@ -0,0 +1,23 @@
---
name: opencode-mirror
description: Maintain the local OpenCode mirror for self-reference
---
## Quick Usage (Already Configured)
### Update mirror
```bash
git -C vendor/opencode pull --ff-only
```
## Common Gotchas
- Keep the mirror gitignored; never commit `vendor/opencode`.
- Use `--ff-only` to avoid merge commits in the mirror.
## First-Time Setup (If Not Configured)
### Clone mirror
```bash
git clone https://github.com/opencode-ai/opencode vendor/opencode
```

View File

@@ -0,0 +1,85 @@
---
name: openwork-core
description: Core context and guardrails for OpenWork native app
---
## Quick Usage (Already Configured)
### Orientation
- Read `AGENTS.md` and `design-prd.md` before changing behavior.
- Ensure `vendor/opencode` exists for self-reference.
- Use the `tauri-solidjs` skill for stack-specific guidance.
### Update the OpenCode mirror
```bash
git -C vendor/opencode pull --ff-only
```
### Development workflow
```bash
pnpm tauri dev # Desktop development
pnpm tauri ios dev # iOS development
pnpm tauri android dev # Android development
```
## OpenCode Integration
### Spawn OpenCode CLI
```bash
opencode -p "your prompt" -f json -q
```
### Read OpenCode database
```
~/.opencode/opencode.db # SQLite database
```
### Key tables
- `sessions` — Task runs
- `messages` — Chat messages and tool calls
- `history` — File change tracking
## Common Gotchas
- OpenWork must stay within OpenCode's tool surface; avoid inventing new capabilities.
- Always expose plans, permissions, and progress for non-technical users.
- Use Tauri commands for all system access (file, shell, database).
- Keep UI at 60fps; avoid blocking the main thread.
- Mobile builds require platform-specific setup (Xcode, Android Studio).
## UI Principles
- **Slick and fluid**: animations, transitions, micro-interactions.
- **Mobile-first**: touch targets, gestures, adaptive layouts.
- **Transparency**: show plans, steps, and tool calls.
- **Progressive disclosure**: hide advanced controls until needed.
## First-Time Setup (If Not Configured)
### Clone the OpenCode mirror
```bash
git clone https://github.com/opencode-ai/opencode vendor/opencode
```
### Initialize Tauri project
```bash
pnpm create tauri-app . --template solid-ts
```
### Add mobile targets
```bash
pnpm tauri ios init
pnpm tauri android init
```
## Common Gotchas
- OpenWork must stay within OpenCodes tool surface; avoid inventing new capabilities.
- Always expose plans, permissions, and progress for non-technical users.
## First-Time Setup (If Not Configured)
### Clone the OpenCode mirror
```bash
git clone https://github.com/opencode-ai/opencode vendor/opencode
```

View File

@@ -0,0 +1,156 @@
---
name: tauri-solidjs
description: Tauri 2.x + SolidJS stack for OpenWork native app
---
## Quick Usage (Already Configured)
### Create new Tauri + SolidJS project
```bash
pnpm create tauri-app openwork --template solid-ts
```
### Development
```bash
pnpm tauri dev
```
### Build for production
```bash
pnpm tauri build
```
### Build for mobile
```bash
# iOS
pnpm tauri ios dev
pnpm tauri ios build
# Android
pnpm tauri android dev
pnpm tauri android build
```
## Project Structure
```
apps/openwork/
src-tauri/
src/
main.rs # Rust entry point
lib.rs # Tauri commands and state
Cargo.toml # Rust dependencies
tauri.conf.json # Tauri configuration
capabilities/ # Permission capabilities
src/
App.tsx # SolidJS root component
index.tsx # Entry point
components/ # UI components
stores/ # Solid stores for state
lib/ # Utilities and OpenCode bridge
index.html # HTML template
package.json # Frontend dependencies
vite.config.ts # Vite configuration
```
## Key Dependencies
### Frontend (package.json)
```json
{
"dependencies": {
"solid-js": "^1.8.0",
"@tauri-apps/api": "^2.0.0",
"@tauri-apps/plugin-shell": "^2.0.0",
"@tauri-apps/plugin-fs": "^2.0.0",
"@tauri-apps/plugin-sql": "^2.0.0"
},
"devDependencies": {
"@tauri-apps/cli": "^2.0.0",
"vite": "^5.0.0",
"vite-plugin-solid": "^2.8.0",
"tailwindcss": "^3.4.0"
}
}
```
### Backend (Cargo.toml)
```toml
[dependencies]
tauri = { version = "2", features = ["shell-open"] }
tauri-plugin-shell = "2"
tauri-plugin-fs = "2"
tauri-plugin-sql = { version = "2", features = ["sqlite"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
```
## Tauri Commands (Rust -> JS)
```rust
// src-tauri/src/lib.rs
use tauri::Manager;
#[tauri::command]
async fn spawn_opencode(prompt: String) -> Result<String, String> {
use std::process::Command;
let output = Command::new("opencode")
.args(["-p", &prompt, "-f", "json", "-q"])
.output()
.map_err(|e| e.to_string())?;
String::from_utf8(output.stdout)
.map_err(|e| e.to_string())
}
#[tauri::command]
fn get_opencode_db_path() -> String {
// Return path to .opencode/opencode.db
dirs::home_dir()
.map(|p| p.join(".opencode/opencode.db").to_string_lossy().to_string())
.unwrap_or_default()
}
```
## Invoking Commands from SolidJS
```tsx
import { invoke } from "@tauri-apps/api/core";
async function runTask(prompt: string) {
const result = await invoke<string>("spawn_opencode", { prompt });
return JSON.parse(result);
}
```
## Common Gotchas
- Tauri 2.x uses `@tauri-apps/api/core` instead of `@tauri-apps/api/tauri`.
- Mobile builds require Xcode (iOS) or Android Studio (Android).
- File access requires `tauri-plugin-fs` and capability configuration.
- SQLite access requires `tauri-plugin-sql`.
## First-Time Setup (If Not Configured)
### Install Tauri CLI
```bash
pnpm add -D @tauri-apps/cli
```
### Initialize Tauri in existing project
```bash
pnpm tauri init
```
### Add mobile targets
```bash
pnpm tauri ios init
pnpm tauri android init
```
## References
- [Tauri 2.0 Docs](https://v2.tauri.app/)
- [SolidJS Docs](https://www.solidjs.com/)
- [Tauri Mobile](https://v2.tauri.app/start/prerequisites/#mobile)