Redesenhando o dashboard do argocd-vpa-sync com GitHub Copilot e Impeccable
O GitHub Copilot deixou de ser só autocomplete faz tempo. No agent mode ele lê o projeto, roda comandos no terminal e segue instruções empacotadas como Agent Skills. Uma dessas skills é o Impeccable, um conjunto de instruções e scripts de design que faz o agente trabalhar como um diretor de arte: primeiro entende o produto, depois propõe uma identidade visual e só então mexe no código. Usei essa combinação para fazer o redesign completo do dashboard do argocd-vpa-sync, e o resultado foram três temas visuais escolhidos na instalação pelo Helm.
Antes do design, vale entender o produto. O argocd-vpa-sync resolve um conflito conhecido entre o Vertical Pod Autoscaler e o Argo CD. No modo `Auto`, o VPA altera os Pods fora do Git e o Argo CD reverte. No modo `Off`, ele só registra recomendações que ninguém aplica. O argocd-vpa-sync fecha esse ciclo: a recomendação aparece num dashboard, o time revisa e seleciona as mudanças, e um worker faz o commit no values file do Helm ou no manifesto YAML. Daí o Argo CD sincroniza normalmente.
O dashboard antigo funcionava, mas tinha a cara de qualquer painel administrativo. Ele tinha tabela, cards, badges coloridos e um botão de aceitar em cada linha.
Imagem: Dashboard original do argocd-vpa-sync, com a listagem de recomendações no layout genérico de painel administrativo


A skill do Impeccable fica versionada no próprio repositório, em `.github/skills/impeccable`, junto com os agents auxiliares em `.github/agents`. O GitHub Copilot carrega skills dessa pasta, então não precisei configurar mais nada. Para conferir o que a skill oferece, basta digitar o comando sem argumento no chat do GitHub Copilot. Ele mostra o menu de comandos e sugere o próximo passo com base no estado do projeto.
text/impeccableImagem: Menu de comandos do Impeccable exibido no chat do GitHub Copilot


O primeiro comando de verdade foi o `init`. Ele não mostra temas nem gera tela nenhuma. O trabalho dele é entrevistar você sobre o produto e gravar esse contexto em um arquivo `PRODUCT.md` na raiz do projeto, que vira a fonte de verdade para todas as decisões de design seguintes.
text/impeccable initO arquivo gerado descreve quem usa o produto, o que ele faz, as restrições e os princípios que nenhum layout pode quebrar. Este é um trecho do `PRODUCT.md` do projeto:

A seção de usuários define o cenário de uso: revisão periódica, em lote, por gente que lê números de CPU e memória todos os dias. Os princípios são as regras que o redesign precisava respeitar. O mais importante é o primeiro: a interface nunca pode sugerir que altera o cluster diretamente, porque toda mudança sai como commit no Git. O arquivo também registra a terminologia que deve ser mantida (recommendation, eligible, write-back, binding, headroom) e deixa claro que não existem métricas de adoção para inventar.
Com o contexto pronto, fiz o pedido em linguagem natural.

Para o Impeccable, esse pedido é trabalho visual novo. Não é um ajuste fino sobre o visual existente, é a substituição da identidade visual inteira. Por isso a skill segue o fluxo descrito em `reference/new-work.md`, que tem uma regra rígida: nenhum código de interface pode ser escrito antes de uma direção visual ser sorteada e escolhida. O visual antigo passa a valer como evidência do que o produto é, não como referência do que ele deve virar.
O fluxo também classifica a tela por modo. Um dashboard é uma tela de Operate, em que o usuário precisa concluir uma tarefa. Nesse modo, a skill prioriza leitura rápida, consistência e padrões que o usuário já conhece, e a personalidade da marca aparece nos detalhes. O primeiro script que o GitHub Copilot rodou já recebe esse modo como parâmetro.
bash.github/skills/impeccable/scripts/impeccable concept-seed --scope direction --mode operateO `concept-seed` sorteia uma direção visual e distribui alternativas tiradas do catálogo de mundos visuais do Impeccable. A ideia do sorteio é evitar que todo redesign termine no mesmo visual padrão que modelos de linguagem tendem a gerar. O parâmetro `--scope direction` indica que está em jogo a identidade visual inteira, e não só a estrutura de uma tela. O `--mode operate` faz o script imprimir as regras desse modo, que passam a valer para todas as propostas.
Com as direções montadas, o GitHub Copilot rodou o segundo script, que sobe um servidor local com a página de decisão.
bash.github/skills/impeccable/scripts/impeccable serve-question --startA página abriu no navegador em `http://127.0.0.1:52834`, com o título "Choose the visual world for argocd-vpa-sync". Cada opção vem com paleta, materiais, descrição do primeiro viewport, o risco assumido e um mock em HTML gerado em `.impeccable/mocks/decision/`. Dali dá para manter a direção sorteada, escolher outra ou pedir um novo sorteio, mais conservador ou mais ousado.
Imagem: Página de decisão do Impeccable no navegador com as três opções principais lado a lado

A primeira das três opções principais foi The Fitting Room, a direção sorteada. Ela usa o universo da alfaiataria: cada container é "medido" contra uma fita métrica, e as mudanças saem para o Git como uma ordem de ajuste. A paleta combina uma barra superior em carvão (`#23262B`), amarelo de fita métrica (`#F2C230`) como destaque e azul giz (`#3B6FB6`) para a recomendação. O risco que o próprio Impeccable apontou foi a metáfora vazar para os textos, então todo rótulo continua em termos de VPA e GitOps.

A segunda foi Calibration Certificate, a escolha recomendada pelo Impeccable. Cada container aparece como um instrumento num certificado de calibração de laboratório de metrologia: valor medido, valor nominal, faixa de tolerância e um veredito IN ou OUT. A seleção de mudanças vira um certificado com a prévia do commit. O risco declarado era a familiaridade, já que essa é a opção mais parecida com outros dashboards da categoria.

O Terceiro foi o padrão da categoria, a saída que o fluxo sempre oferece. É um console administrativo de Kubernetes no estilo do Argo CD ou do Kubecost, bem executado: barra lateral, tabela limpa, status em pills, fundo branco e azul `#2563EB`. O Impeccable nunca recomenda essa opção. Ela existe para que você sempre tenha uma saída segura.
Dark:

Light:

As outras cinco alternativas do catálogo apareceram rebaixadas, em tamanho menor: Labanotation Score (notação de dança), Lexicon Page (dicionário do século XIX), Design Annual Plates, Crouwel Grid Specimen e Vertical Feed. Cada uma veio com o motivo da recusa, quase sempre por esconder a tabela ou atrapalhar a revisão em lote. O detalhe interessante é que cada recusada deixou uma ideia para a direção sorteada. Da notação de dança veio a regra de indicar a direção da mudança pela forma da marca e a elegibilidade pelo preenchimento, nunca só pela cor. Do dicionário veio a linha-guia que mostra a faixa de namespaces visível durante o scroll. Do feed vertical veio a navegação com j/k entre os containers elegíveis na tela de detalhe.
Imagem: Alternativas recusadas do catálogo exibidas em tamanho reduzido abaixo das opções principais

Em vez de escolher uma única direção, optei por três temas, definidos na instalação: The Fitting Room, Calibration Certificate e o padrão da categoria. O Impeccable registrou essa decisão como um contrato de direção no brief da tela, em `.impeccable/surfaces/web-src-app-tsx.md`, antes de qualquer código.
Constraints: the user chose THREE install-time themes instead of one world, selected via Helm `theme` (`default` | `fitting-room` | `calibration`). Same routes, components and behavior in all three; themes differ in type, palette, density, shell placement and signature move only. Light grounds (office daylight). Copy stays in VPA/GitOps terms. No invented capabilities (no export, no rescan, no PR flow).
Removed on purpose: Table/Cards toggle (table only), per-row Accept buttons (the selection panel is the single apply path).Esse contrato é a parte que mais me surpreendeu no fluxo. Ele trava o que os temas podem mudar (tipografia, paleta, densidade, posição do shell e o elemento visual característico de cada um) e o que precisa ser igual (rotas, componentes e comportamento). Ele também registra o que foi removido de propósito. A visualização em cards e os botões de aceitar por linha saíram, e a fila de write-back virou o único caminho para aplicar mudanças, o que reforça o princípio de revisão em lote do `PRODUCT.md`.
Na implementação, o GitHub Copilot criou o módulo `web/src/theme.ts`, que concentra os temas disponíveis e decide qual renderizar.
export const THEMES = ['default', 'fitting-room', 'calibration'] as const
export type Theme = (typeof THEMES)[number]
export const DEFAULT_THEME: Theme = 'fitting-room'
export function isTheme(value: unknown): value is Theme {
return typeof value === 'string' && (THEMES as readonly string[]).includes(value)
}
export function resolveTheme(serverTheme: unknown): Theme {
if (import.meta.env.DEV) {
const override = new URLSearchParams(window.location.search).get('theme')
if (isTheme(override)) return override
}
return isTheme(serverTheme) ? serverTheme : DEFAULT_THEME
}
export function applyTheme(theme: Theme): void {
document.documentElement.dataset.theme = theme
}**isTheme()**Valida se um valor qualquer é um dos três temas conhecidos e funciona como type guard para o TypeScript.
**resolveTheme()**Usa o tema enviado pelo servidor e cai no `fitting-room` quando o valor está ausente ou é inválido. Em desenvolvimento, aceita `?theme=<nome>` na URL para visualizar qualquer tema sem redeploy.
**applyTheme()**Grava o tema no atributo `data-theme` do elemento raiz, que é onde o CSS se apoia.
Cada tema é um bloco de CSS Custom Properties em `web/src/index.css`, sob o seletor `[data-theme]`. Os componentes só consomem os tokens, então a mesma marcação React muda de identidade sem nenhuma condição no JSX. Este é um trecho do bloco do The Fitting Room:
:root[data-theme='fitting-room'] {
--bg: #f6f7f5;
--surface: #ffffff;
--ink: #1d1f23;
--line: #d9dcd6;
--accent: #f2c230;
--accent-hover: #e3b11c;
--rec: #3b6fb6;
--band: #dcdfd9;
--shell-bg: #23262b;
--font: 'Archivo Variable', 'Arial Narrow', system-ui, sans-serif;
--radius: 0px;
--label-case: uppercase;
--label-tracking: 0.08em;
}Os valores saem direto da proposta escolhida na página de decisão: fundo off-white, amarelo de fita métrica como destaque, azul giz para a recomendação e barra superior em carvão. O `--radius: 0px` e os rótulos em caixa alta aplicam a regra de cantos retos e linhas finas que veio da alternativa Design Annual Plates. As fontes são servidas localmente pelo Fontsource, sem depender de CDN.
O elemento que mais diferencia os temas é a forma de desenhar uma recomendação de CPU ou memória. No tema padrão, ela é um badge com a variação percentual. No The Fitting Room, vira uma fita métrica. No Calibration Certificate, vira uma barra de tolerância com veredito IN/OUT. As duas últimas compartilham o mesmo componente `Gauge`, em `web/src/components/ResourceReading.tsx`.
function Gauge({ geo, eligible, label }: GaugeProps) {
const direction = geo.target > geo.current ? 'up' : geo.target < geo.current ? 'down' : 'flat'
const moveLeft = Math.min(geo.current, geo.target)
const moveWidth = Math.abs(geo.target - geo.current)
return (
<span
className={`gauge gauge-${direction}${eligible ? ' gauge-eligible' : ''}${geo.outOfBand ? ' gauge-out' : ''}`}
role="img"
aria-label={label}
>
<span className="gauge-scale" />
{geo.band && <span className="gauge-band" style={{ left: `${geo.band.left}%`, width: `${geo.band.width}%` }} />}
{direction !== 'flat' && (
<span className="gauge-move" style={{ left: `${moveLeft}%`, width: `${moveWidth}%` }} />
)}
<span className="gauge-target" style={{ left: `${geo.target}%` }} />
<span className="gauge-current" style={{ left: `${geo.current}%` }} />
</span>
)
}
**Gauge()**Desenha numa mesma escala a faixa do VPA (`lowerBound` a `upperBound`), o request atual como um traço e o deslocamento até a recomendação como uma barra com seta. A direção é codificada na forma (`gauge-up` ou `gauge-down`) e a elegibilidade no preenchimento sólido ou hachurado (`gauge-eligible`), seguindo a regra de não depender só de cor. O `aria-label` descreve os valores em texto para leitores de tela.
No backend, o tema vem da variável de ambiente `DASHBOARD_THEME`, validada no carregamento da configuração em `internal/config/config.go`.
if v := os.Getenv("DASHBOARD_THEME"); v != "" {
if !slices.Contains(Themes, v) {
return Config{}, fmt.Errorf("config: DASHBOARD_THEME must be one of %v, got %q", Themes, v)
}
cfg.Theme = v
}Um valor desconhecido derruba a inicialização com uma mensagem clara, em vez de cair silenciosamente num tema padrão. O tema vai para o frontend junto com a resposta de `userinfo`, que não exige autenticação, então até a tela de login já aparece no tema certo.
Para quem instala, o tema é só um valor no `values.yaml` do chart. O comando abaixo troca o tema de uma instalação existente, mantendo os outros valores, e o novo Pod já serve o visual escolhido.
helm upgrade argocd-vpa-sync oci://registry-1.docker.io/azurebrasil/argocd-vpa-sync \
--namespace argocd --reuse-values \
--set theme=calibrationO The Fitting Room acabou virando o tema padrão. A barra superior em carvão, as tabelas sem bordas arredondadas e a fita métrica em cada célula de CPU e memória deixam visível, numa olhada, quanto a recomendação se afasta do request atual e se ela cai fora da faixa do VPA.
Imagem: Dashboard no tema The Fitting Room, com a barra carvão, as fitas métricas nas colunas de CPU e memória e a fila de write-back à direita

O Calibration Certificate traz uma faixa de cabeçalho com o resumo do cluster (bindings, elegíveis, write-backs com falha e último commit). Cada célula mostra a barra de tolerância com o veredito IN/OUT, e a fila de write-back exibe a prévia do diff que será commitado no values file.
Imagem: Dashboard no tema Calibration Certificate, com o cabeçalho de resumo, os vereditos IN/OUT e a prévia do diff na fila

O tema `default` é o padrão da categoria bem feito: barra lateral, destaque azul, badges de variação e modo claro ou escuro escolhido por cada usuário no navegador.
Imagem: Dashboard no tema default, com barra lateral e badges de variação percentual

No fim, o Impeccable fecha o ciclo com o agent `impeccable-documenter`, que gera o `DESIGN.md` a partir do que foi construído e não das intenções iniciais. O arquivo registra os tokens de cor e tipografia dos três temas e serve de referência para qualquer ajuste futuro. Essa ordem importa: um guia escrito antes da implementação acaba sendo defendido contra a realidade, enquanto um guia extraído do código pronto descreve o que de fato existe.
O processo funciona igual em outra aplicação ou em outra tela. Basta digitar `/impeccable` seguido do pedido em linguagem natural, como `/impeccable redesenhe a tela de login`. Se você quiser planejar a experiência antes de gerar código, use `/impeccable shape <tela>`, que conduz a descoberta da tarefa e só entra no fluxo de direção visual quando necessário. E se não lembrar o comando, `/impeccable` sem argumento mostra o menu.
Para mim, o ganho dessa combinação não foi o GitHub Copilot escrever CSS mais rápido. Foi a ordem imposta pelo Impeccable: primeiro o contexto do produto, depois uma escolha visual explícita entre alternativas com riscos declarados, e só então o código.
Você já pode baixar o projeto por esse link, e não esquece de me seguir no LinkedIn!
Links & Docs:





Até a próxima, abraços!





