dbhq-uk/legwork-skill

Compétence de recherche décisionnelle pour Claude Code et Codex – chaque affirmation indique son niveau de soutien et précise quand les preuves ne peuvent pas la trancher. Un outil gratuit par DBHQ.

Qu'est-ce que legwork-skill ?

Legwork est une compétence de recherche décisionnelle conçue pour les agents d'IA comme Claude Code et Codex. Contrairement à la recherche universitaire, son objectif est de répondre à la question pratique « que devrions-nous faire à propos de X » et le livrable est jugé sur son utilité, non sur son exhaustivité. La compétence utilise un pipeline en quatre phases : cadrage, collecte, remise en question et rédaction, avec trois niveaux de profondeur (rapide, standard, approfondi) qui augmentent la rigueur sans allonger le texte. Legwork exige que chaque affirmation soit étayée par des sources appropriées, vérifie les contradictions, et déclare honnêtement lorsque les preuves sont insuffisantes pour trancher. Elle fonctionne sur des modèles de langage via des appels d'outils (WebSearch, WebFetch) et comprend des scripts Python pour la gestion des sources, l'indexation des rapports et la vérification de la qualité. Elle est particulièrement utile pour les décisions commerciales, les analyses de marché et les évaluations concurrentielles, où la fiabilité des informations prime sur la quantité.

Compatible avec✓Claude Code✓Codex CLI~Cursor
npx skills add dbhq-uk/legwork-skill

Installed? Explore more Recherche et analyse de données skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Legwork

À quoi ça sert

Recherche décisionnelle. Pas de la recherche universitaire. La question est toujours une variante de « que devrions-nous faire à propos de X », et le livrable est jugé sur son utilité, pas sur son exhaustivité.

Cela façonne tout ce qui suit. Une affirmation est jugée sur le fait que sa source soit le bon type de chose pour cette affirmation, pas sur la respectabilité de son domaine. Trois sources qui s'accordent ne comptent que si elles auraient pu être en désaccord. Et une session qui ne peut pas répondre à la question le dit plutôt que de produire un texte alambiqué.

Principe d'autonomie. Déduisez ce dont vous avez besoin du contexte, choisissez un niveau et commencez. Annoncez le niveau en une ligne et poursuivez ; ne demandez pas à l'utilisateur de choisir. Il peut rediriger en cours de session, ce qui coûte bien moins qu'une question bloquante à chaque requête. Arrêtez-vous uniquement pour une erreur critique ou une requête incompréhensible.

Niveaux

La profondeur augmente la rigueur. Elle n'augmente jamais la longueur.

rapidestandardapprofondi
CadrageDécision plus 2-3 sous-questionsPlus les falsificateurs nommésPlus les angles secondaires
CollecteExtraits SERP ; ne récupérer que pour fixer un chiffreRécupération directe des sources principales par constatUne source primaire pour chaque constat
Remise en questionRegroupement par indépendance uniquementUne recherche d'infirmation par constatPassage d'infirmation par constat plus un audit d'origine
Formatbrefbref ou rapportrapport
Porte de niveau--level quick--level standard--level deep
Temps approximatif3-5 min8-12 min20-40 min

La valeur par défaut est standard. Utilisez le niveau nommé par l'utilisateur (quick, standard, deep, ou un équivalent comme « analyse rapide » ou « aller en profondeur »), sinon $LEGWORK_DEFAULT_MODE, sinon standard. « Deep research » seul est une phrase d'invocation pour cette compétence, pas une demande de niveau approfondi – passez au niveau par défaut.

Montez silencieusement d'un niveau si le cadrage révèle que la question est matériellement plus importante que ce que la requête impliquait, et dites-le dans la même ligne d'ouverture.

Ligne d'ouverture, puis directement dans la Phase 1 :

Exécution standard (~8-12 min). Dites « approfondi » pour les sources primaires et un passage d'infirmation.

Pipeline

Quatre phases. Instructions complètes dans methodology.md.

  1. Cadrage – nommer la décision, les sous-questions qui la trancheraient, et quelles preuves changeraient la réponse.
  2. Collecte – récupérer pour chaque sous-question, en enregistrant chaque récupération.
  3. Remise en question – chercher le cas infirmant ; regrouper les sources par indépendance.
  4. Rédaction – assembler le livrable, puis le passer à la porte.

Les phases 2 et 3 s'entrelacent par constat plutôt que de fonctionner comme des portes strictes.

Avant de commencer

Ancrez la date. Exécutez date -u +%Y-%m-%d et utilisez cette chaîne pour la session, dans le nom du dossier de sortie, et dans chaque requête de recherche qui pourrait renvoyer du contenu daté. Ne vous fiez jamais à votre propre sens de l'année en cours, et ne laissez jamais un sous-agent la déterminer lui-même.

Vérifiez si cette session a déjà été effectuée. Lisez d'abord l'index. C'est un répartiteur : une ligne par session passée, et la colonne de résumé existe pour que vous puissiez décider d'ouvrir un rapport sans payer le coût d'ouverture.

python3 ${CLAUDE_SKILL_DIR}/scripts/index.py list --base "$OUTPUT_BASE"

Choisissez ensuite l'un des quatre chemins, et dites lequel dans votre ligne d'ouverture :

L'index ditFaites ceci
Une session couvre ce sujet et n'est pas obsolèteRépondez à partir d'elle. Lisez ce rapport, pas le web.
Une session couvre ce sujet mais est marquée comme obsolèteRafraîchissez-la
Une session est proche mais répond à une question différenteNouvelle session, et faites une référence croisée
Rien ne correspondNouvelle session

Répondre à partir d'une session antérieure est un succès, pas un raccourci. Ouvrez le rapport, lisez les constats qui se rapportent à la question, et répondez avec leurs bandes de confiance intactes. Dites clairement qu'il provient d'une session d'une date donnée. Relancer une recherche déjà effectuée et toujours valide est le gaspillage que cet index existe pour empêcher.

Rafraîchir plutôt que relancer

Un rafraîchissement met à jour le rapport existant sur place – même dossier, même fichier. Ne créez pas un second dossier : deux dossiers décrivant une question, c'est ainsi qu'un lecteur finit par agir sur celui qu'il a ouvert par hasard.

  1. Reprenez le journal des récupérations plutôt que d'en commencer un nouveau. Tout ce qu'il contient est déjà payé.

    python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py resume --tsv "$OUT/$BASE.tsv"
    

    Cela affiche les angles déjà traités, les pages déjà récupérées, et lesquelles ne contiennent encore aucune citation. Travaillez les angles non couverts et revérifiez les affirmations qui décident de la réponse ; ne récupérez pas ce qui est déjà enregistré et à jour.

  2. Déplacez chaque affirmation qui est maintenant erronée dans ## Remplacé avec la date et la raison. Ne supprimez jamais une affirmation en silence. Quelqu'un a peut-être agi dessus, et une future session doit savoir que ce terrain a été couvert. Si la même réponse a maintenant été renversée deux fois, dites-le clairement – c'est le signal le plus fort dans le document que la question est instable.

  3. Ajoutez une ligne ## Chronologie indiquant ce qui a changé.

  4. Mettez à jour la ligne de l'index.

Archivage de la session

Chaque session se termine dans l'index, y compris celle qui n'a pas pu répondre – « nous avons cherché et n'avons rien trouvé » est exactement ce dont une future session a besoin pour ne pas chercher à nouveau.

python3 ${CLAUDE_SKILL_DIR}/scripts/index.py add --base "$OUTPUT_BASE" \
  --folder "$BASE" --topic "Tri des Outlook pour les petites structures" --level deep \
  --one-liner "Pas de tri natif en dessous d'E5 ; l'écart est réel mais étroit"

Le résumé indique ce que la session a conclu, pas son sujet. « Notes sur la galerie de plugins » est inutile dans six mois ; « Aucune voie de soumission n'existe, l'installation se fait par URL ou pas du tout » répond à la question tout seul. La porte avertit lorsqu'une session manque dans un index qui existe.

Politique de récupération

Deux échelles, premiers échelons gratuits. Ne montez qu'aussi haut que nécessaire.

Pour chercher :

ÉchelonAppelQuand
1WebSearchToujours. Trois variantes de requête par angle.
2platforms.py search --on ...La réponse est un enregistrement détenu par une plateforme : un fil de discussion, un paquet, un dépôt, un article de presse daté, un journal des modifications d'un fournisseur. Gratuit, sans clé, et renvoie l'enregistrement plutôt qu'une page à son sujet.
3bd_search.py -m general --engine bing --country XX --language yyFaible après trois variantes, ou la question est géo-spécifique. Un deuxième moteur est la raison de payer.
4bd_search.py -m discover --intent "..."Deux moteurs encore faibles.

Pour ouvrir une page :

ÉchelonAppelQuand
1fetch.py "<url>" --find "terme"Toujours en premier. Gratuit, et le seul transport gratuit qui donne le texte de la page, donc les chiffres peuvent être retracés et les citations vérifiées.
2WebFetchfetch.py a quitté avec le code 3 et la page ne vaut pas la peine d'être payée.
3bd_search.py "<url>" -m scrapeBloqué : protection anti-bot, paywall, 403.
4bd_search.py "<url>" -m renderUne coque rendue côté client.
5bd_search.py "<url>" -m pipeline --pipeline NOMUne plateforme qui bloque tout ce qui précède. Facturé par enregistrement ; -m reddit est celui où c'est la seule route, pas un dernier recours.

Exécutez platforms.py list pour les dix plateformes gratuites, et bd_search.py --help pour les modes payants. En cas de code de sortie 2 (authentification ou quota), dites à l'utilisateur d'exécuter brightdata login. Ne réessayez pas.

Un résultat de recherche est une piste, pas une page que vous lisez. Aux niveaux standard et approfondi, ouvrez ce que vous citez : la porte traite une citation reposant uniquement sur des lignes websearch comme non ouverte, un avertissement au niveau standard et une erreur au niveau approfondi. Le niveau rapide est conçu pour être basé sur les extraits en premier et n'est pas concerné.

Enregistrez l'échec avant la solution de repli. Une page qui ne s'ouvre pas est une preuve concernant la session – --status blocked – et le reçu en tient compte.

Limitez ce que vous récupérez. --max-chars 8000 sur les appels de scraping, et préférez --find à une limite aveugle : sur une longue page, les huit mille premiers caractères sont généralement la navigation.

Sources que vous pouvez utiliser

La recherche est ce qu'un étranger pourrait établir. Cette limite est importante dans les deux sens.

Ne présentez jamais les propres enregistrements de l'utilisateur comme un constat. Si la question concerne la propre entreprise, le produit ou la position sur le marché de l'utilisateur, ne fouillez pas dans ses comptes privés – son registraire, sa facturation, sa boîte de réception, ses fichiers internes – et ne rapportez pas ce que vous y avez trouvé comme si cela avait été découvert. Il le sait déjà. C'est circulaire, cela gonfle les preuves apparentes, et cela masque à quel point un étranger peut réellement voir peu de choses. Cherchez l'équivalent public et rapportez ce qu'un étranger trouverait, y compris rien.

Utilisez l'accès exclusif que l'utilisateur vous a donné, sur des tiers. Un abonnement payant, un ensemble de données privé ou une base de données interne que l'utilisateur vous a explicitement offert est un avantage réel lors de la recherche sur des concurrents, des fournisseurs ou un marché. Utilisez-le, enregistrez-le comme une source comme les autres, et notez dans les Limitations que le constat repose sur un accès que le lecteur pourrait ne pas avoir.

Lorsqu'une entité s'avère n'avoir aucune empreinte publique du tout, c'est la réponse. Listez ce que vous avez vérifié, dites que l'existence ou l'échelle n'a pas pu être vérifiée de l'extérieur, et ne comblez pas le vide à partir d'un accès privilégié. C'est la forme « n'a pas pu répondre » appliquée à une entité plutôt qu'à l'ensemble de la question.

Le journal des récupérations

Chaque récupération, à chaque niveau, ajoute une ligne :

python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py log \
  --tsv "$OUT/$BASE.tsv" \
  --url "https://acme.example/pricing" \
  --kind vendor_pricing \
  --angle "que facture le titulaire" \
  --via webfetch \
  --date 2026-07-01 \
  --title "Tarifs" \
  --quote "Forfait Équipe : 30 dollars américains par utilisateur par mois, facturé annuellement." \
  --text-file /tmp/page.txt

Deux champs portent le poids, et aucun ne peut être vérifié par quoi que ce soit en aval.

--angle est la sous-question à laquelle cette récupération répondait. La corroboration est comptée par angles plutôt que par sources car la propre dispersion de Legwork gonfle les nombres de sources. Enregistrez l'angle honnêtement – réutiliser une même chaîne dans une session détruit silencieusement la vérification, et aucun script ne peut dire que vous l'avez fait.

--quote est la phrase textuelle qui a rendu la source digne d'être citée. Enregistrez-en une pour chaque source que vous avez l'intention de citer, au moment où vous la lisez. Environ la moitié de tous les constats ne contiennent aucun chiffre, donc pour ceux-ci, la citation est la seule preuve qui existe, et c'est la seule partie qui survit au changement de la page. Lorsque le texte de la page est sur disque – tout ce qui a été ouvert avec fetch.py, ou un -m scrape avec --out – la citation est vérifiée par rapport à lui et quote_verified: false signifie que vous avez mal cité la page.

--from-fetch remplit l'url, le titre, la date et le texte de la page à partir du fichier sidecar que ces deux-là écrivent, donc rien n'a à être retapé :

python3 ${CLAUDE_SKILL_DIR}/scripts/sources.py log --tsv "$OUT/$BASE.tsv" \
  --from-fetch /tmp/legwork/ab12cd34ef56.json \
  --angle "que facture le titulaire" --kind vendor_pricing \
  --query "site:acme.example tarifs" --quote "Forfait Équipe : 30 dollars américains ..."

sources.py log --help couvre le reste : --via transports (incluant api, local et mcp), --text-file extraction numérique, --kind. Enregistrez le transport que vous avez réellement utilisé – récupérer à nouveau une page via un autre transport pour la rendre enregistrable déforme la piste plutôt que de l'enregistrer. sources.py kinds affiche quels types de sources conviennent à quelles affirmations.

Sous-agents

La récupération est la seule phase qui vaut la peine d'être parallélisée, un sous-agent par angle. Briefez-les à partir de subagent-brief.md, qui contient le modèle textuellement, la forme de retour requise, et la raison pour laquelle chaque ligne s'y trouve. Un sous-agent a zéro contexte, donc tout ce dont il a besoin va dans le brief.

Trois choses restent avec vous plutôt que dans le brief :

  • Faites correspondre le modèle à la forme de l'angle. La collecte d'extraits et la fixation d'un chiffre connu fonctionnent bien sur un modèle bon marché – passez l'override explicitement, ne laissez jamais un sous-agent hériter du modèle de session par accident. Mais le travail de source primaire de niveau approfondi, et tout ce qui reconstruit une énumération, reste sur le modèle de l'orchestrateur. Mesuré : lors d'une comparaison, les orchestrateurs ont ouvert 3, 8 et 32 pages de fournisseurs dans la gamme du bon marché au performant, et seul le plus faible a rempli chaque cellule de la grille à partir d'un seul agrégateur tout en signalant un succès.
  • Ne collez jamais la transcription d'un sous-agent dans votre synthèse. Prenez le retour structuré, vérifiez que la chaîne d'angle est revenue inchangée, enregistrez chaque ligne, travaillez à partir du journal.
  • Le cadrage, la remise en question et la synthèse sont des jugements. Ils restent sur le modèle principal.

Scripts

Tous basés sur la bibliothèque standard uniquement. Pas de virtualenv. Tout python3 >= 3.9.

ScriptObjectif
fetch.py "<url>" --find TERMEOuvrir une page gratuitement et conserver son texte ; quitte avec le code 3 en cas de blocage ou de coque
platforms.py list | search --on XDix sources natives de plateformes gratuites, renvoyant des enregistrements plutôt que des pages
sources.py kinds | log | scoreVocabulaire des types de sources, le journal des récupérations, le score d'adéquation par type d'affirmation
sources.py receiptLes compteurs de récupération pour la ligne de reçu, tirés du journal
sources.py stale --claim-kind KQuelles sources enregistrées sont devenues obsolètes, selon la demi-vie de ce type d'affirmation
sources.py resumeCe qu'une session précédente a déjà récupéré, afin qu'une reprise l'ignore
independence.py groups | checkRéduire les sources à des voix indépendantes ; compter la corroboration tenant compte des angles
independence.py portfolioConcentration des sources sur l'ensemble de la session, pas au sein d'un seul constat
index.py add | listL'index de recherche – archiver une session, en trouver une passée, repérer les obsolètes
matrix.py check --report CHEMINComplétude d'une matrice de comparaison
check.py --report CHEMIN --level NIVEAULa porte de livraison
finish.py --report CHEMIN --level NIVEAUPorte, balayage d'obsolescence et archivage en un seul appel
`bd_search.py "<requêteurl>" -m MODE --json`

Sortie

Résolvez la base de sortie une fois au début de la session :

OUTPUT_BASE="${LEGWORK_OUTPUT:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)/docs/research}"
BASE="[Sujet]_Recherche_$(date +%Y%m%d)"
OUT="$OUTPUT_BASE/$BASE"; mkdir -p "$OUT"

…

[tronqué pour la traduction]

Skills associés