- name
- open-design-ai-prototyping
- description
- Local-first AI design tool that turns coding agents into design engines with 31 skills, 129 design systems, and multi-format export
- triggers
- ["set up Open Design for AI-driven prototyping","create a web prototype using Open Design with Claude","generate a pitch deck with Open Design agent skills","use Open Design to build a SaaS landing page","configure Open Design with my coding agent CLI","export Open Design artifacts to HTML and PDF","integrate Open Design design systems into my project","run Open Design locally with sandboxed preview"]
# Open Design AI Prototyping
> Skill by [ara.so](https://ara.so) — Design Skills collection.
**Open Design** is a local-first, open-source alternative to Claude Design that transforms coding agents (Claude Code, Cursor, Codex, Gemini CLI, etc.) into design engines. It provides 31 composable skills, 129 brand-grade design systems, and a sandboxed preview environment with HTML/PDF/PPTX/MP4 export capabilities.
## What It Does
- **Agent-Native Design**: Detects 16 coding agent CLIs on your PATH and uses them as the design execution engine
- **Skill-Driven Workflow**: 31 built-in skills across web prototypes, decks, dashboards, mobile apps, marketing materials, and more
- **Design Systems Library**: 129 pre-built design systems (Linear, Stripe, Vercel, Airbnb, Tesla, Notion, etc.)
- **Multi-Format Export**: HTML, PDF, PPTX, MP4, ZIP, Markdown from a single artifact
- **Local-First**: SQLite persistence, on-disk project folders, no cloud lock-in
- **BYOK Support**: OpenAI/Anthropic/Azure/Google-compatible API proxy when no CLI is available
## Installation
### Quick Start (Local Development)
```bash
# Clone the repository
git clone https://github.com/nexu-io/open-design.git
cd open-design
# Install dependencies
pnpm install
# Start daemon + web interface
pnpm tools-dev
```
This boots:
- Daemon on `http://localhost:3001`
- Web UI on `http://localhost:3000`
- Auto-detects coding agents on your `PATH`
### Desktop App
Download pre-built installers from [open-design.ai](https://open-design.ai):
- macOS (Apple Silicon): `.dmg`
- Windows (x64): `.exe`
### Vercel Deployment (Web Layer Only)
```bash
# Deploy web interface (daemon runs separately)
vercel deploy
# Set environment variables in Vercel dashboard:
# - DAEMON_URL=your-daemon-endpoint
# - ANTHROPIC_API_KEY (optional, for BYOK)
# - OPENAI_API_KEY (optional, for BYOK)
```
## Project Structure
```
open-design/
├── apps/
│ ├── daemon/ # Core agent orchestration service
│ │ ├── src/
│ │ │ ├── prompts/ # Discovery, directions, critique prompts
│ │ │ ├── agents/ # CLI adapters (claude-code, cursor, etc.)
│ │ │ └── routes/ # API endpoints
│ │ └── package.json
│ ├── web/ # Next.js frontend
│ │ ├── app/
│ │ ├── components/
│ │ └── lib/
│ └── desktop/ # Electron wrapper (optional)
├── skills/ # 31 built-in skills
│ ├── web-prototype/
│ ├── guizang-ppt/ # Magazine-style decks
│ ├── saas-landing/
│ └── ...
├── design-systems/ # 129 design systems
│ ├── linear/
│ ├── stripe/
│ └── ...
└── prompt-templates/ # Media generation gallery (93 prompts)
```
## Key Commands
### Tools CLI
```bash
# Start all services
pnpm tools-dev
# Check system status
pnpm tools-dev status
# View daemon logs
pnpm tools-dev logs
# Inspect desktop (if Electron running)
pnpm tools-dev inspect desktop screenshot
# Stop all services
pnpm tools-dev stop
# Health check
pnpm tools-dev check
```
### Development
```bash
# Run daemon only
cd apps/daemon
pnpm dev
# Run web only
cd apps/web
pnpm dev
# Build for production
pnpm build
# Run tests
pnpm test
```
## Configuration
### Agent Detection
The daemon auto-detects CLIs on your `PATH`:
```typescript
// Supported agents (auto-detected)
const AGENTS = [
'claude-code', // Claude Code
'codex', // Codex CLI
'devin', // Devin for Terminal
'cursor-agent', // Cursor Agent
'gemini', // Gemini CLI
'opencode', // OpenCode
'qwen-code', // Qwen Code
'qoder', // Qoder CLI
'gh-copilot', // GitHub Copilot CLI
'hermes', // Hermes (ACP)
'kimi', // Kimi CLI (ACP)
'pi', // Pi (RPC)
'kiro', // Kiro CLI (ACP)
'kilo', // Kilo (ACP)
'mistral-vibe', // Mistral Vibe CLI
'deepseek-tui' // DeepSeek TUI
];
```
### BYOK Configuration (No CLI)
When no agent CLI is detected, configure API proxy:
```bash
# Environment variables
ANTHROPIC_API_KEY=your_key_here
OPENAI_API_KEY=your_key_here
AZURE_OPENAI_KEY=your_key_here
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com
GOOGLE_API_KEY=your_key_here
```
### Database
SQLite configuration (`.od/app.sqlite`):
```typescript
// apps/daemon/src/db/schema.ts
export const projects = sqliteTable('projects', {
id: text('id').primaryKey(),
name: text('name').notNull(),
skill: text('skill').notNull(),
designSystem: text('design_system'),
direction: text('direction'),
createdAt: integer('created_at', { mode: 'timestamp' }),
updatedAt: integer('updated_at', { mode: 'timestamp' })
});
export const conversations = sqliteTable('conversations', {
id: text('id').primaryKey(),
projectId: text('project_id').notNull().references(() => projects.id),
messages: text('messages', { mode: 'json' }),
artifacts: text('artifacts', { mode: 'json' })
});
```
## API Reference
### Daemon Endpoints
#### Start Agent Session
```typescript
// POST /api/agent/start
const response = await fetch('http://localhost:3001/api/agent/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
projectId: 'proj_123',
skill: 'web-prototype',
designSystem: 'linear',
direction: 'modern-minimal',
prompt: 'Create a SaaS dashboard with user analytics'
})
});
const { sessionId, status } = await response.json();
```
#### Stream Agent Response
```typescript
// GET /api/agent/stream/:sessionId (SSE)
const eventSource = new EventSource(
`http://localhost:3001/api/agent/stream/${sessionId}`
);
eventSource.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log(data); // { type: 'delta', content: '...' }
});
eventSource.addEventListener('artifact', (event) => {
const artifact = JSON.parse(event.data);
console.log(artifact); // { type: 'html', content: '...', title: '...' }
});
eventSource.addEventListener('tool_call', (event) => {
const tool = JSON.parse(event.data);
console.log(tool); // { name: 'Write', args: { path: '...', content: '...' } }
});
```
#### Export Artifacts
```typescript
// POST /api/export
const response = await fetch('http://localhost:3001/api/export', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
projectId: 'proj_123',
format: 'pdf', // 'html' | 'pdf' | 'pptx' | 'zip' | 'mp4' | 'markdown'
artifactId: 'art_456'
})
});
const blob = await response.blob();
// Save or download the exported file
```
#### Import Claude Design Export
```typescript
// POST /api/import/claude-design
const formData = new FormData();
formData.append('file', claudeDesignZip);
const response = await fetch('http://localhost:3001/api/import/claude-design', {
method: 'POST',
body: formData
});
const { projectId, conversationId } = await response.json();
```
### BYOK Proxy Endpoints
```typescript
// POST /api/proxy/anthropic/stream
const response = await fetch('http://localhost:3001/api/proxy/anthropic/stream', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.ANTHROPIC_API_KEY}`
},
body: JSON.stringify({
model: 'claude-3-5-sonnet-20241022',
messages: [{ role: 'user', content: 'Design a landing page' }],
max_tokens: 4096
})
});
// SSE stream normalized to Open Design chat protocol
```
## Working Code Examples
### Creating a Web Prototype with Design System
```typescript
// apps/web/lib/create-prototype.ts
import { useAgent } from '@/hooks/use-agent';
export function usePrototypeCreation() {
const { startSession, streamResponse } = useAgent();
async function createPrototype(prompt: string) {
const session = await startSession({
skill: 'web-prototype',
designSystem: 'stripe', // Use Stripe design system
direction: 'modern-minimal',
prompt: `
${prompt}
Requirements:
- Use Stripe's color palette and typography
- Include responsive navigation
- Add interactive components
- Follow accessibility best practices
`
});
for await (const chunk of streamResponse(session.id)) {
if (chunk.type === 'artifact') {
// Artifact ready for sandboxed preview
renderInIframe(chunk.content);
}
if (chunk.type === 'tool_call' && chunk.name === 'Write') {
// Agent writing to project folder
console.log(`Writing: ${chunk.args.path}`);
}
}
}
return { createPrototype };
}
```
### Using Skills Programmatically
```typescript
// apps/daemon/src/skills/loader.ts
import { loadSkill } from './skills-registry';
async function executeSkillWithAgent(
skillName: string,
userPrompt: string,
agentCli: string
) {
const skill = await loadSkill(skillName);
// Combine skill prompt + user prompt
const fullPrompt = `
${skill.systemPrompt}
## User Request
${userPrompt}
## Design System
${await loadDesignSystem('linear')}
## Visual Direction
${await loadDirection('modern-minimal')}
## Pre-flight Checklist
${skill.checklist.join('\n')}
`;
// Spawn agent CLI
const process = spawn(agentCli, ['--prompt-file', 'prompt.txt'], {
cwd: projectPath,
env: { ...process.env }
});
// Stream response
process.stdout.on('data', (chunk) => {
const artifact = parseArtifact(chunk.toString());
if (artifact) {
emit('artifact', artifact);
}
});
}
```
### Custom Skill Definition
```typescript
// skills/custom-portfolio/skill.json
{
"name": "custom-portfolio",
"displayName": "Portfolio Website",
"scenario": "personal",
"description": "Personal portfolio with project showcase",
"mode": "prototype",
"template": "portfolio-base",
"checklist": [
"Hero section with name and tagline",
"Project grid with hover states",
"About section with bio",
"Contact form with validation",
"Responsive mobile layout"
],
"systemPrompt": "You are building a personal portfolio...",
"palette": ["oklch(0.95 0.02 200)", "oklch(0.2 0.05 250)"],
"fonts": {
"heading": "Inter",
"body": "Inter"
}
}
```
### Export Pipeline
```typescript
// apps/daemon/src/export/pdf.ts
import puppeteer from 'puppeteer';
export async function exportToPDF(
htmlContent: string,
options: { format?: 'A4' | 'Letter' }
) {
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
عرض على GitHub