MÓDULO 2.1

🏗️ Arquitetura do monorepo: core + dashboard + plugin

Um repo, três cidadãos: o core (engine pura), o dashboard (app React) e o plugin (skills, agents, manifests). Você vai entender quem fala com quem, onde estão as fronteiras e por que importar do lugar errado quebra o Vite.

6
Tópicos
40
Minutos
Intermediário
Nível
Estrutural
Tipo
packages/core types · schema · search tree-sitter · tours packages/dashboard React · Vite · React Flow Zustand · Tailwind v4 plugin/src slash-commands TS skills · agents · hooks /types /schema /search entry default .claude-plugin/ Claude Code .cursor-plugin/ Cursor .copilot-plugin/ VS Code Copilot Arquitetura do monorepo pnpm workspaces · subpath exports · três targets de empacotamento
O core é a engine compartilhada. Dashboard e plugin consomem por subpath exports. Os três manifests empacotam o mesmo plugin para runtimes distintos.
1

📦 pnpm workspaces: o "porquê" de monorepo

O Understand Anything roda em três runtimes diferentes (Claude Code, Cursor, Copilot) e compartilha código entre duas superfícies (skill TypeScript + dashboard React). Repositórios separados significariam publicar versões alinhadas manualmente o tempo todo. pnpm workspaces resolve isso: um workspace:* no package.json e o link entre pacotes vira simbólico, instantâneo.

🎯 O contrato do workspace

A raiz declara três coisas que definem tudo:

  • pnpm-workspace.yaml — lista os pacotes (understand-anything-plugin/packages/*)
  • package.json raiz — campo packageManager pina a versão do pnpm
  • Scripts --filter — rodam tarefas só onde importa

pnpm-workspace.yaml

packages:
  - "understand-anything-plugin"
  - "understand-anything-plugin/packages/*"

workspace protocol

Link simbólico entre pacotes locais

Hoisting

Deps comuns sobem para a raiz

--filter

Roda script só num pacote

packageManager

Pin do gerenciador para reprodutibilidade

2

🧩 packages/core: a engine de análise compartilhada

O @understand-anything/core é o cérebro neutro. Não sabe se está num terminal, num navegador ou dentro de um agente — só sabe trabalhar com o grafo. Esse isolamento é o que permite o dashboard rodar a mesma lógica de busca que o skill TS roda no scan.

✓ O que vive no core

  • types — definição canônica de Node, Edge, Graph
  • schema — validação Zod do grafo persistido
  • persistence — read/write atômico de knowledge-graph.json
  • tree-sitter (WASM) — parser determinístico
  • search — fuzzy + semantic indices
  • tours — gerador de walkthroughs

✗ O que NÃO pertence ao core

  • Componentes React (vão pro dashboard)
  • Lógica de slash-command (vai pro plugin/src)
  • Chamadas para LLM (são responsabilidade dos agents)
  • Configs de Vite/Tailwind/PostCSS
  • I/O específico de Claude Code, Cursor, etc.

💡 Dica prática

Antes de criar uma feature nova, pergunte: "isso é sobre o grafo em si, ou sobre como o grafo é usado?" Se for sobre o grafo, vai pro core. Se for sobre uso, vai pro dashboard ou plugin. Esse teste evita 80% das discussões de arquitetura.

Pure TS

Sem deps de framework

SSOT

Schema canônico

Subpaths

Browser-safe exports

Vitest

Testes rápidos com filter

3

🌐 Subpath exports browser-safe

O core importa node:fs e node:path na camada de persistência. Se o dashboard importasse o entry default, o Vite tentaria empacotar isso pro navegador e o build morreria. A solução: conditional exports que expõem só fatias seguras.

packages/core/package.json (trecho)

{
  "exports": {
    ".":        "./dist/index.js",         // Node-only (skill, scan)
    "./types":  "./dist/types/index.js",   // Browser-safe
    "./schema": "./dist/schema/index.js",  // Browser-safe
    "./search": "./dist/search/index.js"   // Browser-safe
  }
}

🚨 Atenção

Importar from '@understand-anything/core' dentro de packages/dashboard/ é proibido. Use from '@understand-anything/core/search', /types, ou /schema. Esse é um dos erros que mais aparecem em PR de contribuidor novo.

✓ FAZER (dashboard)

  • import {'{ Graph }'} from '@ua/core/types'
  • import {'{ validate }'} from '@ua/core/schema'
  • import {'{ fuzzySearch }'} from '@ua/core/search'

✗ NÃO fazer (dashboard)

  • import {'{ ... }'} from '@ua/core'
  • import {'{ readGraph }'} from '@ua/core/persistence'
  • import fs from 'node:fs' (browser!)

Conditional exports

Múltiplos entrypoints

Boundary

Browser ↔ Node

Vite-friendly

Build não quebra

TS strict

.d.ts por subpath

4

🎨 packages/dashboard: o frontend que o usuário vê

Aqui mora o app React. Stack escolhida pra ser leve e moderna: Vite como bundler, React Flow para o canvas do grafo, Zustand para estado global e Tailwind v4 com tokens centralizados. Sem Redux, sem Monaco, sem ChatPanel — o foco é o grafo.

1

Layout: 75% grafo + sidebar 360px

Decisão de UX

O grafo é a estrela. A sidebar à direita é um painel auxiliar que reage à seleção. Nada de painel inferior cheio de abas — isso vira ruído.

2

Schema validation no boot

Falha cedo, falha alto

Ao carregar o JSON, o dashboard valida contra o schema do core. Falha = banner vermelho explicando qual campo está errado. Nunca tela em branco.

3

Tema dark luxury

Identidade visual

Preto profundo #0a0a0a, acento gold/amber #d4a574, tipografia DM Serif Display nos títulos. Tailwind v4 tokens centralizam tudo.

React Flow

Canvas de grafo

Zustand

Estado global enxuto

Tailwind v4

Tokens centralizados

prism-react-renderer

Code viewer leve

5

🔌 understand-anything-plugin/: skills, agents, hooks, src

A pasta understand-anything-plugin/ é o "embrulho" Claude-Code. Ela junta TypeScript dos slash-commands em src/, definições de skills/, agentes em agents/ e hooks de auto-update. É o ponto de integração com o runtime.

Estrutura

understand-anything-plugin/
├── packages/
│   ├── core/          # @understand-anything/core
│   └── dashboard/     # @understand-anything/dashboard
├── src/               # TypeScript dos slash-commands
│   ├── understand-chat.ts
│   ├── understand-diff.ts
│   ├── understand-explain.ts
│   └── understand-onboard.ts
├── skills/            # Skill definitions (.md frontmatter)
├── agents/            # Agentes do pipeline
│   ├── project-scanner.md
│   ├── file-analyzer.md
│   ├── architecture-analyzer.md
│   ├── tour-builder.md
│   └── graph-reviewer.md
└── .claude-plugin/
    └── plugin.json    # Manifest Claude Code

📊 Como nasce um comando novo

  • 1. Escreve a lógica TS em src/understand-novo.ts
  • 2. Cria a skill em skills/understand-novo/SKILL.md com frontmatter
  • 3. Se precisar de pipeline, adiciona agente em agents/
  • 4. Builda com pnpm --filter @understand-anything/skill build

💡 Dica prática

Agentes omitem o campo model no frontmatter. Era model: inherit antes — mas opencode e outras ferramentas tratam isso como literal e quebram com ProviderModelNotFoundError. Sem campo, cada plataforma usa o default dela. Veja a issue #167.

src/

TS dos comandos

skills/

Definições .md

agents/

Pipeline workers

hooks/

post-commit, etc.

6

🛒 Três manifests: Claude, Cursor, Copilot

Cada runtime quer um manifesto diferente — e cada um valida coisas diferentes. O Understand Anything mantém três pastas: .claude-plugin/, .cursor-plugin/, .copilot-plugin/. Cada uma com seu plugin.json. Mas o número da versão tem que bater.

🚨 Cinco arquivos, uma versão

Quando empurra pra remote, atualize a versão em todos os cinco:

  • • understand-anything-plugin/package.json
  • • understand-anything-plugin/.claude-plugin/plugin.json
  • • .claude-plugin/plugin.json
  • • .cursor-plugin/plugin.json
  • • .copilot-plugin/plugin.json

Cuidado: .claude-plugin/marketplace.json NÃO tem campo version. Adicionar quebra a validação do marketplace.

✓ Auto-discovery

  • Cursor: detecta .cursor-plugin/plugin.json ao abrir o repo
  • VS Code + Copilot (v1.108+): mesma ideia via .copilot-plugin/
  • Sem instalação manual no fluxo padrão

📦 Instalação explícita

  • Claude Code: /plugin install understand-anything
  • Codex/OpenCode/etc: install.sh codex
  • Copilot CLI: copilot plugin install ...

3 manifests

Mesmo plugin, runtimes diferentes

5 versões

Sincronizadas em cada release

marketplace.json

Sem version (schema strict)

install.sh

12 plataformas suportadas

📋 Resumo do Módulo

Monorepo via pnpm workspaces — três pacotes, um grafo de deps, builds com filter.
Core é a engine neutra — types, schema, search, tours. Sem framework.
Subpath exports protegem o dashboard — use /types, /schema, /search.
Dashboard é graph-first — 75% grafo + sidebar 360px, dark luxury.
Plugin junta tudo — src, skills, agents, hooks num só lugar.
Três manifests, cinco versões — release exige sincronização.

Próximo Módulo:

2.2 — O pipeline de agentes e o knowledge graph