Obrigado por considerar contribuir. O OD é pequeno de propósito — a maior parte do valor mora em arquivos (skills, design systems, fragmentos de prompt) e não em código de framework. Isso significa que as contribuições com maior alavancagem geralmente são uma pasta, um arquivo Markdown ou um adapter do tamanho de um PR.
Este guia diz exatamente onde olhar para cada tipo de contribuição e qual a barra que um PR precisa atingir antes do merge.
English · Português (Brasil) · Deutsch · Français · 简体中文 · 日本語
| Se você quer… | Você está adicionando | Onde mora | Tamanho da entrega |
|---|---|---|---|
| Fazer o OD renderizar um novo tipo de artifact (uma nota fiscal, uma tela de Settings do iOS, um one-pager…) | uma Skill | skills/<sua-skill>/ |
uma pasta, ~2 arquivos |
| Fazer o OD falar a linguagem visual de uma nova marca | um Design System | design-systems/<marca>/DESIGN.md |
um arquivo Markdown |
| Plugar um novo CLI de agente de código | um Adapter de agente | apps/daemon/src/agents.ts |
~10 linhas em um array |
Adicionar uma feature, corrigir um bug, trazer um padrão de UX do open-codesign |
código | apps/web/src/, apps/daemon/ |
PR normal |
| Melhorar docs, traduzir uma seção para Français / Deutsch / 中文, corrigir typos | docs | README.md, README.fr.md, README.de.md, README.zh-CN.md, docs/, QUICKSTART.md |
um PR |
Se você não tem certeza em qual balde sua ideia se encaixa, abra primeiro uma discussion / issue e te apontamos para a superfície certa.
O setup completo numa página mora em QUICKSTART.pt-BR.md. O TL;DR para contribuidores:
git clone https://github.com/nexu-io/open-design.git
cd open-design
corepack enable # selects the pinned pnpm from packageManager
pnpm install
pnpm tools-dev run web # daemon + web foreground loop
pnpm typecheck # tsc -b --noEmit
pnpm --filter @open-design/web build # build do pacote web quando necessárioNode ~24 e pnpm 10.33.x são obrigatórios. nvm / fnm são opcionais; use nvm install 24 && nvm use 24 ou fnm install 24 && fnm use 24 se preferir gerenciar Node assim. macOS, Linux e WSL2 são os caminhos principais. Windows nativo costuma funcionar, mas não é alvo principal — abra uma issue se quebrar.
Você não precisa de nenhum CLI de agente no PATH para desenvolver o próprio OD — o daemon dirá "no agents found" e cairá no caminho Anthropic API · BYOK, que é o loop de dev mais rápido de qualquer jeito.
Uma skill é uma pasta sob skills/ com um SKILL.md na raiz, seguindo a convenção SKILL.md do Claude Code mais nossa extensão opcional od:. Não há passo de registro. Coloque a pasta, reinicie o daemon e o picker mostra.
skills/your-skill/
├── SKILL.md # required
├── assets/template.html # optional but recommended — the seed file
├── references/ # optional — knowledge files the agent reads
│ ├── layouts.md
│ ├── components.md
│ └── checklist.md
└── example.html # strongly recommended — a real, hand-built sample
As três primeiras chaves são a base spec do Claude Code — name, description, triggers. Tudo sob od: é específico do OD e opcional, mas od.mode decide em qual grupo a skill aparece (Prototype / Deck / Template / Design system).
---
name: your-skill
description: |
One-paragraph elevator pitch. The agent reads this verbatim to decide
if the user's brief matches. Be concrete: surface, audience, what's in
the artifact, what's not.
triggers:
- "your trigger phrase"
- "another phrase"
- "中文触发词"
od:
mode: prototype # prototype | deck | template | design-system
platform: desktop # desktop | mobile
scenario: marketing # free-form tag for grouping
featured: 1 # any positive integer surfaces it under "Showcase examples"
preview:
type: html # html | jsx | pptx | markdown
entry: index.html
design_system:
requires: true # does the skill read the active DESIGN.md?
sections: [color, typography, layout, components]
example_prompt: "A copy-pastable prompt that nicely shows what this skill does."
---
# Your Skill
Body is free-form Markdown describing the workflow the agent should follow…A gramática completa — inputs tipados, parâmetros de slider, gating de capacidades — vive em docs/skills-protocol.md.
Somos exigentes com skills porque elas são a superfície voltada para o usuário. Uma nova skill precisa:
- Trazer um
example.htmlreal. Feito à mão, abre direto do disco e parece algo que um designer entregaria. Sem lorem ipsum, sem hero placeholder<svg><rect/></svg>. Se você não consegue construir o exemplo, provavelmente a skill ainda não está pronta. - Passar no checklist anti-AI-slop no corpo. Sem gradiente roxo, sem ícones genéricos de emoji, sem card arredondado com borda lateral de destaque, sem Inter como fonte de display, sem stats inventados. Leia a seção Anti-AI-slop machinery do README para a lista completa.
- Placeholders honestos. Quando o agente não tem um número real, escreva
—ou um bloco cinza com label, não "10× mais rápido". - Ter um
references/checklist.mdcom pelo menos os gates P0 (o que o agente precisa passar antes de emitir<artifact>). Pegue o formato emskills/guizang-ppt/references/checklist.mdouskills/dating-web/references/checklist.md. - Adicionar um screenshot em
docs/screenshots/skills/<skill>.pngse a skill for featured. PNG, ~1024×640 retina, capturado doexample.htmlreal em zoom-out do navegador. - Ser uma única pasta self-contained. Sem imports de CDN além do que outras skills já usam; sem fontes que você não licenciou; sem imagens maiores que ~250 KB.
Se você forkar uma skill existente (por exemplo, partir do dating-web e remixar para um recruiting-web), preserve o LICENSE original e a autoria em references/ e mencione isso na descrição do PR.
- Showcase visual, protótipo de tela única:
skills/dating-web/,skills/digital-eguide/ - Fluxo mobile multi-frame:
skills/mobile-onboarding/,skills/gamified-app/ - Documento / template (sem design system obrigatório):
skills/pm-spec/,skills/weekly-update/ - Modo deck:
skills/guizang-ppt/(bundled literalmente de op7418/guizang-ppt-skill) eskills/simple-deck/
Um design system é um único arquivo DESIGN.md sob design-systems/<slug>/. Um arquivo, sem código. Coloque, reinicie o daemon, o picker mostra agrupado por categoria.
design-systems/your-brand/
└── DESIGN.md
# Design System Inspired by YourBrand
> Category: Developer Tools
> One-line summary that shows in the picker preview.
## 1. Visual Theme & Atmosphere
…
## 2. Color
- Primary: `#hex` / `oklch(...)`
- …
## 3. Typography
…
## 4. Spacing & Grid
## 5. Layout & Composition
## 6. Components
## 7. Motion & Interaction
## 8. Voice & Brand
## 9. Anti-patternsO schema de 9 seções é fixo — é o que os corpos das skills procuram via grep. O primeiro H1 vira o label do picker (o prefixo Design System Inspired by é removido automaticamente) e a linha > Category: … decide em qual grupo o sistema cai. As categorias existentes estão em design-systems/README.md; se sua marca realmente não couber, dá pra introduzir uma nova, mas tente as existentes primeiro.
- As 9 seções presentes. Corpos vazios são aceitáveis para dados difíceis (por exemplo, motion tokens), mas os títulos precisam estar lá ou o grep do prompt quebra.
- Códigos hex reais. Amostre direto do site ou produto da marca, não da memória nem de chute de IA. O protocolo de extração de spec da marca em 5 passos do README vale também para mantenedores.
- Valores OKLch para cores de destaque são desejáveis. Eles fazem paletas interpolarem de forma previsível entre claro/escuro.
- Sem fluff de marketing. O slogan da marca não é um design token. Corte.
- Slug em ASCII —
linear.appviralinear-app,x.aivirax-ai. Os 69 sistemas importados já seguem essa convenção; espelhe.
Os 69 sistemas de produto que entregamos são importados de VoltAgent/awesome-design-md via scripts/sync-design-systems.ts. Se sua marca pertence ao upstream, mande o PR para lá primeiro — pegamos automaticamente no próximo sync. A pasta design-systems/ é para sistemas que não cabem no upstream, mais nossos dois starters escritos à mão.
Plugar um novo agente (por exemplo, o CLI foo-coder de alguma loja nova) é uma entrada em apps/daemon/src/agents.ts:
{
id: 'foo',
name: 'Foo Coder',
bin: 'foo',
versionArgs: ['--version'],
buildArgs: (prompt) => ['exec', '-p', prompt],
streamFormat: 'plain', // or 'claude-stream-json' if it speaks that
}É só isso — o daemon detecta no PATH, o picker mostra, o caminho de chat funciona. Se o CLI emite eventos tipados (como o --output-format stream-json do Claude Code), conecte um parser em apps/daemon/src/claude-stream.ts e defina streamFormat: 'claude-stream-json'.
Barra para mergear:
- Uma sessão real funciona end-to-end com o novo agente — cole o log do daemon na descrição do PR mostrando que ele conseguiu streamar um artifact.
docs/agent-adapters.mdatualizado com as peculiaridades do CLI (precisa de arquivo de chave? aceita imagem? qual a flag não-interativa?).- A tabela "Supported coding agents" do README ganha uma linha.
O chat em modo API envia max_tokens para o provider upstream em toda requisição. O cliente web pega esse número de uma busca em três níveis em apps/web/src/state/maxTokens.ts:
- O override explícito do usuário em Settings, se definido.
- Caso contrário, o default por modelo em
apps/web/src/state/litellm-models.json— uma fatia vendored domodel_prices_and_context_window.jsondo BerriAI/litellm (MIT). Cobre ~2k modelos de chat de Anthropic, OpenAI, DeepSeek, Groq, Together, Mistral, Gemini, Bedrock, Vertex, OpenRouter etc. - Caso contrário,
FALLBACK_MAX_TOKENS = 8192.
Para incluir um modelo recém-lançado, regere o JSON vendored:
node --experimental-strip-types scripts/sync-litellm-models.tsO script busca o catálogo do LiteLLM, filtra entradas mode: 'chat', projeta cada uma para max_output_tokens (com fallback em max_tokens) e grava um snapshot ordenado. Faça commit do litellm-models.json regerado junto com o PR que disparou o refresh.
A tabela OVERRIDES em maxTokens.ts é para o caso raro em que o LiteLLM está faltando ou errado para um id de modelo que de fato usamos — por exemplo, mimo-v2.5-pro (o LiteLLM só entrega o MiMo via aliases openrouter/xiaomi/... e novita/xiaomimimo/..., e nenhum bate com o id canônico que a API direta da Xiaomi usa). Mantenha-a pequena; tudo que o LiteLLM acerta pertence ao upstream.
Alemão usa o formal Sie porque o OD fala com uma audiência mista de criadores solo, agências e times de engenharia; até feedback do projeto mostrar que uma voz informal du se encaixa melhor, alemão formal é o default menos surpreendente. PRs de locale devem traduzir chrome de UI, docs principais e metadados visuais de galeria em apps/web/src/i18n/content.ts, mas não devem traduzir skills/, design-systems/ nem corpos de prompt que os agentes executam. Esses prompts-fonte são mantidos como entradas de workflow, e manter um único idioma de fonte evita multiplicar QA de prompt entre locales. Ao adicionar ou renomear uma skill, design system ou prompt template, atualize os metadados de display em alemão e rode pnpm --filter @open-design/web test; o content.test.ts falha se a cobertura de display em alemão sair de sincronia. Erros do daemon, nomes de arquivos exportados e texto de artifact gerado pelo agente são limitações conhecidas, a menos que um PR explicitamente os englobe.
Para instruções passo a passo sobre adicionar um novo locale (dicionário de UI, README, language switcher, terminologia regional), veja TRANSLATIONS.md.
Não somos pedantes com formatação (Prettier on save está ok), mas duas regras são inegociáveis porque aparecem na pilha de prompt e na API voltada ao usuário:
- Aspas simples em JS/TS. Strings ficam com aspas simples a menos que escapar fique feio. O codebase já está consistente — siga.
- Comentários em inglês. Mesmo se o PR é para traduzir algo para alemão ou 中文, comentários de código ficam em inglês para mantermos um único conjunto de referências grepáveis.
Além disso:
- Não narre. Sem
// import the module, sem// loop through items. Se o código se lê obviamente, o comentário é ruído. Reserve comentários para intenção não-óbvia ou restrições que o código não consegue expressar. - TypeScript em
apps/web/src/. O daemon (apps/daemon/) é JavaScript ESM puro com JSDoc onde tipos importam — mantenha assim. - Sem novas dependências top-level sem um parágrafo na descrição do PR sobre o que ganhamos vs. quantos bytes despachamos. A lista de deps em
package.jsoné pequena de propósito. - Rode
pnpm typecheckantes do push. CI roda; falhar lá rende um comentário "please fix".
- Uma preocupação por PR. Adicionar uma skill + refatorar o parser + bumpar uma dep são três PRs.
- Título é imperativo + escopo.
add dating-web skill,fix daemon SSE backpressure when CLI hangs,docs: clarify .od layout. - Corpo explica o porquê. "O que isso faz" geralmente é óbvio do diff; "por que isso precisa existir" raramente é.
- Referencie uma issue se houver. Se não houver e o PR for não-trivial, abra uma antes para combinarmos que a mudança é desejada antes de você gastar o tempo.
- Sem squash durante review. Empurre fixups; squash no merge.
- Sem force-push em branch compartilhado a não ser que o reviewer tenha pedido.
Não exigimos CLA. A Apache-2.0 nos cobre; sua contribuição é licenciada nos mesmos termos.
Abra uma issue com:
- O que você executou (a invocação
pnpm tools-dev ...exata). - Qual CLI de agente foi selecionado (ou se você estava no caminho BYOK).
- O par skill + design system que disparou.
- A tail relevante de stderr do daemon — a maior parte dos relatos "o artifact nunca renderizou" são diagnosticados em 30 segundos quando dá pra ver
spawn ENOENTou o erro real do CLI. - Um screenshot se for UI.
Para bugs da pilha de prompt ("o agente emitiu um hero com gradiente roxo, a blacklist de slop deveria proibir isso"), inclua a mensagem completa do assistente para conseguirmos ver se a violação foi do modelo ou do prompt.
- Pergunta de arquitetura, pergunta de design, "isso é bug ou mau uso" → GitHub Discussions (preferido — pesquisável para o próximo).
- "Como escrevo uma skill que faz X" → Abra uma discussion. Respondemos e transformamos a resposta em
docs/skills-protocol.mdse for um padrão faltante.
Para manter o projeto focado, por favor não abra PRs que:
- Embutam um runtime de modelo. Toda a aposta do OD é "seu CLI existente já basta". Não despachamos
pi-ai, chaves OpenAI nem loaders de modelo. - Reescrevam o frontend para fora da stack atual sem discussão prévia. Next.js 16 App Router + React 18 + TS é a linha. Sem Astro, Solid, Svelte ou outras reescritas de framework a menos que mantenedores explicitamente queiram essa migração.
- Substituam o daemon por uma função serverless. O ponto inteiro do daemon é ter um
cwdreal e spawnar um CLI real. Deploy do SPA na Vercel está ok; o daemon continua daemon. - Adicionem telemetry / analytics / phone-home. O OD é local-first. As únicas chamadas de saída são para providers que o usuário configurou explicitamente.
- Empacotem um binário sem arquivo de licença e atribuição de autoria ao lado.
Se não tem certeza se sua ideia se encaixa, abra uma discussion antes de escrever o código.
Se você vem contribuindo de forma consistente e quer saber como é o caminho para se tornar um Maintainer, as regras estão em MAINTAINERS.md. A versão curta:
- Um Maintainer pode revisar, aprovar e fechar issues. O botão de merge continua com o Core Team — sua aprovação ainda conta como a aprovação obrigatória para merge.
- A barra é ≥ 20 merged PRs mais uma verificação publicada de qualidade da conta (anti-bot, anti-sock-puppet) mais um julgamento do Core Team sobre a qualidade da contribuição. Não há formulário de inscrição; o Core Team levanta candidatos internamente e entra em contato.
- Não há cotas, nem SLAs, nem mandato fixo. Sair é fácil e reversível (Emeritus → volte quando a vida acalmar).
- Todos os limiares, o fluxo de nomeação, as regras de step-down e o waiver de projeto inicial estão em
MAINTAINERS.md. Leia esse documento se algo acima te interessar.
O tl;dr: mande bons PRs, revise com cuidado, apareça nas Discussions / no Discord, e o resto se resolve sozinho.
Ao contribuir, você concorda que sua contribuição é licenciada sob a Licença Apache-2.0 deste repositório, com a exceção dos arquivos dentro de skills/guizang-ppt/, que mantêm sua licença MIT original e atribuição de autoria a op7418.