cannonball

agent
Security Audit
Warn
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 8 GitHub stars
Code Pass
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Você não começa do zero — chega com impulso. Guarda as peças de site que você já fez e as encontra de volta antes de gerar qualquer coisa outra vez. Agent Skills para Claude Code, Codex, Gemini CLI e Cursor.

README.md

cannonball

Você não começa do zero. Você já chega com impulso.

Plugin do Claude Code que guarda as peças de site que você já fez — e as encontra
de volta, antes de qualquer coisa ser gerada outra vez.

Claude Code
Python 3
9 skills
MIT


SHUI, montada a partir do acervo

Acima: uma loja de 81 produtos e 99 páginas, montada de três peças do acervo. O caso completo, com os quatro bugs que a montagem achou →

O acervo é seu, e começa quase vazio: vêm três peças de exemplo e mais nada.
Você alimenta com o que já tem — prompt, componente, efeito, design system, projeto
inteiro — e a partir daí as skills decidem a partir do que existe ali dentro, não de
uma lista fixa escrita por outra pessoa.

Nenhuma skill carrega número fixo. Todas leem o acervo na hora, então o mesmo motor
serve quem tem três peças e quem tem mil — e fica melhor a cada uma que entra.

O ciclo

ingerir  →  indexar  →  buscar  →  montar  →  registrar armadilha  →  ingerir…

Cada volta o acervo fica melhor, e as skills junto com ele. Não há número fixo em
lugar nenhum: toda skill lê o acervo na hora.

python scripts/perfil.py

É o retrato de agora — famílias, setores, stacks, cobertura por função, lacunas,
armadilhas registradas e os avisos de saúde. Toda skill começa por aí.

Instalar

Requisito único: Python 3. Os scripts importam só a biblioteca padrão — sem
pip install, sem node_modules, sem rede.

Claude Code

git clone https://github.com/harebeats/cannonball.git
cd cannonball
claude plugin marketplace add .
claude plugin install cannonball@cannonball

Codex, Gemini CLI, Cursor e os outros

A CLI do Agent Skills instala nos agentes que encontrar:

npx skills add harebeats/cannonball -g

-g instala para o seu usuário (~/.codex/skills, ~/.gemini/skills,
~/.agents/skills…); sem ele, instala no projeto atual. Para mirar um só:

npx skills add harebeats/cannonball -g -a codex
npx skills add harebeats/cannonball -g -a gemini
npx skills list harebeats/cannonball        # ver as 9 antes de instalar

Cada pasta em skills/ é autocontida — carrega o SKILL.md, o scripts/ que ele
chama, o references/ que cita e o seed/. Você pode instalar as nove ou só a que
interessa: kit-cor e kit-tipo, por exemplo, resolvem paleta e licença de fonte sem
depender de acervo nenhum.

Manual, em qualquer agente

git clone https://github.com/harebeats/cannonball.git
ln -s "$(pwd)/cannonball/skills/kit-buscar" ~/.agents/skills/kit-buscar

O símbolo mantém a instalação em dia com o seu clone. Serve para ~/.codex/skills,
~/.gemini/skills, ~/.cursor/skills — a pasta muda, o resto não.

Por que funciona igual em todos. Nenhum SKILL.md usa variável de ambiente de
agente. Cada um resolve os próprios scripts a partir da pasta de onde foi lido, o
que é informação que todo harness dá. Ver AGENTS.md.

O frontmatter fica nos seis campos da spec do Agent Skills
name, description, license, compatibility, metadata, allowed-tools.
Campo fora da spec não é ignorado lá fora: npx skills add e a Skills API falham
com erro duro
. publicar.py recusa exportar se algum escapar.

O acervo é criado em ~/.cannonball na primeira vez que uma skill roda, já com as
três peças de exemplo dentro.

O que vem na caixa

Três componentes originais, e eles existem tanto para a primeira busca devolver
alguma coisa quanto para servir de modelo de ficha bem escrita:

Peça O que resolve
kit-agendamento serviço → data/hora → contato, com expediente, duração e antecedência como configuração
kit-calendario seleção de data com teclado, idioma via Intl, disponibilidade por predicado
kit-mapa localização sem chave de API, na paleta do site por filtro CSS

Vêm com 11 armadilhas registradas — sobreposição de horário que dobra a agenda,
new Date() durante a renderização quebrando hidratação entre servidor UTC e
visitante UTC−3, iframe de mapa roubando o scroll da página. Busque por
agendamento e leia: é o formato que o resto do acervo deve seguir.

Nenhuma tem dependência npm nem asset externo. Toda a aparência sai de variável CSS
(--kit-*, com fallback nos tokens do site e, por último, currentColor), e texto e
regra de negócio saem de prop. Trocar de cliente é trocar configuração.

São suas depois de copiadas: edite, melhore ou apague. Nada volta a sobrescrever.

Vincule a sua pasta — é o primeiro passo, e o mais fácil de esquecer

Sem isso o acervo nasce em ~/.cannonball, que serve para experimentar mas quase
nunca é onde você quer o material a longo prazo. Faça antes de ingerir qualquer
coisa
— depois é mover pasta na mão.

python scripts/vincular.py --para ~/meu-acervo

O ponteiro é gravado em ~/.cannonball/aonde, fora do plugin. Isso importa: o
plugin instalado é uma cópia em cache que a próxima atualização apaga, então qualquer
configuração gravada dentro dele se perde em silêncio.

python scripts/vincular.py                    # onde está agora, e quem está mandando
python scripts/vincular.py --para <pasta> --mover   # leva junto o que já tem
python scripts/vincular.py --soltar           # volta para o padrão

Se preferir variável de ambiente, ela vence o ponteiro:
export CANNONBALL_ACERVO="/caminho/para/o/acervo".

Aponte para uma pasta versionada num repositório privado seu: o acervo é material
seu e de terceiros, e não é para redistribuir.

Por onde começar

O plugin não impõe ordem — as skills disparam sozinhas quando o assunto aparece. Mas
existe uma sequência que dá resultado muito melhor, e ela sai adaptada ao estado do
seu acervo em:

python scripts/perfil.py

Uma vez, ao instalar:

1 vincular.py --para <pasta> diga qual pasta é o seu acervo
2 /kit-ingerir encha com o que você já tem — arquivo, texto colado, projeto inteiro, registro shadcn
3 /kit-curar depois da primeira leva grande: acha ficha fraca, que é peça invisível para a busca

Em cada projeto novo:

1 /kit-buscar o que eu já tenho pra isso? Dispara sozinha antes de construir
2 /kit-cor decida a cor antes de escolher o design system
3 /kit-tipo confira a licença antes de adotar a fonte
4 /kit-montar pergunta a stack e o tipo de hero, e monta
5 /kit-otimizar-3d se tem WebGL, antes de entregar
6 /kit-ingerir guarde o que deu certo e registre a armadilha

A ordem de 2 e 3 não é preciosismo: escolher o design system primeiro faz a cor e a
fonte virem de brinde, e é exatamente assim que se chega no automático — e como se
descobre na entrega que a fonte é paga.

O passo 6 é o que fecha o ciclo. Sem ele o plugin é uma biblioteca parada; com ele,
cada projeto deixa o próximo mais rápido.

As duas que trabalham com prompt

Nem todo trabalho termina em código escrito aqui. Metade do que circula em web design
hoje é prompt — o brief que você leva ao v0, o texto que alguém te mandou no
Twitter, a spec que você guarda para reusar. Duas skills existem só para isso, e elas
são as portas de entrada e de saída do acervo.

/kit-prompt — o acervo vira prompt

Entrevista sobre o site e devolve um prompt de construção completo, no padrão dos
que já funcionaram: stack, fontes com licença conferida, paleta com contraste medido,
estrutura seção a seção, medidas exatas e proibições explícitas.

O resultado é texto. Você leva para o v0, o Lovable, o Cursor, outro modelo — ou
guarda no acervo para a próxima vez.

"gera um prompt pra uma landing de clínica"    →  o texto, pronto para levar

O que separa isso de pedir um prompt a qualquer modelo: ele é alimentado pelo seu
acervo
. A paleta sai da kit-cor com contraste já medido, a fonte sai da kit-tipo
com licença já conferida, a estrutura sai de um template que já rodou. Prompt genérico
devolve site genérico.

/kit-adaptar — o prompt de fora vira seu

O caminho inverso, e o mais subestimado. Alguém te manda um prompt em inglês, sem
contexto, que constrói sabe-se lá o quê. Esta skill lê e devolve em português:

  • que tipo de site é, e qual o escopo real (hero solto ou landing inteira)
  • seção por seção, o que cada uma faz
  • a técnica por trás (hover, cursor, scroll, WebGL, vídeo) e o que ela custa
  • stack e dependências
  • o mapa de assets — o caminho exato de cada arquivo que o prompt vai pedir

Essa última linha é a que economiza a tarde: prompt de fora sempre assume mídia que
você não tem. O que faltar vira placeholder descrito, não erro no meio do build.

Depois ela torce o prompt para o seu projeto — sua stack, seu setor, seu cliente.
Aceita print ou vídeo do site original junto, se você tiver.

[cola um prompt em inglês]  →  "o que é isso?"  →  "adapta pra clínica"

As duas funcionam com o acervo vazio. A kit-adaptar não depende de peça nenhuma,
e a kit-prompt fica melhor com acervo mas não precisa dele. São o caminho mais curto
para tirar valor do plugin no primeiro dia — e o que sair bom delas, você ingere.

O exemplo

exemplo/ — a SHUI, loja de streetwear com 81 produtos, 765
variantes e 99 páginas estáticas, montada de três peças do acervo: um template deu as
rotas e o carrinho, outro deu a ficha de produto, um design system deu a identidade.

E os quatro bugs que a montagem encontrou — SKU repetido entre tamanhos, opcao1
que não é a cor, next/link baixando doze páginas por clique, a mesma cor cadastrada
de cinco jeitos. Nenhum dá erro. Todos viraram armadilha nas peças de origem.

É o ciclo inteiro num lugar só: buscar → montar → tropeçar → registrar.

As skills

Skill Quando dispara
kit-buscar "que hero eu tenho pra clínica?" — e sozinha, antes de construir qualquer seção
kit-montar "monta uma landing pra joalheria" — do briefing ao código
kit-prompt "gera um prompt pra esse site" — do briefing ao texto, para levar ao v0, Lovable, Cursor. Detalhe ↑
kit-adaptar "o que esse prompt constrói?" — lê prompt de fora, traduz, mapeia os assets e adapta ao seu projeto. Detalhe ↑
kit-cor "define a paleta", "está tudo no automático" — decide a cor antes do design system
kit-tipo "que fonte usar", "essa fonte é paga?" — licença, substituto livre, par e escala
kit-otimizar-3d "a cena trava no celular" — e antes de entregar qualquer projeto com WebGL
kit-ingerir "guarda isso" — arquivo, texto colado, projeto inteiro, registro shadcn ou MCP
kit-curar saúde do acervo: duplicatas, fichas fracas, assets mortos

Quatro delas funcionam com o acervo vazio: kit-cor, kit-tipo,
kit-otimizar-3d e kit-adaptar não dependem de peça guardada. As outras degradam
com uma frase em vez de quebrar, e mandam você ingerir.

As famílias

Um acervo mistura naturezas diferentes, e é a natureza que decide como a peça se usa:

Família O que é Como se usa
receita composição de peças que já deu certo ponto de partida
template projeto de site completo e rodável você clona
design-system identidade visual: paleta, tipografia, regras você aplica
efeito wrapper WebGL ou objeto 3D você copia
ui componente React pronto você copia
animacao demo isolada de uma técnica você extrai
html página completa sem build abre no navegador
mcp ficha aqui, código gerado sob medida por um servidor você pede
prompt spec em linguagem natural de uma página você executa

Ordem de preferência quando mais de uma serve: receita → template → código →
prompt
. Prompt por último porque re-gera tudo e o resultado varia.

A combinação que dá o maior ganho, e a razão de o acervo existir:

template ou prompt dá a estrutura — rotas, seções, componentes.
design system dá a identidade — paleta, tipografia, espaçamento, regras.

Os dois eixos são independentes, então N templates × M identidades é um espaço de
combinação grande sem repetir visual entre clientes.

O que faz a busca funcionar

Cada peça tem quando_usar e nao_usar_quando. São eles que fazem a skill decidir
sozinha, em vez de devolver 12 heros para você escolher na mão.

nao_usar_quando fica fora do texto pesquisável de propósito: se entrasse,
buscar "mobile" ranquearia no topo justamente as peças que dizem "não use em mobile".

Ao guardar peça nova, esses dois campos são o trabalho que importa. Concreto vence
genérico: "clínica odontológica que quer destacar um procedimento" serve; "sites
modernos e bonitos"
não serve para nada. Uma peça mal descrita continua no disco e
some da busca — e some da busca é o mesmo que não ter.

Armadilhas — o ciclo que faz o acervo aprender

nao_usar_quando responde "devo escolher esta peça?". Armadilha responde outra
coisa: "escolhi — onde vou tropeçar?".

Toda montagem descobre o que não estava em documentação nenhuma. Esse conhecimento
custou caro e não pode morrer dentro da nota de um projeto:

python scripts/armadilhas.py --add luxury-hero \
  --texto "Tailwind v4: o reset '*{padding:0}' precisa ficar dentro de @layer base — solto, anula o espaçamento inteiro em silêncio" \
  --origem imobiliaria-luxo-escura --grau alta
python scripts/indexar.py

A busca imprime como ARMADILHA: e o texto entra no índice — quem procura
"contraste" acha as peças que já reprovaram.

--grau separa o que trava do que incomoda: critica (página em branco, build
falhando, dado errado gravado), alta (visual quebrado, performance no chão) e
media (ajuste fino). A busca ordena por gravidade — sem isso, a que derruba o site
sai lado a lado com a que desalinha 2px.

É o que nenhum catálogo externo tem. Catálogo descreve o que a peça faz; só o seu
acervo sabe onde ela já te derrubou.

Cor e tipografia: os dois vieses previsíveis

Todo acervo montado a partir de site real herda os mesmos dois defeitos. Os dois são
mensuráveis, e as skills medem em vez de adivinhar.

Cor — mesmice. Design system vem de marca, marca converge para neutro e azul,
tema claro. Puxar design system sem ter decidido a cor devolve o lugar-comum.

python scripts/cor.py --vies                    # de onde vem o automático
python scripts/cor.py --paleta --fundo … --tinta … --acento …
python scripts/cor.py --contraste "#767676" "#ffffff"

O script deriva 11 papéis a partir de três decisões e mede WCAG 2.x em cada par que
existe na tela — separando o que tem mínimo obrigatório do que não tem. Divisória
decorativa não precisa de 3:1, e forçá-la produz aquela borda pesada que denuncia
site feito por régua.

Tipo — fragmentação, e o problema é legal. Site de marca paga por tipo, então o
acervo enche de fonte comercial que você não pode servir. Design system nomeia a
fonte e não diz onde carregá-la; prompt de página puxa de site de redistribuição.

python scripts/tipo.py --vies
python scripts/tipo.py --licenca "Aeonik"       # comercial, CoType
python scripts/tipo.py --substituir "Roobert"   # -> General Sans
python scripts/tipo.py --par "Instrument Serif"
python scripts/tipo.py --escala --base 17 --razao 1.25

Cor é de graça; tipo não é. SF Pro é o caso que mais passa batido: está
instalada em todo Mac e a licença da Apple não permite servi-la na web.

A base de licenças (scripts/fontes_licenca.json) vem com o plugin e não depende do
acervo.

MCPs que o cannonball usa

Nenhum é obrigatório — o motor funciona sozinho. Cada um fecha um buraco distinto, e
as skills só disparam a seção correspondente quando o MCP está ligado.

MCP Para quê Livre Com cota
GetLayers composição (esqueleto de layout), background de vídeo, cena 3D nova — o que um acervo de código não tem por natureza start, search, browse, compositions, palettes, fonts, source materialize; downloadProject = 3/dia
Motion Sites catálogo de prompt de página inteira list_prompts, search_prompts, get_related_prompts get_prompt = 3 na conta sem plano
OriginKit componente gerado já na sua stack list_components, search get_component
Higgsfield imagem e vídeo do hero, quando o cliente não tem material get_cost (preflight) generate_image, generate_video — crédito real

Detalhes de cada um em references/. O Higgsfield é o único que gasta
dinheiro do usuário por chamada: higgsfield.md traz a
disciplina de custo, os modelos e o que a moderação reprova por engano.

O critério, não só as peças

O acervo responde "o que eu já tenho pra isso". Não responde "isso deveria
existir assim"
. references/fundamentos-visuais.md
cobre o segundo — o vocabulário que decide antes da peça e julga depois dela:

  • as perguntas que substituem "está bonito?" — o que isso quer que eu sinta, que eu faça, e que decisões me levaram lá
  • os cinco níveis — estética, organização, comunicação, persuasão, memória — e o teto de cada um
  • seis níveis de movimento, nove tipos de contraste, cinco usos da cor, psicologia de forma
  • seis técnicas de geração de conceito, para quando o briefing está pobre
  • sete testes executáveis, todos de minutos e sem ferramenta

Os testes são a parte que mais rende, e estão ligados como passo 7.9 da
kit-montar: o passo 8 registra o que quebrou; o 7.9 pega o que não quebra e
mesmo assim falha
. O melhor deles inverte o instinto — cubra a mensagem
principal, veja o que sobrou roubando atenção, e reduza antes de apagar.

Comandos

python scripts/perfil.py                                # o retrato de agora
python scripts/buscar.py "landing de clínica odontológica"
python scripts/buscar.py --setor joias --estrutura scroll-cinematica
python scripts/buscar.py --listar setor
python scripts/ingerir.py <arquivo> --analisar          # peça avulsa
python scripts/ingerir_projeto.py <pasta> --analisar    # projeto inteiro
python scripts/ingerir_design.py <arquivo> --analisar   # design system
python scripts/ingerir_registro.py --url <url>.json     # componente de registro shadcn
python scripts/ingerir_mcp.py --catalogo <c>.json       # catálogo servido por MCP
python scripts/lote.py <lote>.json --simular            # muitos projetos de uma vez
python scripts/receita.py criar <slug> --pecas a,b,c    # salvar uma composição
python scripts/capturar.py --tudo                       # preview das peças que rodam sozinhas
python scripts/capturar.py --url <url> --viewport 390x844 --saida <png>
python scripts/painel.py --abrir                        # o acervo com miniatura
python scripts/curar.py                                 # saúde do acervo
python scripts/curar.py --assets                        # testa as URLs externas
python scripts/curar.py --autoteste                     # checa o detector de import
python scripts/publicar.py --autoteste                  # checa a rede anti-vazamento
python scripts/indexar.py          # SEMPRE depois de ingerir ou editar ficha

indexar.py no fim não é opcional: os scripts gravam no disco, mas a busca lê
acervo/index.json. Sem reindexar, nada muda.

O preview — o acervo deixou de ser só texto

Peça que roda sozinha ganha preview.png ao lado da ficha: família html, e
animacao/template com um index.html dentro.

python scripts/capturar.py --tudo && python scripts/indexar.py
python scripts/painel.py --abrir

Usa o Chrome que já está na máquina, em headless — sem Playwright, sem dependência
nova. Aponte outro binário com CANNONBALL_CHROME.

A captura é julgada antes de ser gravada. Um PNG válido não prova nada: canvas
WebGL que não inicializou, página que não carregou e loader que nunca saiu produzem
imagem perfeita e inútil. O script mede variação de cor e brilho, e recusa com o
motivo escrito. Recusa é informação, não erro.

Componente React solto fica de fora: precisaria de build. São 159 peças capturáveis
hoje, e as 130 animações são justamente onde "como é que isso fica?" mais dói.

O mesmo script serve à revisão do passo 7.9 da /kit-montar, apontado para a página
que você acabou de construir:

python scripts/capturar.py --url http://localhost:3000 --viewport 1440x900 --saida /tmp/d.png
python scripts/capturar.py --url http://localhost:3000 --viewport 390x844  --saida /tmp/m.png

Assets pesados ficam fora

Template e animação guardam só o código. Imagem, vídeo e fonte continuam no
projeto original — o campo projeto_origem diz onde, e curar.py verifica se o
caminho ainda existe. Num template típico 99% do peso é mídia, que não cabe no git e
é trocada por material do cliente de qualquer forma.

Se a pasta de material mudar de lugar:

python scripts/relocalizar.py --verificar
python scripts/relocalizar.py --assets-de "<raiz antiga>" --assets-para "<raiz nova>"
python scripts/indexar.py

Depois de editar scripts ou skills

O plugin instalado é uma cópia. Force a atualização:

claude plugin marketplace update cannonball
claude plugin uninstall cannonball@cannonball && claude plugin install cannonball@cannonball

Coisas que mordem

  • A extensão mente. Arquivo .md contendo TSX puro é comum. A classificação é
    sempre por conteúdo, nunca por extensão.
  • @/lib/utils (a função cn) não é pacote npm, é arquivo que precisa existir no
    projeto. Quase todo componente de origem shadcn importa isso.
  • Componente de registro puxa outros. A busca imprime PRECISA JUNTO: — colar sem
    a base quebra o import, e o erro não diz que falta uma peça, diz que falta um módulo.
  • motion e framer-motion são a mesma lib com nomes diferentes. Misturar
    instala duas vezes. Padronize em motion, que é o sucessor.
  • Componente autorado em Framer convertido para Next.js deixa resíduo (shim
    RenderTarget, JSDoc @framer*, props: any) e exige Tailwind v4.
  • A peça sai do acervo por cópia, e import relativo não sabe disso. Escrito para
    o layout do acervo, ele quebra no destino com Module not found — que parece falta
    de pacote npm e não falta de peça. curar.py tem uma seção só para isso e, quando
    o alvo já está no acervo com outro id, imprime o de-para.
  • Asset em bucket temporário morre. curar.py --assets testa de verdade; a busca
    avisa ASSET MORTO na hora da escolha, não na entrega.
  • Fonte de db.onlinewebfonts.com é redistribuição de fonte comercial. Verifique
    a licença antes de entregar a cliente.

Publicar sua própria versão

O acervo é seu e não deve ir junto num repositório público — peça de terceiro,
projeto de cliente e prompt comprado não são seus para redistribuir.

python scripts/publicar.py --para ../cannonball-publico --listar
python scripts/publicar.py --para ../cannonball-publico

Exporta o motor (scripts, skills, referências) e o seed/ das três peças de exemplo,
e recusa a exportação se qualquer material privado escapar para o destino.

O que fica de fora: acervo/, _fonte/ e todo artefato de importação em massa.

Histórico

O que mudou em cada versão, e por quê: CHANGELOG.md.

Créditos

A disciplina de ficha da /kit-ingerir — mecanismo numa frase, três pilhas, regra
ancorada na falha que evita, números em vez de adjetivos — vem do
web-technique-to-skill do Meng To (MIT),
traduzida para o vocabulário do acervo. O repo dele é a metade oposta deste: acervo
curado de técnica de web design, sem motor de busca.

O §15 da /kit-otimizar-3d — depurar shader extraindo os valores internos como
pixel, em vez de mexer na constante até a imagem melhorar — vem do
shader-debugging do vgpu da
vercel-labs (MIT). O vgpu é WebGPU/WGSL e não é dependência daqui: o que foi
trazido é o método, reescrito para WebGL2/GLSL, mais a correção que ele traz sobre
captura headless no Linux.

Licença

MIT — ver LICENSE. A licença cobre o motor. O que você guardar no
acervo continua sob a licença de origem de cada peça.

Reviews (0)

No results found