O que show-n-tell faz?
Você orquestra um pipeline completo que transforma qualquer site + logotipo + um pouco de intenção em um vídeo de demonstração narrado e com marca, de 5 minutos. Os scripts em scripts/ são canos burros; você é o maestro.
Documentos de referência nesta pasta: docs/SCHEMAS.md (gramática YAML + ações), docs/GOTCHAS.md (problemas conhecidos + soluções alternativas), docs/CONTEXT.md (“como é uma boa saída”), examples/halyard-spme/ (exemplo completo canônico). Leia-os conforme necessário — não os pré-carregue.
Quando usar esta skill
- O usuário quer um vídeo de demonstração narrado de um site (ao vivo, dev local ou estático).
- O usuário tem pelo menos uma orientação leve de intenção (“mostre X, Y, Z” / “demonstre o fluxo do painel”).
- O usuário tem acesso a um logotipo ou marca nominativa.
Recuse-se a prosseguir se o usuário não fornecer notas de intenção nem um logotipo. Demonstrações genéricas com marca padrão são demonstrações ruins. Peça orientação em vez de produzir silenciosamente um vídeo fraco.
Detecção de ambiente (leia antes de começar)
Antes de fazer qualquer coisa, determine em qual ambiente o Claude está sendo executado:
- Cowork:
mcp__cowork__list_artifactsemcp__computer-use__screenshotestão disponíveis na lista de ferramentas do Claude. - Claude Code CLI: essas ferramentas estão ausentes.
Isso é importante porque várias fases se comportam de forma diferente entre ambientes. Referência rápida:
| Fase | Claude Code CLI | Cowork |
|---|---|---|
| Diretório de trabalho (Fase 5) | ~/demo-videos/<slug>/ | request_cowork_directory fornece o caminho |
| Exploração do site pública (Fase 2b) | Ferramentas Playwright MCP | Ferramentas Chrome MCP ou explore_page.py headless |
| Captura de autenticação OAuth (Fase 2a) | Executar capture_auth.py via Bash | Usuário executa capture_auth.py localmente |
| Comandos longos (Fases 7–9) | Executar de forma síncrona | nohup + poll (timeout de 45s do bash) |
| Entrega (Fase 11) | Relatar caminho do mp4 | Caminho do mp4 + link computer:// |
Fase 1 — Entrevista (coletar entradas)
Faça uma ou duas perguntas de cada vez, não todas de uma vez. Obrigatório:
- URL alvo — confirme que está acessível.
- Notas de intenção da demonstração — que história ela conta? Quais recursos são importantes?
- Público + tom — interno/externo/investidores; explicativo/vendas/técnico/casual.
- Duração alvo — padrão 5 min.
- Logotipo — URL ou caminho. Se apenas texto estiver disponível, sinalize a limitação, mas aceite.
- Cores da marca — primária (tinta) + destaque. Se não forem especificadas, infira a partir do logotipo com PIL.
- Autenticação? — o site exige login?
- Não → prossiga.
- Sim, baseado em formulário (o site tem seus próprios campos de e-mail/senha que você controla) → use
session.pre_sessionemdemo_config.yaml. Colete os nomes das variáveis de ambiente de credenciais (NÃO os valores reais) e a URL/seletores de login. Diga ao usuário para colocar as credenciais reais no<working_dir>/.envantes de executar, nunca no chat. Vejaexamples/login-flow/. - Sim, OAuth / SSO / magic-link / passkey (Google, Microsoft, Okta, etc.) → use
session.storage_state. O usuário NÃO executa nenhum comando. VOCÊ iniciahelpers/capture_auth.pypara eles na Fase 2a, e eles só fazem login interativamente na janela do navegador que abrir. Oauth.jsoncapturado é então usado tanto para a exploração da Fase 2b quanto para a gravação da Fase 8. Vejaexamples/oauth-storage-state/.
Fase 2a — Captura de autenticação (apenas OAuth)
Pule esta fase completamente se a pergunta 7 da Fase 1 resultou em "sem autenticação" ou "baseado em formulário". Para OAuth / SSO / magic-link / passkey, capture uma sessão autenticada AGORA, antes da exploração do site — a Fase 2b precisa dela para visualizar páginas autenticadas.
mkdir -p ~/demo-videos/<demo-slug>/
uv run helpers/capture_auth.py <login_ou_url_inicial> \
--out ~/demo-videos/<demo-slug>/auth.json \
--viewport <recording.viewport do demo_config.yaml; padrão 1440x900>
Execute isso via ferramenta Bash com timeout: 600000 (10 minutos — o máximo). O script abre uma janela Chromium com cabeçalho. Diga ao usuário em palavras claras:
"Estou abrindo uma janela do navegador para você fazer login. Complete o login (Google, Microsoft, etc., lide com 2FA), navegue até a página de onde você quer que a gravação comece e feche a janela do navegador. Vou salvar a sessão e continuar automaticamente."
O script escreve auth.json com modo 0600 atomicamente. Se o usuário demorar mais de 10 minutos (raro, mas possível com 2FA baseada em telefone em outra sala), o timeout do Bash é acionado — basta reexecutar o mesmo comando.
--viewport DEVE corresponder a recording.viewport em demo_config.yaml. Alguns sites identificam o tamanho da viewport; a incompatibilidade pode invalidar a sessão capturada no momento da gravação ou exploração.
Se o Chromium do Playwright ainda não estiver instalado (clone recente da skill), o script gera um erro acionável. Execute uv run --with playwright playwright install chromium uma vez.
Se estiver executando no Claude Code CLI: execute capture_auth.py via Bash conforme descrito acima.
Se estiver executando no Cowork: o Claude lida com isso diretamente usando as ferramentas de computer-use e Chrome — o usuário só precisa fazer login quando o navegador abrir. Etapas:
-
Certifique-se de que o caminho do diretório de trabalho é conhecido. Se a Fase 5 ainda não foi executada, chame
mcp__cowork__request_cowork_directoryagora para obter o caminho das saídas e definir<working_dir>como<outputs_path>/<demo-slug>/. -
Abra o Chrome na área de trabalho do usuário:
mcp__computer-use__open_application → "Google Chrome" (ou "Chrome") -
Navegue até a URL de login. Prefira o Chrome MCP se estiver conectado:
- Extensão do Chrome disponível:
mcp__Claude_in_Chrome__navigatepara<login_ou_url_inicial> - Extensão do Chrome não conectada: use as ferramentas
mcp__computer-use__*para clicar na barra de endereços e digitar a URL
- Extensão do Chrome disponível:
-
Diga ao usuário para fazer login — diga em palavras claras:
"O Chrome está aberto na página de login. Por favor, faça login (lide com qualquer 2FA, SSO, etc.), então navegue até a página onde a gravação deve começar. Avise-me quando terminar."
-
Aguarde e observe. Faça polling com
mcp__computer-use__screenshota cada ~15 segundos. Continue quando a URL não for mais uma página de login/auth e um painel ou página de aplicativo estiver visível. -
Extraia o estado da sessão via JavaScript. Execute este snippet com
mcp__Claude_in_Chrome__javascript_tool:(() => { const cookies = document.cookie.split(';').map(c => { const [name, ...rest] = c.trim().split('='); return { name: name.trim(), value: rest.join('='), domain: location.hostname, path: '/', expires: -1, httpOnly: false, secure: location.protocol === 'https:', sameSite: 'Lax' }; }).filter(c => c.name); const ls = {}; for (let i = 0; i < localStorage.length; i++) { const k = localStorage.key(i); ls[k] = localStorage.getItem(k); } const ss = {}; for (let i = 0; i < sessionStorage.length; i++) { const k = sessionStorage.key(i); ss[k] = sessionStorage.getItem(k); } return JSON.stringify({ cookies, origins: [{ origin: location.origin, localStorage: Object.entries(ls).map(([n,v]) => ({name:n,value:v})), sessionStorage: Object.entries(ss).map(([n,v]) => ({name:n,value:v})) }] }, null, 2); })() -
Escreva o resultado em
<working_dir>/auth.jsonusando a ferramenta Write. Este é o formatostorage_stateválido do Playwright —helpers/explore_page.pyerecord_demo.pyambos o consomem viabrowser.new_context(storage_state=...). -
Ressalva sobre cookies HttpOnly. JavaScript não pode ler cookies HttpOnly — eles são intencionalmente invisíveis para
document.cookie. Se o token de sessão do site for apenas HttpOnly (comum em cookies de sessão de Rails/Django mais antigos), o estado extraído estará faltando. Diga ao usuário:"Nota: cookies de sessão marcados como HttpOnly não são acessíveis pelo JavaScript, então posso não ter capturado todos os tokens de autenticação. A gravação tentará usar o que foi capturado — se encontrar uma parede de login durante a Fase 8, podemos recorrer ao uso de
capture_auth.pylocalmente." Em seguida, continue — muitos sites modernos (Google, Microsoft, Okta) mantêm estado suficiente em cookies não HttpOnly ou localStorage para o Playwright funcionar.
Fase 2b — Exploração do site
Se a Fase 2a foi executada (auth.json existe), use helpers/explore_page.py para visualizar páginas autenticadas — o Playwright MCP não pode carregar storage_state e apenas veria paredes de login. Para demos sem autenticação, o Playwright MCP é bom e mais interativo; use-o como antes.
Para páginas autenticadas:
mkdir -p ~/demo-videos/<demo-slug>/_explore/
uv run helpers/explore_page.py https://target.example.com/dashboard \
--storage-state ~/demo-videos/<demo-slug>/auth.json \
--out-dir ~/demo-videos/<demo-slug>/_explore/
Isso escreve três arquivos por página em _explore/: <slug>.png (captura de tela), <slug>.dom.html (DOM para seleção de seletores), <slug>.meta.json ({url_solicitada, url_final, título, status}). Leia o PNG com a ferramenta Read para ver a página; use grep no DOM para seletores. Se final_url no meta.json apontar para uma página de login, a sessão expirou — execute novamente a Fase 2a.
Para páginas públicas (página inicial, páginas de marketing em qualquer demo; tudo em uma demo sem autenticação) — use as ferramentas Playwright MCP (mcp__plugin_playwright_playwright__*) como antes:
browser_navigatepara a URL alvo e, em seguida, para 2–5 páginas que a intenção do usuário menciona.browser_snapshotoubrowser_take_screenshotpara ver o layout de cada página.- Use
browser_evaluatepara ler o DOM em busca de seletores estáveis (prefira semântica em vez denth-of-typequando possível).
Se estiver executando no Claude Code CLI: use as ferramentas mcp__plugin_playwright_playwright__* conforme descrito acima.
Se estiver executando no Cowork: Primeiro, certifique-se de que o Chromium está