Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 31 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ OD stands on four open-source shoulders:

| | What you get |
|---|---|
| **Coding agents supported** | Claude Code · Codex CLI · Cursor Agent · Gemini CLI · OpenCode · Qwen Code · Anthropic API (BYOK fallback) |
| **Coding agents supported** | Claude Code · Codex CLI · Cursor Agent · Gemini CLI · OpenCode · Qwen Code · Hosted-API BYOK fallback (Anthropic · OpenAI-compatible · Azure · Google Gemini, plus AWS Bedrock & GCP Vertex via proxy) |
| **Design systems built-in** | **71** — 2 hand-authored starters + 69 product systems (Linear, Stripe, Vercel, Airbnb, Tesla, Notion, Anthropic, Apple, Cursor, Supabase, Figma, …) imported from [`awesome-design-md`][acd2] |
| **Skills built-in** | **19** — prototype, deck, mobile, dashboard, pricing, docs, blog, SaaS landing, plus 10 document/work-product templates (PM spec, weekly update, OKRs, runbook, kanban, …) |
| **Visual directions** | 5 curated schools (Editorial Monocle · Modern Minimal · Tech Utility · Brutalist · Soft Warm) — each ships a deterministic OKLch palette + font stack |
Expand Down Expand Up @@ -180,7 +180,7 @@ Adding a skill takes one folder. Read [`docs/skills-protocol.md`](docs/skills-pr

### 1 · We don't ship an agent. Yours is good enough.

The daemon scans your `PATH` for [`claude`](https://docs.anthropic.com/en/docs/claude-code), [`codex`](https://github.com/openai/codex), [`cursor-agent`](https://www.cursor.com/cli), [`gemini`](https://github.com/google-gemini/gemini-cli), [`opencode`](https://opencode.ai/), and [`qwen`](https://github.com/QwenLM/qwen-code) on startup. Whichever it finds becomes the design engine — driven via stdio, with one adapter per CLI. Inspired by [`multica`](https://github.com/multica-ai/multica) and [`cc-switch`](https://github.com/farion1231/cc-switch). No CLI? `Anthropic API · BYOK` is the same pipeline minus the spawn.
The daemon scans your `PATH` for [`claude`](https://docs.anthropic.com/en/docs/claude-code), [`codex`](https://github.com/openai/codex), [`cursor-agent`](https://www.cursor.com/cli), [`gemini`](https://github.com/google-gemini/gemini-cli), [`opencode`](https://opencode.ai/), and [`qwen`](https://github.com/QwenLM/qwen-code) on startup. Whichever it finds becomes the design engine — driven via stdio, with one adapter per CLI. Inspired by [`multica`](https://github.com/multica-ai/multica) and [`cc-switch`](https://github.com/farion1231/cc-switch). No CLI? The `Hosted API · BYOK` fallback streams directly from the browser to **Anthropic**, any **OpenAI-compatible** endpoint (OpenRouter / LiteLLM / DeepSeek / Groq / Together / Mistral …), **Azure OpenAI**, or **Google Gemini** — pick the provider in Settings, paste a key, go. AWS Bedrock and GCP Vertex Anthropic models work the same way through a server-side LiteLLM (or equivalent) proxy pointed at the `Anthropic` provider, since SigV4 / GCP JWT signing belongs on the server, not the browser.

### 2 · Skills are files, not plugins.

Expand Down Expand Up @@ -227,8 +227,10 @@ Every layer is composable. Every layer is a file you can edit. Read [`src/prompt
│ /api/* (proxied in dev) │ direct (BYOK)
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ Local daemon │ │ Anthropic SDK │
│ (Express + SQLite) │ │ (browser fallback) │
│ Local daemon │ │ Hosted-API router │
│ (Express + SQLite) │ │ Anthropic · OpenAI- │
│ │ │ compatible · Azure │
│ │ │ · Google Gemini │
│ │ └──────────────────────┘
│ /api/agents │
│ /api/skills │
Expand Down Expand Up @@ -268,7 +270,7 @@ The first load:

1. Detects which agent CLIs you have on `PATH` and picks one automatically.
2. Loads 19 skills + 71 design systems.
3. Pops the welcome dialog so you can paste an Anthropic key (only needed for the BYOK fallback path).
3. Pops the welcome dialog so you can pick a hosted-API provider — **Anthropic**, **OpenAI-compatible** (OpenRouter / LiteLLM / DeepSeek / Groq / Together / Mistral / OpenAI), **Azure OpenAI**, or **Google Gemini** — and paste the matching key (only needed for the BYOK fallback path; for AWS Bedrock or GCP Vertex Anthropic models, run a server-side LiteLLM proxy and point the `Anthropic` provider at it).
4. **Auto-creates `./.od/`** — the local runtime folder for the SQLite project DB, per-project artifacts, and saved renders. There is no `od init` step; the daemon `mkdir`s everything it needs on boot.

Type a prompt, hit **Send**, watch the question form arrive, fill it, watch the todo card stream, watch the artifact render. Click **Save to disk** or download as a project ZIP.
Expand Down Expand Up @@ -334,7 +336,12 @@ open-design/
│ │ └── zip.ts ← project archive
│ ├── providers/
│ │ ├── daemon.ts ← /api/chat SSE stream consumer
│ │ ├── anthropic.ts ← BYOK Anthropic SDK path
│ │ ├── model.ts ← BYOK provider router (anthropic / openai / azure / google)
│ │ ├── anthropic.ts ← Anthropic SDK path (also covers any Anthropic-compatible proxy)
│ │ ├── openai.ts ← OpenAI-compatible SSE (OpenRouter / LiteLLM / DeepSeek / Groq / Together)
│ │ ├── azure.ts ← Azure OpenAI deployment URLs + api-key header
│ │ ├── google.ts ← Google Generative Language streamGenerateContent
│ │ ├── presets.ts ← per-provider defaults shown in Settings
│ │ └── registry.ts ← /api/agents, /api/skills, /api/design-systems
│ └── state/ ← config + projects (localStorage + daemon-backed)
Expand Down Expand Up @@ -499,10 +506,27 @@ Auto-detected from `PATH` on daemon boot. No config required.
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `gemini` | line-buffered | `gemini -p` |
| [OpenCode](https://opencode.ai/) | `opencode` | line-buffered | `opencode run` |
| [Qwen Code](https://github.com/QwenLM/qwen-code) | `qwen` | line-buffered | `qwen -p` |
| Anthropic API · BYOK | n/a | SSE direct | Browser fallback when no CLI is on PATH |
| Hosted API · BYOK | n/a | SSE direct | Browser fallback when no CLI is on PATH — pick any of the providers below |

Adding a new CLI is one entry in [`daemon/agents.js`](daemon/agents.js). Streaming format is one of `claude-stream-json` (typed events) or `plain` (raw text).

### Hosted-API providers (BYOK fallback)

When no CLI is detected, OD streams directly from the browser to a hosted endpoint. Pick one in **Settings → Hosted API**, paste a key, optionally tweak the base URL.

| Provider | Wire format | What it covers |
|---|---|---|
| **Anthropic** | `@anthropic-ai/sdk` | `api.anthropic.com`, plus any Anthropic-compatible proxy (LiteLLM, custom gateways, **AWS Bedrock** & **GCP Vertex** via a server-side proxy) |
| **OpenAI-compatible** | `/chat/completions` SSE | OpenAI proper, [OpenRouter](https://openrouter.ai), [LiteLLM proxy](https://docs.litellm.ai/), [DeepSeek](https://platform.deepseek.com/), [Groq](https://groq.com/), [Together](https://together.ai/), [Mistral](https://mistral.ai/), and any other OpenAI-shaped endpoint |
| **Azure OpenAI** | `/openai/deployments/<deployment>/chat/completions` SSE + `api-key` header | Azure-hosted OpenAI deployments. Base URL is the resource endpoint, Model is the deployment name, plus the Azure `api-version` |
| **Google Gemini** | `:streamGenerateContent?alt=sse` | Google Generative Language API direct (Gemini family) |

**Text-only on the OpenAI, Azure, and Google paths today.** The `Anthropic` provider (and any Anthropic-compatible proxy) bridges the full event stream. The other three paths only forward text deltas — `delta.tool_calls` / `delta.function_call` / `delta.reasoning_content` (DeepSeek-R1, OpenAI o-series) and Gemini `parts[*].functionCall` / `parts[*].inlineData` are dropped. If a skill or artifact prompt needs tool calls or vision, stay on the `Anthropic` provider for now.

**On AWS Bedrock & GCP Vertex with Anthropic models:** Both require credential signing (SigV4 / GCP service-account JWT) which is unsafe to do from a browser with long-lived BYOK credentials. The recommended path is to run a server-side proxy ([LiteLLM](https://docs.litellm.ai/) works well — it speaks Anthropic-compatible *and* OpenAI-compatible — see the [Bedrock](https://docs.litellm.ai/docs/providers/bedrock) and [Vertex AI](https://docs.litellm.ai/docs/providers/vertex_ai) docs for the exact passthrough config) and point either the `Anthropic` or `OpenAI-compatible` provider at the proxy URL. The signing stays on the server where it belongs.

Adding a fifth wire format is mechanical: a row in `ModelProvider`, an entry in [`src/providers/presets.ts`](src/providers/presets.ts), a `stream<X>` function alongside [`anthropic.ts` / `openai.ts` / `azure.ts` / `google.ts`](src/providers/), one more `case` in [`src/providers/model.ts`](src/providers/model.ts).

## References & lineage

Every external project this repo borrows from. Each link goes to the source so you can verify the provenance.
Expand Down
38 changes: 31 additions & 7 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ OD 站在四个开源项目的肩膀上:

| | 你拿到的 |
|---|---|
| **支持的 coding agent** | Claude Code · Codex CLI · Cursor Agent · Gemini CLI · OpenCode · Qwen Code · Anthropic APIBYOK 兜底) |
| **支持的 coding agent** | Claude Code · Codex CLI · Cursor Agent · Gemini CLI · OpenCode · Qwen Code · 托管 API · BYOK 兜底(Anthropic · OpenAI 兼容 · Azure · Google Gemini,AWS Bedrock 与 GCP Vertex 通过代理接入) |
| **内置 design system** | **71 套** —— 2 套手写起手 + 69 套从 [`awesome-design-md`][acd2] 导入的产品系统(Linear、Stripe、Vercel、Airbnb、Tesla、Notion、Anthropic、Apple、Cursor、Supabase、Figma…) |
| **内置 skill** | **19 个** —— 原型 / deck / 移动端 / dashboard / pricing / docs / blog / SaaS landing,外加 10 个文档与办公产物模板(PM 规范、周报、OKR、runbook、看板…) |
| **视觉方向** | 5 套精选流派(Editorial Monocle · Modern Minimal · Tech Utility · Brutalist · Soft Warm),每一套自带 OKLch 色板 + 字体栈 |
Expand Down Expand Up @@ -180,7 +180,7 @@ OD 站在四个开源项目的肩膀上:

### 1 · 我们不带 agent,你的就够好

Daemon 启动时扫 `PATH`,找 [`claude`](https://docs.anthropic.com/en/docs/claude-code)、[`codex`](https://github.com/openai/codex)、[`cursor-agent`](https://www.cursor.com/cli)、[`gemini`](https://github.com/google-gemini/gemini-cli)、[`opencode`](https://opencode.ai/)、[`qwen`](https://github.com/QwenLM/qwen-code)。哪个在就用哪个 —— 通过 stdio 驱动,每个 CLI 一个 adapter。灵感来自 [`multica`](https://github.com/multica-ai/multica) 和 [`cc-switch`](https://github.com/farion1231/cc-switch)。一个 CLI 都没有?`Anthropic API · BYOK` 就是同一条管线减去 spawn。
Daemon 启动时扫 `PATH`,找 [`claude`](https://docs.anthropic.com/en/docs/claude-code)、[`codex`](https://github.com/openai/codex)、[`cursor-agent`](https://www.cursor.com/cli)、[`gemini`](https://github.com/google-gemini/gemini-cli)、[`opencode`](https://opencode.ai/)、[`qwen`](https://github.com/QwenLM/qwen-code)。哪个在就用哪个 —— 通过 stdio 驱动,每个 CLI 一个 adapter。灵感来自 [`multica`](https://github.com/multica-ai/multica) 和 [`cc-switch`](https://github.com/farion1231/cc-switch)。一个 CLI 都没有?`托管 API · BYOK` 就是同一条管线减去 spawn —— 浏览器直连 **Anthropic**、任意 **OpenAI 兼容**端点(OpenRouter / LiteLLM / DeepSeek / Groq / Together / Mistral …)、**Azure OpenAI**、或 **Google Gemini**。在 Settings 里选渠道、贴 Key、走起。AWS Bedrock 和 GCP Vertex 上的 Anthropic 模型按同样的方式接入:服务端跑一个 LiteLLM(或同类)代理,再把 `Anthropic` 渠道指向它 —— SigV4 / GCP JWT 签名应留在服务器,不放进浏览器

### 2 · Skill 是文件,不是插件

Expand Down Expand Up @@ -227,8 +227,10 @@ DISCOVERY 指令 (turn-1 表单、turn-2 品牌分支、TodoWrite、
│ /api/* (dev 走代理) │ direct (BYOK)
▼ ▼
┌──────────────────────┐ ┌──────────────────────┐
│ 本地 daemon │ │ Anthropic SDK │
│ (Express + SQLite)│ │ (浏览器兜底) │
│ 本地 daemon │ │ 托管 API 路由器 │
│ (Express + SQLite)│ │ Anthropic · OpenAI │
│ │ │ 兼容 · Azure · Google│
│ │ │ Gemini │
│ │ └──────────────────────┘
│ /api/agents │
│ /api/skills │
Expand Down Expand Up @@ -268,7 +270,7 @@ open http://localhost:5173

1. 检测你 `PATH` 上有哪些 agent CLI,自动选一个。
2. 加载 19 个 skill + 71 套 design system。
3. 弹欢迎对话框,让你贴 Anthropic key(仅 BYOK 兜底路径需要)。
3. 弹欢迎对话框,让你挑一个托管 API 渠道 —— **Anthropic**、**OpenAI 兼容**(OpenRouter / LiteLLM / DeepSeek / Groq / Together / Mistral / OpenAI)、**Azure OpenAI** 或 **Google Gemini** —— 并贴上对应的 Key(仅 BYOK 兜底路径需要;要在浏览器里调 AWS Bedrock / GCP Vertex 上的 Anthropic 模型,建议在服务器跑一个 LiteLLM 代理,再把 `Anthropic` 渠道指向它)。
4. **自动创建 `./.od/`** —— 本地运行时目录,存放 SQLite 项目库、各项目工作区、保存下来的 artifact。**没有** `od init` 这一步,daemon 启动时会自己 `mkdir`。

输入需求,回车,看 question form 跳出来,填,看 todo 卡片流动,看 artifact 渲染。点 **Save to disk** 或导出整个项目 ZIP。
Expand Down Expand Up @@ -334,7 +336,12 @@ open-design/
│ │ └── zip.ts ← 项目打包
│ ├── providers/
│ │ ├── daemon.ts ← /api/chat SSE 流消费者
│ │ ├── anthropic.ts ← BYOK Anthropic SDK 路径
│ │ ├── model.ts ← BYOK 渠道路由(anthropic / openai / azure / google)
│ │ ├── anthropic.ts ← Anthropic SDK 路径(也涵盖任意 Anthropic 兼容代理)
│ │ ├── openai.ts ← OpenAI 兼容 SSE(OpenRouter / LiteLLM / DeepSeek / Groq / Together)
│ │ ├── azure.ts ← Azure OpenAI 部署 URL + api-key 头
│ │ ├── google.ts ← Google Generative Language streamGenerateContent
│ │ ├── presets.ts ← Settings 中各渠道的默认值
│ │ └── registry.ts ← /api/agents、/api/skills、/api/design-systems
│ └── state/ ← config + projects(localStorage + daemon 持久化)
Expand Down Expand Up @@ -499,10 +506,27 @@ Daemon 启动时从 `PATH` 自动检测,无需配置。
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | `gemini` | line-buffered | `gemini -p` |
| [OpenCode](https://opencode.ai/) | `opencode` | line-buffered | `opencode run` |
| [Qwen Code](https://github.com/QwenLM/qwen-code) | `qwen` | line-buffered | `qwen -p` |
| Anthropic API · BYOK | n/a | SSE 直连 | 没装任何 CLI 时的浏览器兜底 |
| 托管 API · BYOK | n/a | SSE 直连 | 没装任何 CLI 时的浏览器兜底 —— 在下方任意一个渠道里挑一个 |

加一个新 CLI = 在 [`daemon/agents.js`](daemon/agents.js) 里加一项。流式格式从 `claude-stream-json`(类型化事件)和 `plain`(原始文本)两种里选一个。

### 托管 API 渠道(BYOK 兜底)

没检测到 CLI 时,OD 会从浏览器直连一个托管端点。在 **Settings → 托管 API** 里挑一个渠道,贴 Key,按需改 Base URL。

| 渠道 | 报文格式 | 覆盖范围 |
|---|---|---|
| **Anthropic** | `@anthropic-ai/sdk` | `api.anthropic.com`,以及任意 Anthropic 兼容代理(LiteLLM、自建网关、**AWS Bedrock** 与 **GCP Vertex** 通过服务端代理接入) |
| **OpenAI 兼容** | `/chat/completions` SSE | OpenAI 官方、[OpenRouter](https://openrouter.ai)、[LiteLLM 代理](https://docs.litellm.ai/)、[DeepSeek](https://platform.deepseek.com/)、[Groq](https://groq.com/)、[Together](https://together.ai/)、[Mistral](https://mistral.ai/),以及任意 OpenAI 形态的端点 |
| **Azure OpenAI** | `/openai/deployments/<deployment>/chat/completions` SSE + `api-key` 头 | Azure 托管的 OpenAI 部署。Base URL 是资源终结点,Model 是部署名,再加 Azure 的 `api-version` |
| **Google Gemini** | `:streamGenerateContent?alt=sse` | Google Generative Language API 直连(Gemini 系列) |

**目前 OpenAI、Azure、Google 渠道仅桥接文本。**`Anthropic` 渠道(含任意 Anthropic 兼容代理)会传递完整事件流,其他三条路径只转发文本增量 —— `delta.tool_calls` / `delta.function_call` / `delta.reasoning_content`(DeepSeek-R1、OpenAI o-series)以及 Gemini 的 `parts[*].functionCall` / `parts[*].inlineData` 都会被丢弃。如果某个 skill 或 artifact prompt 依赖工具调用或视觉,请暂时留在 `Anthropic` 渠道。

**关于 AWS Bedrock 与 GCP Vertex 上的 Anthropic 模型:**两者都需要凭证签名(SigV4 / GCP service-account JWT),用浏览器里长期存放的 BYOK 凭证去签是不安全的。推荐做法:在服务器端跑一个代理([LiteLLM](https://docs.litellm.ai/) 同时支持 Anthropic 兼容和 OpenAI 兼容 —— 具体配置见 [Bedrock](https://docs.litellm.ai/docs/providers/bedrock) 与 [Vertex AI](https://docs.litellm.ai/docs/providers/vertex_ai) 文档),把 `Anthropic` 或 `OpenAI 兼容` 渠道的 Base URL 指向代理,签名留在服务器端。

加第五种报文格式很机械:`ModelProvider` 里加一行、[`src/providers/presets.ts`](src/providers/presets.ts) 里加一项、和 [`anthropic.ts` / `openai.ts` / `azure.ts` / `google.ts`](src/providers/) 一起放一个 `stream<X>` 函数、[`src/providers/model.ts`](src/providers/model.ts) 里再加一个 `case`。

## 引用与师承

每一个被借鉴的开源项目都列在这里。点链接可以验证师承。
Expand Down
5 changes: 3 additions & 2 deletions src/components/AvatarMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import { useT } from '../i18n';
import { providerLabel } from '../providers/presets';
import { AgentIcon } from './AgentIcon';
import { Icon } from './Icon';
import type { AgentInfo, AppConfig, ExecMode } from '../types';
Expand Down Expand Up @@ -82,11 +83,11 @@ export function AvatarMenu({
<span className="who">
{config.mode === 'daemon'
? t('avatar.localCli')
: t('avatar.anthropicApi')}
: providerLabel(config.provider)}
</span>
<span className="where">
{config.mode === 'api'
? safeHost(config.baseUrl)
? `${config.model}${config.baseUrl ? ` · ${safeHost(config.baseUrl)}` : ''}`
: currentAgent
? `${currentAgent.name}${currentAgent.version ? ` · ${currentAgent.version}` : ''}`
: t('avatar.noAgentSelected')}
Expand Down
Loading