mirror of
https://github.com/different-ai/openwork
synced 2026-04-25 17:15:34 +02:00
Initial OpenWork app
This commit is contained in:
192
.opencode/skill/opencode-bridge/SKILL.md
Normal file
192
.opencode/skill/opencode-bridge/SKILL.md
Normal 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
|
||||
```
|
||||
23
.opencode/skill/opencode-mirror/SKILL.md
Normal file
23
.opencode/skill/opencode-mirror/SKILL.md
Normal 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
|
||||
```
|
||||
85
.opencode/skill/openwork-core/SKILL.md
Normal file
85
.opencode/skill/openwork-core/SKILL.md
Normal 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 OpenCode’s 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
|
||||
```
|
||||
156
.opencode/skill/tauri-solidjs/SKILL.md
Normal file
156
.opencode/skill/tauri-solidjs/SKILL.md
Normal 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)
|
||||
Reference in New Issue
Block a user