Enregistrer & Rejouer (navigateur + bureau)
Enregistrer & Rejouer permet à un agent d'apprendre un workflow démontré par l'utilisateur et de le transformer en une compétence réutilisable. Deux modes :
- Mode navigateur (par défaut, preuves les plus riches) : un navigateur Playwright avec tête (Google Chrome système s'il est disponible) enregistre chaque action de l'utilisateur dans
events.jsonlavec plusieurs sélecteurs candidats, plus des morceaux de trace Playwright (trace-NNN.zip). Fonctionne sur macOS, Windows et Linux. - Mode bureau (applications natives) : un enregistreur monoprocessus léger (pynput) capture les événements globaux de souris/clavier, les changements de fenêtre active, les captures d'écran au moment du clic et la cible d'accessibilité de chaque clic (macOS AX, Windows UI Automation) dans
desktop-events.jsonl+screens/, avec masquage des champs de mot de passe — parité avec Codex (Codex enregistre également un flux d'événements/contexte, pas une vidéo), ~1-3% CPU. Fonctionne sur macOS, Windows et Linux (X11). Voir "Enregistrement bureau" ci-dessous.
Choisissez le mode navigateur à chaque fois que le workflow est uniquement dans le navigateur — ses sélecteurs sémantiques produisent de bien meilleures compétences que les coordonnées du bureau.
Configuration (une fois)
cd ~/.agents/skills/record-and-replay
node setup.mjs # npm install + (Chromium seulement si Chrome est manquant) + auto-tests
node install.mjs # lien vers les répertoires de compétences de l'agent (lien symbolique sur macOS/Linux, jonction sur Windows)
Installe le paquet npm playwright. Les navigateurs ne sont PAS téléchargés lorsque Google Chrome est installé (l'enregistreur utilise channel: 'chrome') ; sinon le script télécharge Chromium. Les deux scripts sont multiplateformes (Node).
Workflow d'enregistrement
-
Avant de commencer, dites à l'utilisateur de fermer les fenêtres, fichiers et conversations qu'il ne souhaite pas voir capturés, et de ne pas taper de secrets qu'il ne voudrait pas voir stockés. Démarrez l'enregistreur en arrière-plan détaché uniquement lorsque l'utilisateur est prêt à commencer. Passez toujours
--name <slug>pour que le répertoire de sortie soit connu à l'avance :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>"Les agents disposant d'une fonction d'exécution en arrière-plan native (par exemple, le
run_in_backgroundde Bash de Claude Code) peuvent l'utiliser à la place. Les sorties vont dans~/.agents/recordings/<slug>/. -
Vérifiez le démarrage une fois (~2-3 secondes après le lancement — une seule vérification, pas une boucle d'interrogation) : confirmez que
~/.agents/recordings/<slug>/session.jsonexiste avec"status": "recording"(l'enregistreur imprime également une ligne{"status":"recording",...}dans le journal en cas de succès). Si la vérification échoue, lisez le journal :recording_already_active(sortie 2) signifie qu'un autre enregistrement détient le verrou ;launch_failedou une erreur de module manquant signifie que la configuration est nécessaire. Signalez le problème réel au lieu de dire à l'utilisateur que l'enregistrement a commencé. -
Après la vérification du démarrage, ne vous endormez pas, n'interrogez pas et n'attendez pas dans une boucle. Terminez votre tour : dites à l'utilisateur que l'enregistrement a commencé, quelle est la limite de temps, et qu'une petite fenêtre de contrôle flottante (en bas à droite, comme les contrôles d'enregistrement de Codex) a une minuterie ainsi que les boutons Pause/Reprendre, Arrêter et Ignorer (appuyez deux fois pour confirmer). Rien n'est capturé en pause — les événements et la trace s'arrêtent tous les deux. Si l'utilisateur ferme la fenêtre de contrôle par accident, elle se rouvre toute seule ; la fermeture de la fenêtre principale du navigateur met également fin à la session (évitez de quitter complètement le navigateur avec Cmd+Q, ce qui peut perdre la dernière minute de trace). Passez
--badgeau démarrage pour utiliser un badge dans la page au lieu de la fenêtre de contrôle (solution de repli pour les environnements exotiques). -
Pause/reprise (l'utilisateur vous demande de faire une pause, ou vous devez sauter une partie sensible) :
touch ~/.agents/recordings/<slug>/PAUSEmet en pause dans les 2 secondes ; supprimez le fichier pour reprendre. Les boutons de la fenêtre de contrôle et le fichier PAUSE restent synchronisés ;session.jsonporte l'étatpausedactuel. Les intervalles de pause apparaissent comme des marqueurspaused/resumeddansevents.jsonlet sont absents de la trace. -
Lorsque l'utilisateur dit qu'il a terminé :
- Si le processus est toujours en cours d'exécution, arrêtez-le proprement :
touch ~/.agents/recordings/<slug>/STOP(l'enregistreur le remarque dans les 2 secondes et finalise). - Lisez
session.json—status: "recording"signifie toujours actif ;"completed"signifie que les sorties sont finales ;"discarded"signifie que l'utilisateur a appuyé sur Ignorer — les fichiers de preuve ont été supprimés, reconnaissez-le et ne créez JAMAIS une compétence à partir de cela.endReasonest l'un deuser_stopped,user_discarded,browser_closed,stop_file,time_limit,signal,event_limit. - Inspectez les événements capturés avant de répondre : exécutez
node scripts/summarize.mjs <outDir>pour une chronologie compacte, puis lisezevents.jsonldirectement pour les étapes qui nécessitent des détails.
- Si le processus est toujours en cours d'exécution, arrêtez-le proprement :
-
L'annulation est définie par le contenu, pas par endReason : si l'enregistrement contient peu ou pas d'événements
kind: "dom"— quelle que soit la endReason — traitez-le comme annulé. Reconnaissez, ne créez pas et ne mettez pas à jour une compétence. -
Si l'enregistrement contient suffisamment d'informations pour identifier un workflow réutilisable, créez ou affinez une compétence par défaut — même si l'utilisateur ne l'a pas demandé explicitement. Ne vous arrêtez pas après avoir produit uniquement un résumé ou un plan de rejeu. Suivez "Création de compétences à partir d'un enregistrement" ci-dessous — cela commence par un court tour de clarification.
-
Si l'enregistrement est trop mince ou ambigu pour identifier le workflow, ne devinez pas. Expliquez ce qui n'est pas clair et demandez à l'utilisateur les éléments manquants.
Enregistrement concurrent
Un seul enregistrement peut être actif à la fois (fichier de verrouillage ~/.agents/recordings/.lock). Si l'enregistreur se termine avec recording_already_active, ne forcez pas le démarrage d'un autre ; dites à l'utilisateur qu'un enregistrement est déjà en cours et demandez-lui s'il souhaite l'utiliser ou l'arrêter d'abord. Redémarrer avec le même --name est sûr : le events.jsonl précédent est conservé comme .bak horodaté, pas ajouté.
Interprétation des événements
events.jsonl est la preuve principale ; session.json ne donne que les temps/chemins ; les morceaux trace-NNN.zip sont la vérité terrain au niveau DOM (npx playwright show-trace <outDir>/trace-*.zip ; session.json's traceChunks les liste dans l'ordre). La trace par défaut est en mode léger — instantanés DOM complets par action mais pas de captures d'écran continues (maintient le CPU bas). Commencez avec --trace full lorsque l'utilisateur souhaite une preuve visuelle parfaite au pixel près, ou --trace off pour l'empreinte minimale absolue.
Chaque ligne est un événement : {seq, t (ms depuis le début), kind, type, url, ...}.
kind: "page"— navigations, téléchargements, boîtes de dialogue, ouvertures/fermetures d'onglets. Les navigations segmentent le workflow en étapes.kind: "dom"— actions de l'utilisateur.target.selectorsporte plusieurs candidats sélecteurs :testId,role({role, name}),id,nameAttr,text,css. Préférez-les dans cet ordre lors de la génération du code de rejeu ;cssest le dernier recours.- Les événements
type: "input"sont anti-rebond — un événement par champ avec la valeur finale (vidé sur blur, Enter, change et soumission de formulaire). Les champs ressemblant à des mots de passe/cartes de crédit/OTP (noms anglais et turcs : password, parola, şifre, kart, kimlik…) arrivent pré-masqués (***MASKED***,masked: true). - Les événements
selectionetcopyrévèlent avec quel contenu l'utilisateur travaillait — souvent le meilleur indice lorsque l'utilisateur fait référence à "ceci" ou "la chose que j'ai sélectionnée". Les sélections à apparence de secret (OTP, clés API, jetons) sont masquées. Les événementspastene portent que la longueur/le nombre de mots, jamais le contenu. - Données sensibles : le masquage est heuristique, pas une garantie — et il s'applique uniquement à
events.jsonl. Les morceaux de trace ne sont PAS masqués : les instantanés DOM contiennent des valeurs d'entrée brutes (y compris les valeurs masquées dans le JSONL) et les captures d'écran capturent tout ce qui est visible à l'écran (jetons révélés, codes 2FA, soldes). Traitez l'intégralité du répertoire~/.agents/recordings/<name>/comme sensible : inspectez-le localement uniquement, ne le téléchargez ni ne le validez jamais, et ne citez jamais les secrets littéraux de celui-ci dans les résumés ou les compétences générées — utilisez des espaces réservés ou des descriptions génériques.
Création de compétences à partir d'un enregistrement
Lisez references/skill-authoring.md avant d'écrire : il contient la banque de questions, les limites du préambule, le squelette SKILL.md, les règles pour les scripts groupés et la liste de contrôle qualité. Si une compétence skill-creator est disponible dans votre environnement, ses conseils s'appliquent également. Créez une compétence réellement découvrable (un dossier SKILL.md), pas seulement un manuel Markdown.
Copiez cette liste de contrôle et cochez-la :
- [ ] 1. Résumez l'enregistrement ; notez chaque lacune (décisions, étendues masquées, angles morts)
- [ ] 2. Clarifiez : un message, au maximum 6 questions, uniquement sur les lacunes
- [ ] 3. Vérifiez s'il existe une compétence existante couvrant ce workflow → mettez-la à jour au lieu de la dupliquer
- [ ] 4. Écrivez la compétence + evals/evals.json (l'enregistrement est le cas de test 1)
- [ ] 5. Validez : node scripts/export-skill.mjs <skillDir> --check → corrigez les erreurs, relancez
- [ ] 6. Proposez la vérification du déclencheur + un test à blanc ; intégrez les corrections, augmentez metadata.version
- [ ] 7. Proposez l'export ZIP pour claude.ai
Étape 2 — clarifiez avant d'écrire. Il n'y a pas d'audio : l'enregistrement montre ce qui s'est passé, pas pourquoi. Répondez à partir de l'enregistrement tout ce qu'il montre, puis demandez à l'utilisateur — une fois, dans un seul message, au maximum 6 questions — sur ce qu'il ne peut pas : le résultat et comment dire que cela a fonctionné, quelles valeurs varient entre les exécutions, pourquoi ils ont choisi X à un moment donné, quelles actions étaient des détours, ce qu'ils diraient pour déclencher la compétence (et ce qui ne devrait pas), et quelles actions nécessitent une confirmation. Citez le moment que vous voulez dire ("à 02:14 vous avez effacé le filtre de date — pourquoi ?"). Utilisez votre outil de question structurée si vous en avez un ; une discussion simple sinon. Sautez le tour uniquement lorsque l'enregistrement plus la demande de l'utilisateur répondent déjà à tout, et dites-le.
Règles d'écriture :
- Traitez l'enregistrement comme preuve du résultat escompté de l'utilisateur, pas comme un script à rejouer pixel par pixel. Si un connecteur/API/CLI/outil MCP peut atteindre le même résultat sémantiquement (créer un événement de calendrier, ouvrir une PR, publier un message), préférez-le à l'automatisation de l'interface utilisateur.
- Lorsque le rejeu de l'interface utilisateur est vraiment nécessaire, générez un script Playwright à partir de
scripts/replay-template.mjs: localisateurs sémantiques (getByTestId>getByRole>getByLabel>getByText), une étape de vérification après chaque action critique, secrets à partir des variables d'environnement. N'utilisez jamais de coordonnées brutes à moins que le flux d'événements n'offre pas de meilleure cible. - Les étapes du bureau nomment la cible capturée (rôle + nom + fenêtre, par exemple Bouton "Enregistrer" dans "Facture — Acme") afin qu'un outil d'arbre d'accessibilité puisse la trouver ; coordonnées uniquement lorsqu'aucune cible n'a été capturée.
- Le profil persistant de l'enregistreur (
~/.agents/recordings/.browser-profile) conserve les connexions entre les sessions, donc les compétences générées n'ont généralement pas besoin d'étapes de connexion. Sécurité : ce répertoire contient des données de session authentifiées en direct (cookies/localStorage ; Playwright lance Chrome avec un trousseau factice, traitez-le donc comme des identifiants en texte brut). Ne validez, ne partagez ni ne sauvegardez jamais ce répertoire sans chiffrement — et rappelez-vous que toute compétence de rejeu qui le réutilise s'exécute avec les connexions de l'utilisateur. Pour les enregistrements sur des sites non fiables ou à haute sensibilité, préférez un profil jetable (--outplus un profil temporaire) ou effacez le profil par la suite. - Enregistrez les nouvelles compétences dans
~/.agents/skills/<skill-name>/(nom du dossier =name, en kebab-case) et créez un lien symbolique vers les répertoires de compétences de l'agent (voirinstall.mjspour le modèle) afin que chaque agent sur cette machine puisse les utiliser. - Paramétrez ce qui varie (dates, montants, noms) et codez en dur ce qui ne varie pas. Indiquez le but du workflow et les critères de vérification dans le SKILL.md généré. Ne copiez jamais les secrets ou les valeurs masquées dans la compétence.
Export pour claude.ai (proposez-le ; exécutez sur demande) : node scripts/export-skill.mjs ~/.agents/skills/<name> écrit ~/.agents/exports/<name>.zip (dossier à la racine du ZIP ; README, évaluations, caches et preuves d'enregistrement exclus ; archive relue avant le succès). Si la compétence utilise un préambule propre à Claude Code (disable-model-invocation, …) ajoutez --strip-cc-keys. Dites à l'utilisateur où se trouve le fichier et qu'il se télécharge sous Personnaliser › Compétences › + › Télécharger une compétence (l'exécution du code doit être activée).
Enregistrement bureau (macOS, Windows, Linux/X11)
Configuration : node setup.mjs (crée l'environnement Python .venv-desktop minimal à partir de requirements-desktop.txt — pynput+mss+pillow, plus comtypes sur Windows, ~50 Mo ; nécessite uv).
Autorisations (macOS) : l'enregistreur les pré-vérifie et signale l'état lisible par machine, donc ne devinez jamais. start imprime permissions: {inputMonitoring, screenRecording, grantTo} plus un warning quand quelque chose manque, et ouvre automatiquement la boîte de dialogue système et le volet Paramètres approprié (--no-permission-prompt désactive cela ; node scripts/desktop-record.mjs permissions l'exécute à la demande). grantTo nomme l'application à laquelle l'utilisateur doit accorder l'autorisation — une concession TCC se lie au bundle .app hébergeant l'agent, pas à Python, et cette application doit être redémarrée ensuite. Relayer grantTo textuellement ; dire à l'utilisateur "accordez-le à votre terminal" est généralement faux. Windows n'a besoin d'aucune autorisation ni de droits d'administrateur.
Le moteur est un enregistreur monoprocessus (~0-3% CPU) : flux d'événements d'entrée + changements de fenêtre active/titre + une capture d'écran demi-résolution à chaque clic (max 1/700ms) → desktop-events.jsonl + screens/. Chaque clic porte également la description d'accessibilité de l'élément sous le curseur (ligne kind: "target", jointe au clic par forSeq) : role, name, automationId, window, ancestors — une cible sémantique telle que Bouton "Enregistrer" au lieu d'une coordonnée nue (macOS AX, Windows UI Automation ; aucun sur Linux). La saisie arrive sous forme d'événements type: "text" contenant la valeur finale de chaque salve (corrections de retour arrière appliquées) ; les raccourcis et touches spéciales comme événements press (ctrl+c, enter). Les captures d'écran, les requêtes de cible et les vérifications de focus s'exécutent sur des threads de travail, jamais dans le rappel d'entrée : un rappel lent désactive le robinet d'événements macOS et supprime silencieusement le hook Windows (l'enregistreur surveille également ce dernier et réinstalle les hooks).
Ceci est la parité avec Codex : l'enregistrement et le rejeu de Codex enregistrent également
…
[tronqué pour la traduction]