O que Gravar e Reproduzir (navegador + desktop) faz?
Gravar e Reproduzir permite que um agente aprenda um fluxo de trabalho demonstrado pelo usuário e o transforme em uma habilidade reutilizável. Dois modos:
- Modo navegador (padrão, evidência mais rica): um navegador Playwright com cabeçalho (Google Chrome do sistema, se disponível) grava cada ação do usuário em
events.jsonlcom múltiplos candidatos a seletor, além de chunks de trace do Playwright (trace-NNN.zip). Funciona no macOS, Windows e Linux. - Modo desktop (aplicativos nativos): um gravador leve de processo único (pynput) captura eventos globais de mouse/teclado, alterações de janela ativa, capturas de tela no momento do clique e o alvo de acessibilidade de cada clique (macOS AX, Windows UI Automation) em
desktop-events.jsonl+screens/, com campos de senha mascarados — paridade com Codex (Codex também grava um fluxo de eventos/contexto, não vídeo), ~1-3% de CPU. Funciona no macOS, Windows e Linux (X11). Veja "Gravação de desktop" abaixo.
Escolha o modo navegador sempre que o fluxo de trabalho for apenas no navegador — seus seletores semânticos produzem habilidades muito melhores do que as coordenadas do desktop.
Configuração (uma vez)
cd ~/.agents/skills/record-and-replay
node setup.mjs # npm install + (Chromium apenas se Chrome estiver faltando) + autotestes
node install.mjs # link para diretórios de habilidades do agente (symlink no macOS/Linux, junction no Windows)
Instala o pacote npm playwright. Os navegadores NÃO são baixados quando o Google Chrome está instalado (o gravador usa channel: 'chrome'); caso contrário, o script baixa o Chromium. Ambos os scripts são multiplataforma (Node).
Fluxo de Trabalho de Gravação
-
Antes de começar, diga ao usuário para fechar janelas, arquivos e conversas que ele não deseja capturar, e para não digitar segredos que não gostaria de armazenar. Inicie o gravador em segundo plano e separado somente quando o usuário estiver pronto para começar. Sempre passe
--name <slug>para que o diretório de saída seja conhecido de antemão:cd ~/.agents/skills/record-and-replay # macOS / Linux: nohup node scripts/recorder.mjs --minutes 30 --name <slug> [--url <startUrl>] \ > ~/.agents/recordings/recorder.log 2>&1 & # Windows (PowerShell): Start-Process node -WindowStyle Hidden -ArgumentList "scripts/recorder.mjs","--minutes","30","--name","<slug>"Agentes com uma facilidade nativa de execução em segundo plano (por exemplo,
run_in_backgrounddo Bash do Claude Code) podem usá-la. As saídas vão para~/.agents/recordings/<slug>/. -
Verifique a inicialização uma vez (~2-3 segundos após o lançamento — uma única verificação, não um loop de polling): confirme se
~/.agents/recordings/<slug>/session.jsonexiste com"status": "recording"(o gravador também imprime uma linha{"status":"recording",...}no log em caso de sucesso). Se a verificação falhar, leia o log:recording_already_active(código de saída 2) significa que outra gravação detém o bloqueio;launch_failedou um erro de módulo ausente significa que a configuração é necessária. Relate o problema real em vez de dizer ao usuário que a gravação começou. -
Após a verificação de inicialização, não durma, faça polling ou espere em um loop. Termine seu turno: diga ao usuário que a gravação começou, qual é o limite de tempo e que uma pequena janela de controle flutuante (canto inferior direito, como os controles de gravação do Codex) tem um timer e botões de Pausar/Retomar, Parar e Descartar (toque duas vezes para confirmar). Nada é capturado enquanto pausado — eventos e trace param. Se ele fechar a janela de controle acidentalmente, ela se reabre sozinha; fechar a janela principal do navegador também encerra a sessão (evite sair completamente do navegador com Cmd+Q, o que pode perder o último minuto do trace). Passe
--badgeno início para usar um emblema na página em vez da janela de controle (fallback para ambientes exóticos). -
Pausar/retomar (o usuário pede para você pausar, ou você precisa pular um trecho confidencial):
touch ~/.agents/recordings/<slug>/PAUSEpausa em 2 segundos; exclua o arquivo para retomar. Os botões da janela de controle e o arquivo PAUSE permanecem sincronizados;session.jsoncarrega o estadopausedatual. Os intervalos pausados aparecem como marcadorespaused/resumedemevents.jsonle estão ausentes do trace. -
Quando o usuário disser que terminou:
- Se o processo ainda estiver em execução, pare-o normalmente:
touch ~/.agents/recordings/<slug>/STOP(o gravador percebe em 2 segundos e finaliza). - Leia
session.json—status: "recording"significa que ainda está ativo;"completed"significa que as saídas são finais;"discarded"significa que o usuário pressionou Descartar — os arquivos de evidência foram excluídos, reconheça e NUNCA crie uma habilidade a partir disso.endReasoné um dos seguintes:user_stopped,user_discarded,browser_closed,stop_file,time_limit,signal,event_limit. - Inspecione os eventos capturados antes de responder: execute
node scripts/summarize.mjs <outDir>para uma linha do tempo compacta, depois leiaevents.jsonldiretamente para as etapas que precisam de detalhes.
- Se o processo ainda estiver em execução, pare-o normalmente:
-
O cancelamento é definido pelo conteúdo, não pelo endReason: se a gravação contiver poucos ou nenhum evento
kind: "dom"— seja qual for o endReason —, trate-a como cancelada. Reconheça, não crie ou atualize uma habilidade. -
Se a gravação contiver informações suficientes para identificar um fluxo de trabalho reutilizável, crie ou refine uma habilidade para ele por padrão — mesmo que o usuário não tenha pedido explicitamente. Não pare após produzir apenas um resumo ou um plano de reprodução. Siga "Criando Habilidades a partir de uma Gravação" abaixo — começa com uma breve rodada de esclarecimento.
-
Se a gravação for muito escassa ou ambígua para identificar o fluxo de trabalho, não adivinhe. Explique o que não está claro e pergunte ao usuário pelas peças faltantes.
Gravação concorrente
Apenas uma gravação pode estar ativa por vez (arquivo de bloqueio ~/.agents/recordings/.lock). Se o gravador sair com recording_already_active, não force o início de outra; diga ao usuário que uma gravação já está em andamento e pergunte se deseja usá-la ou interrompê-la primeiro. Reiniciar com o mesmo --name é seguro: o events.jsonl anterior é preservado como .bak com carimbo de data/hora, não anexado.
Interpretando Eventos
events.jsonl é a evidência primária; session.json fornece apenas tempo/caminhos; os chunks trace-NNN.zip são a verdade fundamental no nível do DOM (npx playwright show-trace <outDir>/trace-*.zip; traceChunks do session.json os lista em ordem). O trace padrão é o modo leve — snapshots completos do DOM por ação, mas sem capturas contínuas de tela (mantém a CPU baixa). Comece com --trace full quando o usuário quiser evidências visuais perfeitas, ou --trace off para a pegada mínima absoluta.
Cada linha é um evento: {seq, t (ms desde o início), kind, type, url, ...}.
kind: "page"— navegações, downloads, diálogos, aberturas/fechamentos de abas. Navegações segmentam o fluxo de trabalho em estágios.kind: "dom"— ações do usuário.target.selectorscarrega múltiplos candidatos a seletor:testId,role({role, name}),id,nameAttr,text,css. Prefira-os nessa ordem ao gerar código de reprodução;cssé o último recurso.- Eventos
type: "input"são debounced — um evento por campo com o valor final (liberado no blur, Enter, change e envio de formulário). Campos do tipo senha/cartão de crédito/OTP (nomes em inglês e turco: password, parola, şifre, kart, kimlik…) chegam pré-mascarados (***MASKED***,masked: true). - Eventos
selectionecopyrevelam qual conteúdo o usuário estava manipulando — geralmente a melhor pista quando o usuário se refere a "isso" ou "a coisa que selecionei". Seleções com aparência de segredo (OTPs, chaves de API, tokens) são mascaradas. Eventospastecarregam apenas comprimento/contagem de palavras, nunca conteúdo. - Dados confidenciais: o mascaramento é heurístico, não uma garantia — e se aplica apenas a
events.jsonl. Os chunks de trace NÃO são mascarados: snapshots do DOM contêm valores de entrada brutos (incluindo valores mascarados no JSONL) e capturas de tela capturam tudo visível na tela (tokens revelados, códigos 2FA, saldos). Trate todo o diretório~/.agents/recordings/<name>/como confidencial: inspecione-o localmente apenas, nunca o carregue ou faça commit, e nunca cite segredos literais dele em resumos ou habilidades geradas — use placeholders ou descrições genéricas.
Criando Habilidades a partir de uma Gravação
Leia references/skill-authoring.md antes de escrever: ele contém o banco de perguntas, os limites do frontmatter, o esqueleto do SKILL.md, as regras para scripts empacotados e a lista de verificação de qualidade. Se uma habilidade skill-creator estiver disponível em seu ambiente, suas orientações também se aplicam. Crie uma habilidade descoberta real (uma pasta SKILL.md), não apenas um runbook Markdown.
Copie esta lista de verificação e marque os itens:
- [ ] 1. Resuma a gravação; anote cada lacuna (decisões, trechos mascarados, pontos cegos)
- [ ] 2. Esclareça: uma mensagem, no máximo 6 perguntas, apenas sobre as lacunas
- [ ] 3. Verifique se existe uma habilidade existente que cubra este fluxo de trabalho → atualize-a em vez de duplicar
- [ ] 4. Escreva a habilidade + evals/evals.json (a gravação é o caso de teste 1)
- [ ] 5. Valide: node scripts/export-skill.mjs <skillDir> --check → corrija erros, reexecute
- [ ] 6. Ofereça a verificação do gatilho + uma execução seca; incorpore correções, aumente metadata.version
- [ ] 7. Ofereça a exportação ZIP para claude.ai
Etapa 2 — esclareça antes de escrever. Não há áudio: a gravação mostra o que aconteceu, não por quê. Responda a partir da gravação o que ela mostra, depois pergunte ao usuário — uma vez, em uma única mensagem, no máximo 6 perguntas — sobre o que ela não pode: o resultado e como saber se funcionou, quais valores variam entre execuções, por que eles escolheram X em um determinado momento, quais ações foram desvios, o que eles diriam para acionar a habilidade (e o que não deveria), e quais ações precisam de confirmação. Cite o momento a que se refere ("às 02:14 você limpou o filtro de data — por quê?"). Use sua ferramenta de perguntas estruturadas se tiver uma; chat simples caso contrário. Pule a rodada apenas quando a gravação mais o pedido do usuário já responderem tudo, e diga isso.
Regras de escrita:
- Trate a gravação como evidência do resultado pretendido pelo usuário, não como um script para reproduzir pixel por pixel. Se um conector/API/CLI/ferramenta MCP puder alcançar o mesmo resultado semanticamente (criar um evento de calendário, abrir um PR, postar uma mensagem), prefira-o em vez da automação de interface do usuário.
- Quando a reprodução da interface do usuário for genuinamente necessária, gere um script Playwright a partir de
scripts/replay-template.mjs: localizadores semânticos (getByTestId>getByRole>getByLabel>getByText), uma etapa de verificação após cada ação crítica, segredos de variáveis de ambiente. Nunca use coordenadas brutas, a menos que o fluxo de eventos não ofereça um alvo melhor. - Etapas de desktop nomeiam o alvo capturado (função + nome + janela, por exemplo, Botão "Salvar" em "Fatura — Acme") para que uma ferramenta de árvore de acessibilidade possa encontrá-lo; coordenadas apenas quando nenhum alvo foi capturado.
- O perfil persistente do gravador (
~/.agents/recordings/.browser-profile) mantém logins entre sessões, portanto as habilidades geradas geralmente não precisam de etapas de login. Segurança: esse diretório contém material de sessão autenticado ativo (cookies/localStorage; o Playwright inicia o Chrome com um chaveiro simulado, portanto trate-o como credenciais de texto simples). Nunca faça commit, compartilhe ou faça backup não criptografado — e lembre-se de que qualquer habilidade de reprodução que o reutilize é executada com os logins do usuário. Para gravações em sites não confiáveis ou de alta confidencialidade, prefira um perfil descartável (--outmais um perfil temporário) ou limpe o perfil depois. - Salve novas habilidades em
~/.agents/skills/<skill-name>/(nome da pasta =name, em kebab-case) e crie links simbólicos nos diretórios de habilidades do agente (vejainstall.mjspara o padrão) para que todos os agentes nesta máquina possam usá-las. - Parametrize o que varia (datas, valores, nomes) e codifique o que não varia. Declare o propósito do fluxo de trabalho e os critérios de verificação no SKILL.md gerado. Nunca copie segredos ou valores mascarados para a habilidade.
Exportar para claude.ai (ofereça; execute sob demanda): node scripts/export-skill.mjs ~/.agents/skills/<name> grava ~/.agents/exports/<name>.zip (pasta na raiz do ZIP; README, evals, caches e evidências de gravação são deixados de fora; o arquivo é lido de volta antes do sucesso). Se a habilidade usar frontmatter exclusivo do Claude Code (disable-model-invocation, …), adicione --strip-cc-keys. Diga ao usuário onde o arquivo está e que ele é enviado em Personalizar › Habilidades › + › Carregar uma habilidade (a execução de código deve estar ativada).
Gravação de desktop (macOS, Windows, Linux/X11)
Configuração: node setup.mjs (cria o ambiente Python mínimo .venv-desktop a partir de requirements-desktop.txt — pynput+mss+pillow, mais comtypes no Windows, ~50 MB; requer uv).
Permissões (macOS): o gravador as pré-verifica e relata o estado legível por máquina, portanto nunca adivinhe. start imprime permissions: {inputMonitoring, screenRecording, grantTo} mais um warning quando algo está faltando, e automaticamente abre o diálogo do sistema e abre o painel de Configurações certo (--no-permission-prompt desativa isso; node scripts/desktop-record.mjs permissions executa sob demanda). grantTo nomeia o aplicativo ao qual o usuário deve conceder — uma concessão TCC vincula-se ao pacote .app que hospeda o agente, não ao Python, e esse aplicativo deve ser reiniciado depois. Transmita grantTo literalmente; dizer ao usuário "conceda ao seu terminal" geralmente está errado. O Windows não precisa de permissão nem de direitos de administrador.
O mecanismo é um gravador de processo único (~0-3% CPU): fluxo de eventos de entrada + alterações de janela ativa/título + um JPEG de meia resolução em cada clique (máx. 1/700ms) → desktop-events.jsonl + screens/. Cada clique também carrega a descrição de acessibilidade do elemento sob o cursor (linha kind: "target", unida ao clique por forSeq): role, name, automationId, window, ancestors — um alvo semântico como Button "Save" em vez de uma coordenada nua (macOS AX, Windows UI Automation; nenhum no Linux). A digitação chega como eventos type: "text" contendo o valor final de cada rajada (correções de backspace aplicadas); atalhos e teclas especiais como eventos press (ctrl+c, enter). Capturas de tela, consultas de alvo e verificações de foco são executadas em threads de trabalho, nunca no callback de entrada: um callback lento faz com que a captura de eventos do macOS seja desativada e o hook do Windows seja removido silenciosamente (o gravador também observa o último e reinstala os hooks).
Esta é a paridade com o Codex: o Record & Replay do Codex também grava… (truncado para tradução)