Que fait begin ?
S'orienter dans une base de code en un seul passage, à partir de preuves, sans errer.
L'échec que cette compétence existe pour éviter : un agent ouvre un dépôt, grep un mot qui semble plausible,
lit trois fichiers qui correspondent par hasard, et produit un résumé d'architecture confiant
qui décrit 4% du système. begin remplace le fait de deviner où se trouve le code important par le fait de mesurer où il se trouve, puis lit uniquement ce que la mesure a indiqué.
Le contrat
- Rien n'est rappelé. Tout est dérivé. L'importance provient d'un PageRank sur le graphe d'imports réel ; la complexité, du nombre de points de décision comptés ; la direction, de git et du journal des PRs. Si vous ne pouvez pas pointer un fichier:ligne ou un commit, vous ne le dites pas.
- Chaque affirmation est ancrée. Chaque déclaration dans
BEGIN.mdcitechemin:ligne, un commit ou un numéro de PR. Une phrase sans ancrage est une supposition, et les suppositions sont ce que cette compétence existe pour éliminer. - Deux couches, dont une vivante.
.begin/est une sortie machine, régénérée et s'ignorant elle-même.BEGIN.mdest une prose que vous écrivez, committez, et timbrez avec le commit dont elle a été dérivée. Un hook post-commit redérive la couche machine et rapporte quelles sections de prose le code a dépassées. Rien dans cette compétence ne modifie jamais un fichier suivi —.begin/porte son propre.gitignore, donc celui du dépôt reste intact. - Les proxies sont nommés comme tels.
complexityProxyest un comptage de points de décision, pas une analyse. L'imbrication est mesurée à partir de l'indentation. Dites-le ; ne transformez pas un proxy en fait. - Une mesure dégradée est annoncée, jamais utilisée en silence. L'analyse imprime un
bloc
[!WARNING]pour un clone peu profond, une fenêtre d'activité morte, des fichiers ignorés, un langage qu'elle ne peut pas du tout analyser, ou une résolution qui échoue pour un langage qu'elle peut analyser. Lisez ce bloc avant le tableau, et répétez ce qu'il dit dans BEGIN.md. Un classement construit sur un graphe cassé ressemble exactement à un bon — c'est tout le danger.
Lancer la compétence
S=~/.claude/skills/begin/scripts
bash $S/recon.sh # qui/quoi/quand : PRs, vos commits, modifications en direct, docs
node $S/scan.mjs # structure : graphe d'imports, points chauds, surface->moteur
Les deux écrivent dans .begin/ et impriment un résumé. Exécutez-les depuis n'importe où dans le dépôt — l'analyse s'ancre à la racine du dépôt. recon.sh se dégrade proprement sans gh, sans réseau et sans remote, mais il nécessite node (la rédaction est obligatoire). Temps mesuré à chaud : 259 fichiers 0,24s · 3 384 fichiers 1,9s · 2 809 fichiers 1,9s · 1 819 fichiers 2,5s · 1 397 fichiers 3,5s. Le nombre de fichiers ne prédit pas le temps ; le contenu si.
Drapeaux utiles :
--since "il y a 90 jours"— fenêtre d'activité (les deux scripts utilisent 90 par défaut).--top 40— combien de points chauds afficher (25 par défaut).--author "..."— une regex. Vous en avez rarement besoin : elle utilise par défaut leuser.namedu dépôt, etrecon.shutilise l'auteur le plus actif du dépôt et le dit quand vous n'avez pas de commits. C'est le cas normal dans un dépôt que vous venez de cloner.--exclude 'examples/**,site/**'— gardez les arbres vendus et les sites de documentation hors du décompte de surface. Les motifs sont ancrés aux deux extrémités, et le nombre de fichiers supprimés est imprimé, car une exclusion silencieuse apparaît plus tard comme une arête manquante.--root DIR— analyser un dépôt différent.
L'ordre des opérations — suivez-le exactement
Faire ces étapes dans le désordre, c'est ainsi qu'un agent finit par lire les mauvais fichiers.
1. Reconnaissance avant structure
Exécutez recon.sh en premier. Il répond à « Qu'est-ce que cette personne a fait ? » — modifications non commitées,
commits branche-vs-principale, les ~20 dernières PRs fusionnées avec leurs corps, et ce que chacune a changé. C'est la priorité directionnelle. Lisez .begin/recon.md entièrement ; c'est court.
Le diff non commité est généralement l'élément le plus informatif du dépôt — c'est la question que l'utilisateur se pose actuellement. La reconnaissance signale trois choses à son sujet : quand l'arbre est propre, elle le dit explicitement (plutôt que d'omettre la section et de vous laisser chercher) ; quand le diff ne contient que des fichiers de verrouillage et des sorties de build, elle vous dit de ne pas y consacrer votre première lecture ; et quand votre checkout est en retard sur origin, elle dit de combien de commits et nomme les fichiers des PRs récentes qui ne sont pas dans votre arbre.
Ce dernier point est une condition préalable, pas une mise en garde. Si la reconnaissance signale que vous êtes en retard, l'étape 3.2 ci-dessous n'est pas sûre : les listes de fichiers de PR décrivent du code que vous n'avez pas. Soit faites git pull d'abord, soit sautez l'étape de lecture des PRs et dites dans BEGIN.md que vous l'avez fait.
2. Structure en deuxième
Exécutez scan.mjs et lisez .begin/scan.md, en commençant par tout bloc [!WARNING]. Vous avez alors, mesuré plutôt que supposé :
- Surfaces — chaque endroit où un humain ou un appelant touche réellement le système, regroupés par type (
web-page,ui-component,http-route,cli-command,mcp-tool,worker,public-api,migration, plusexample,configettestqui sont des surfaces mais pas des produits). C'est l'extrémité UI de la carte. - Points chauds — classés, avec une colonne
whynommant le terme qui a placé chaque fichier là :depended-on,churn,complexourecent. Un fichier en haut pourchurnest un animal différent d'un fichier en haut pourdepended-on; la colonne vous indique quelle conversation avoir. - Chemins surface → moteur — la chaîne d'imports littérale d'un point de terminaison ou d'un bouton jusqu'à la partie difficile, calculée par BFS. Un chemin qui traverse une arête
await import()paresseuse est étiqueté comme tel, car elle est résolue au moment de l'appel plutôt qu'au moment du chargement. - Groupes de cycles d'imports — ensembles fortement connexes sur les arêtes de valeur statiques, avec une boucle dirigée réelle parcourue. Les arêtes de type uniquement et paresseuses (
await import(...)) sont exclues, car aucune ne forme un cycle d'initialisation réel. - Fichiers inaccessibles — code mort, ou une surface que les heuristiques ont manquée. Décidez lequel, et dites lequel.
2.5. Lisez la carte que le dépôt a déjà écrite pour vous
Avant d'ouvrir un point chaud, vérifiez l'existence de AGENTS.md, CLAUDE.md, ARCHITECTURE.md ou des README par répertoire — recon.md les liste. Un dépôt qui fournit une carte de sous-système vous donne en trente lignes ce que l'analyse déduit en deux secondes et qu'il faudrait une heure à reconstruire en prose. Lisez-les d'abord, puis utilisez l'analyse pour les vérifier : la documentation se périme, le graphe non.
3. Lisez uniquement ce que la mesure a indiqué
Lisez, dans cet ordre, et arrêtez-vous :
- Le diff non commité et les commits de la branche actuelle (ce qu'ils font maintenant).
- Les fichiers modifiés par les 3 à 5 PRs fusionnées les plus récentes (ce qu'ils viennent de décider).
- Les 8 à 15 premiers points chauds de
scan.md. - Pour chacun des 3 premiers, parcourez sa surface
reachedViavers l'intérieur, afin de pouvoir énoncer le chemin complet de l'action de l'utilisateur au moteur. README, la documentation destinée à l'agent de l'étape 2.5, et tout document dont le titre correspond à un point chaud.
N'ouvrez pas de fichiers en dehors de cet ensemble lors d'un premier passage. Si quelque chose semble manquant, c'est une constatation à signaler, pas une licence pour naviguer.
4. Vérifiez avant d'écrire
Le tableau est un ensemble de pistes, pas une conclusion. Avant que chaque affirmation n'aille dans BEGIN.md :
- Ouvrez le fichier et confirmez que la ligne que vous êtes sur le point de citer dit bien ce que vous pensez.
- Pour un chemin surface → moteur, confirmez que l'import existe réellement dans la source.
- Pour tout ce qui concerne le comportement, préférez un test qui le démontre à une fonction qui y ressemble.
greples chemins chauds pour les échecs avalés —catch {},.catch(() => {}),as any,as never, les retours ignorés. Les bugs vivent là où les erreurs sont jetées, et ce sont les éléments de la plus haute valeur que vous puissiez fournir dès le premier jour.- Consacrez au moins un passage à essayer de falsifier votre affirmation principale, pas à la confirmer. Les phrases les plus précieuses dans un bon BEGIN.md sont celles qui contredisent l'analyse.
Si l'analyse a tort sur quelque chose, dites-le dans BEGIN.md et corrigez-le. Un fichier que le graphe déclare mort mais qui est en réalité atteint via HTTP ou une file d'attente est la chose la plus utile que vous puissiez enregistrer, car personne d'autre ne le retrouvera non plus. Déclarez ces points d'entrée dans .begin/surfaces.txt (un chemin par ligne, éventuellement chemin<TAB>type) et la prochaine exécution les traitera comme des surfaces.
5. Écrivez BEGIN.md
Utilisez references/BEGIN-template.md, et lisez references/EXAMPLE-BEGIN.md d'abord pour vous calibrer — c'est un vrai, pas une maquette. Structure, dans l'ordre :
- Ce que fait ce système en un paragraphe — dans les termes de l'utilisateur, pas ceux du code.
- Le mécanisme fondamental — premiers principes. Quelle est la transformation de base ? Quelle est l'idée unique qui rend le reste évident ? Qu'est-ce qui casse sans elle ?
- Surfaces → moteur — un tableau à partir des chemins de
scan.md, chaque ligne vérifiée. Si aucune ligne ne traverse une limite de processus ou de réseau, dites-le explicitement : dans un dépôt multilingue, la véritable jointure est généralement un appel HTTP ou de file d'attente qu'aucun graphe d'imports ne peut voir. - Les parties complexes, classées — constat d'abord, mesure ensuite. Chaque entrée a besoin d'un piège qui cite un
fichier:lignepas déjà dans sa ligne de mesure. Une entrée à laquelle vous ne pouvez pas donner cela est une entrée que vous n'avez pas réellement lue : supprimez-la. - Décisions et pourquoi — chacune liée à sa PR ou son commit, avec le raisonnement du corps de la PR. C'est ce qui fait du doc un graphe de connaissance plutôt qu'une visite guidée du code.
- Où vous vous êtes arrêté — ou, dans un dépôt dont vous n'êtes pas propriétaire, qui possède ceci et où ça se développe : les auteurs actifs, ce que les PRs ouvertes les plus récentes ajoutent, lesquelles lire en premier.
- Ce que la couche machine n'a pas pu voir ici — et questions ouvertes, y compris la seule hypothèse qui fait le plus de travail. Ne l'omettez jamais.
Enregistrez également comment l'exécuter et le vérifier (les scripts que recon.md a extraits de package.json) et un glossaire pour tout mot surchargé par ce dépôt. Ce sont les deux choses dont un nouveau venu a besoin en premier et que toute visite guidée du code oublie.
Créez des liens croisés avec des ancres [[style-wiki]]. Timbrez chaque section :
<!-- begin:section id="ingestion" sha="0055f01" files="src/adapter.ts,src/identity.ts" -->
sha = git rev-parse --short HEAD au moment où vous avez dérivé la section (pas le commit qui ajoute BEGIN.md plus tard). files = les fichiers sur lesquels reposent les affirmations de la section ; les globs comme src/engine/** fonctionnent. Une section sans files=, ou avec un files= nommant un chemin qui n'existe pas, ne peut jamais devenir obsolète et est signalée comme invérifiable — c'est l'échec que cette compétence cherche à éviter, donc obtenez les chemins corrects.
6. Rendez-la vivante
bash $S/install-hook.sh # post-commit ; --pre-push pour l'autre déclencheur
Le hook réexécute l'analyse et imprime un avis d'une ligne indiquant combien de sections sont devenues obsolètes, avec les détails dans .begin/stale.md. Il respecte core.hooksPath (husky) et les worktrees git, s'ajoute à un hook existant sans le corrompre, refuse de s'ajouter à un hook non shell, et ne touche jamais un fichier suivi. Supprimez-le avec --uninstall, qui ne supprime que son propre bloc.
/begin update
Lorsque l'utilisateur revient sur un dépôt qui a déjà un BEGIN.md :
node $S/refresh.mjs && cat .begin/stale.md
Réécrivez uniquement les sections obsolètes, réexécutez recon.sh pour rafraîchir la section 6, et retimbrez chaque section réécrite avec le nouveau sha HEAD. Laissez les sections actuelles identiques octet par octet — une mise à jour qui réécrit tout détruit à la fois la perception du lecteur de ce qui a changé et l'utilité de l'historique git.
S'il n'y a pas encore de BEGIN.md, /begin update est juste /begin : écrivez-en un.
Rapport
Un court paragraphe : le mécanisme fondamental, le ou les deux fichiers qui comptent le plus et pourquoi, où l'utilisateur s'est arrêté, et la seule chose que vous n'avez pas pu vérifier. Les détails vivent dans BEGIN.md, pas dans la réponse.
Terminez par ce que vous n'avez pas vérifié. Un passage begin qui prétend à une couverture complète ment.
Limites connues — énoncez-les, ne les masquez pas
- Le graphe d'imports est statique. Un
import('./x')littéral est résolu (et marqué paresseux) ; unimport(expr)calculé, un conteneur DI, ou un registre indexé par chaîne ne produit aucune arête du tout, donc un tel fichier peut sembler inaccessible tout en étant essentiel. Dans un dépôt multilingue, la jointure frontend↔backend est un appel HTTP ou WebSocket et est invisible par construction. L'analyse signale les fichiers inaccessibles précisément pour qu'un humain puisse juger. - Résolution complète JS/TS et Python —
tsconfigpaths(toute configuration dans l'arbre, pas seulement la racine),extends,referencesde projet, NodeNext./x.js→x.ts, et imports Python absolus, relatifs et de sous-module par rapport aux racines déduites (mesurée à ~98% de rappel et de précision par rapport à une vérité terrain CPythonast). Go, Rust, Ruby, Java, Kotlin, Swift, PHP, C# et C/C++ ne contribuent aucune arête du tout. Dans un tel dépôt, chaque fichier montre une importance minimale et semble « inaccessible » ; l'analyse émet un avertissement, et vous devez répéter cet avertissement plutôt que de signaler un graphe vide comme une constatation. complexityProxycompte les points de décision par langue, dans du code avec des commentaires et des chaînes monolignes supprimés. Les fichiers de balisage et de schéma obtiennent un score de 0 par conception ; les fichiers vendus, minifiés et générés sont détectés et classés séparément. Les littéraux de template multilignes sont toujours comptés, donc un fichier riche en templates peut sembler un peu plus chaud.- L'activité est limitée par
--since, et un clone peu profond ou frais n'en a aucune — l'analyse le dit haut et fort. Un fichier réécrit une fois il y a deux ans obtient toujours un score proche de zéro et peut toujours être le fichier le plus important du dépôt.
Tests
node $S/test-scan.mjs # graphe, cycles, surfaces, accessibilité, Python
node $S/test-scan.mjs --mutate pyDotDot # ... et prouver que les assertions peuvent passer au rouge
bash $S/test-living.sh # obsolescence, hooks, propreté de l'arbre
node $S/redact.mjs --self-test # secrets attrapés ET texte propre intact
Chaque assertion existe parce que ce bug était réel et a été livré une fois. Mutations :
alias, jsToTs, valueCycle, typeCycle, pyAbsolute, pyDotDot — chacune doit faire passer son assertion au rouge, et CI échoue si ce n'est pas le cas.