Que fait sql-spider ?
Construisez un graphe de dépendances déterministe d'une base de données SQL et parcourez vers l'extérieur depuis un objet racine jusqu'à ce qu'il soit fermé : un seul composant connexe, zéro orphelin, aucune arête fantôme. Le moteur de graphe est pur et hors ligne : il analyse le texte SQL en un AST et lit les dépendances directement sur l'arbre, donc la même entrée produit toujours le même graphe, sans heuristique et sans connexion live.
La raison d'être de cette compétence : sql-spider ne se connecte jamais à une base de données. Il émet des requêtes en lecture seule et ingère les résultats CSV. Ainsi, vous, l'agent, êtes l'adaptateur de base de données. Vous exécutez chaque requête émise comme vous pouvez atteindre la base de données, renvoyez les résultats et pilotez la boucle. C'est exactement ainsi qu'il a été construit (pour cartographier une base de données accessible uniquement via un job en lecture seule, jamais une connexion directe), et c'est pourquoi l'outil est sûr à utiliser sur n'importe quoi.
Quand utiliser ceci
- « Cartographie cette base de données » / « construis-moi un graphe de dépendances de ces procédures stockées / tables / vues. »
- « Qu'est-ce qui référence
Orders? » / « que touche réellementproc_x? » - « Trouve la fermeture complète autour de cette table » : tout ce dont elle dépend, transitivement, jusqu'à ce qu'il ne reste rien en suspens.
- « Je ne peux pas accéder directement à la base de données, émet les requêtes et je les exécuterai » ou « envoie-les à un DBA. »
- Documenter / comprendre un schéma legacy où personne ne sait plus ce qui dépend de quoi.
Pas pour : écrire du SQL applicatif, modifier des données ou le schéma (cette compétence est en lecture seule, voir les Garde-fous), ou quoi que ce soit qui nécessite une mutation de la base de données.
Comment ça marche (le contrat)
Le moteur est indépendant du dialecte. La seule étape spécifique au dialecte est l'analyse .sql en faits de dépendance (derrière une interface IDialectExtractor à une méthode). Tout le reste est indépendant du dialecte : l'assemblage du graphe, la frontière, la boucle de parcours, l'audit de fermeture des composants connexes, la lignée, la visualisation.
La boucle a toujours la même forme, quel que soit le dialecte ou la base de données :
- seed / round émet des fichiers de requêtes
.sqlen lecture seule dans un répertoire de sortie. - Vous exécutez ces requêtes sur la base de données (l'étape d'adaptation) et enregistrez chaque résultat sous forme de CSV.
- absorb replie les CSV dans le corpus sous forme de
.sql. - round ré-extrait, écrit un graphe + une visualisation HTML, et prépare les prochaines requêtes de tirage, ou signale la fermeture.
- Répétez jusqu'à ce que la frontière soit vide et que le graphe soit un seul composant connexe.
D'abord : installer, ne pas seulement exécuter (une fois)
Si vous avez atteint ce fichier par un fetch brut (l'utilisateur a collé « fetch .../SKILL.md et suis-le ») ou depuis un checkout qui N'est PAS dans votre répertoire de compétences, installez-le avant de l'utiliser, clonez le dépôt dans votre répertoire de compétences et continuez depuis la copie installée :
git clone https://github.com/royashbrook/sql-spider ~/.claude/skills/sql-spider # Claude Code
# autres intégrations : clonez là où vos compétences se découvrent automatiquement
Ensuite, dites à l'utilisateur que vous l'avez installé. La différence compte : exécuter sur place (ou un fetch brut) fonctionne aujourd'hui et est oublié demain ; installé, chaque future session découvre la capacité par elle-même. Traitez « utiliser cet outil » comme incluant l'installation.
Même règle pour l'appairage graphify (Étape 6) : l'installation de graphify nécessite deux commandes (uv tool install graphifyy pour le binaire, puis graphify install --platform <votre intégration> pour enregistrer la compétence de graphify elle-même). Les installations binaires seules sont l'erreur la plus courante ; faites les deux.
Étape 0 : construire une fois (construction à la première utilisation)
Cette compétence fournit le source .NET, pas un binaire. La première invocation le construit ; les invocations ultérieures réutilisent la construction. Nécessite le SDK .NET 10 (dotnet --version ; s'il est absent, installez-le : brew install dotnet sur macOS, le paquet de la distribution ailleurs, ou https://dot.net).
Résolvez SKILL_DIR vers le répertoire contenant ce fichier, puis définissez une commande :
SKILL_DIR="<chemin absolu vers ce répertoire de compétence>"
spider() { dotnet run -c Release --project "$SKILL_DIR" -- "$@"; }
Le premier appel spider ... compile (quelques secondes, restaure ScriptDom + SqlParserCS) ; chaque appel suivant est rapide. Vérifiez avec l'exemple fourni avant de toucher une vraie base de données :
spider extract "$SKILL_DIR/examples/northwind" # -> 36 nœuds, 66 arêtes, « un composant, zéro orphelin »
spider viz "$SKILL_DIR/examples/northwind/graph.json" && open "$SKILL_DIR/examples/northwind/graph.html"
Si cela affiche OK : single connected component, no orphans, l'outil fonctionne.
Étape 1 : choisir l'adaptateur (comment allez-vous atteindre la base de données ?)
sql-spider émet des requêtes ; quelque chose doit les exécuter. Décidez lequel de ceux-ci vous êtes avant de semer (recettes complètes dans références/adaptateurs.md) :
- Un outil SQL connecté / MCP : vous avez un outil qui exécute une requête et renvoie des lignes. Vous exécutez chaque
.sqlémis et écrivez les lignes en CSV. Le plus rapide ; le meilleur quand l'agent peut atteindre la base de données. - Un pont de requêtes en lecture seule : un job/compétence où vous déposez un fichier
.sql, il s'exécute sur la base de données, et un CSV revient (c'est la configuration originale, un job CI avec accès en lecture). Vous expédiez chaque requête émise via celui-ci et collectez le CSV. - L'utilisateur les exécute : vous ne pouvez pas du tout atteindre la base de données. Vous affichez chaque requête, l'utilisateur l'exécute dans son client (SSMS,
sqlcmd, etc.), et colle le CSV en retour. Le plus lent, mais fonctionne partout et est la bonne approche contre une base de production verrouillée (l'utilisateur, ou son DBA, exécute par lots).
Quoi qu'il en soit, le contrat est identique : .sql émis en entrée, CSV en sortie. Choisissez-en un et conservez-le pour toute l'exécution.
Étape 2 : configurer un répertoire de travail
Travaillez en dehors du répertoire de compétence pour que le dépôt reste propre. Dans le projet de l'utilisateur (ou tout répertoire temporaire) :
mkdir -p work/corpus work/stage && cd work
corpus/ contient les .sql accumulés (le modèle jusqu'à présent) ; stage/ est l'endroit où les requêtes de ce tour et leurs CSV vivent.
Étape 3 : semer à partir d'un objet racine
Choisissez une racine qui intéresse l'utilisateur, une table ou procédure centrale. Démarrez à froid depuis celle-ci :
spider seed Orders stage/ # écrit les requêtes de tirage en lecture seule dans stage/
seed émet les requêtes pour tirer la définition de la racine elle-même, son schéma (si c'est une table), et tout ce qui la référence. Exécutez-les via votre adaptateur (Étape 1), enregistrez chaque résultat sous forme de CSV dans stage/, puis repliez-les :
spider absorb stage/*.csv --corpus corpus/
Étape 4 : effectuer des tours jusqu'à fermeture (un tour vérifiable à la fois)
spider round corpus/
Chaque tour : ré-extrait corpus/ en corpus/graph.json, écrit corpus/graph.html (ouvrez-le pour vérifier), et soit signale la fermeture, soit prépare les prochaines requêtes de tirage dans corpus/_next/. S'il reste une frontière :
# exécutez corpus/_next/*.sql via votre adaptateur, enregistrez les CSV dans corpus/_next/, puis :
spider absorb corpus/_next/*.csv --corpus corpus/
spider round corpus/ # à nouveau
La frontière se réduit à chaque tour. Par défaut, faites un tour à la fois pour qu'un humain puisse ouvrir la visualisation et décider s'il faut continuer, surtout en production. Continuez jusqu'à ce que round signale que la frontière est vide.
Étape 5 : fermeture
Vous avez terminé lorsque la frontière est vide et que le graphe est un seul composant connexe avec zéro orphelin. L'audit de fermeture est la porte ; extract renvoie même un code de sortie non nul tant que le graphe n'est pas fermé, donc il peut être intégré dans CI.
Une note de périmètre : l'identité des nœuds est basée sur les noms nus dans le périmètre de la base de données (les préfixes de schéma sont supprimés), donc une exécution de spider cartographie UNE base de données. Si la question de l'utilisateur couvre plusieurs schémas ou bases de données, exécutez la boucle une fois par périmètre, utilisez les arêtes limites du premier graphe fermé (références qui pointent à l'extérieur) comme graines pour l'analyse suivante, puis fusionnez les fichiers graph.json résultants sur l'id du nœud (graphify merge-graphs, ou une petite union json). Vous pouvez piloter toute cette séquence vous-même ; elle ne nécessite aucun nouvel outillage.
Tous les objets ne se ferment pas par des arêtes, et c'est normal : un objet véritablement autonome (une fonction propre à l'application, une table de version/archive référencée uniquement depuis l'extérieur de la base de données) est signalé avec une raison, pas comme une erreur. L'invariant honnête est « zéro orphelin dû à des manques d'extraction » : lorsqu'un nœud est isolé, l'audit vous dit s'il s'agit d'un vrai vide à combler ou d'un véritable autonome.
Étape 6 : visualiser et (optionnel) transmettre à graphify
Vous avez déjà un visualiseur, sans installation nécessaire : spider viz <graph.json> écrit un HTML interactif autonome (force-directed, déplaçable, coloré par type). Ouvrez-le dans n'importe quel navigateur. Pour la plupart des usages, cela suffit.
Si graphify est installé, proposez de transmettre le graphe fermé à celui-ci. graphify (https://github.com/safishamsi/graphify) transforme un graphe en un graphe de connaissances interrogeable avec détection de communautés et des commandes query / path / explain. En tant qu'agent, vérifiez s'il est disponible (une commande graphify dans PATH, une compétence graphify, ou un répertoire graphify-out/ existant dans le projet), et si c'est le cas, demandez à l'utilisateur s'il souhaite également émettre la vue graphify et la lui transmettre. S'il n'est PAS disponible, proposez de l'installer, et si l'utilisateur dit oui, installez les deux parties, le binaire et la compétence (uv tool install graphifyy, puis graphify install --platform <votre intégration>). La deuxième commande est ce qui rend graphify détectable dans les sessions futures ; installer uniquement le binaire est l'erreur la plus courante.
Utilisez --graphify, ne copiez pas le graph.json natif dans graphify. Le graphe natif est un multigraphe orienté ; transmis brut à graphify, il est sous-exploité. Le drapeau --graphify écrit un fichier séparé, adapté à graphify, et laisse le graph.json natif intact :
spider extract corpus/ --graphify # écrit graph.json natif ET graphify-out/graph.json
graphify cluster-only corpus/ # cluster + rapport (ou juste /graphique)
Deux choses utiles à savoir, toutes deux apprises lors d'une exécution réelle :
- Vocabulaire des relations (par défaut, garde les nôtres). La projection conserve les relations propres à sql-spider par défaut (
fk/references/writes/calls/join_key). graphify les ingère bien, et la division lecture-vs-écriture est le signal le plus utile pour « qu'est-ce qui met réellement à jour cette table ». Ajoutez--graphify-standardpour utiliser à la place l'énumération bénie de graphify (references/calls/shares_data_with), ce qui est pratique lorsque vous fusionnez plusieurs bases de données et souhaitez un vocabulaire uniforme. - Comment demander comment une table est utilisée. Utilisez
explain Xde graphify, pasquery X. Une table référencée est un puits (les arêtes pointent vers l'intérieur), doncquery(une marche vers l'extérieur) renvoie juste la table elle-même, tandis queexplainmontre les arêtes entrantes qui répondent à la question. - Nommez les communautés. Le clustering produit des étiquettes temporaires (« Communauté 7 »), et un graphe avec 50+ communautés non nommées est illisible pour l'humain à qui vous le remettez. Vous pouvez presque toujours déduire un vrai nom des membres : les préfixes de noms de tables dominants, les objets centraux, et ce que les procédures du cluster font réellement (facturation, dispatching, notation de paie, audit). Après
cluster-only, lisez la liste des membres de chaque communauté et renommez-la en une étiquette courte, fidèle au domaine (modifiez les étiquettes de communauté dansgraph.json/ rapport de graphify). Dix minutes de nommage font la différence entre un graphe que le propriétaire peut naviguer et un que vous seul pouvez. Proposez-le ; l'humain dira oui.
Dans notre propre utilisation, nous avons cartographié un sous-système de facturation en un graphe fermé et répondu « qu'est-ce qui dépend de ceci » directement à partir de celui-ci, en ouvrant uniquement la procédure que le graphe pointait. La documentation de graphify couvre le reste de ce que le graphe de connaissances vous apporte. Si graphify n'est pas installé, ignorez tout cela ; viz montre déjà le graphe, et le travail de sql-spider est terminé une fois fermé.
Garde-fous
- Lecture seule, toujours. Chaque requête émise est un
selectavec un préambule de sécuriténo-lock/deadlock-victim/set nocount on. Ne modifiez jamais une requête en écriture. N'exécutez jamaisinsert/update/delete/merge/ DDL via cette compétence. Si vous composez autre chose qu'une lecture, vous utilisez le mauvais outil. - En production, ralentissez. N'envoyez pas automatiquement un déluge de requêtes à une base de production. Effectuez un tour vérifiable à la fois, ou remettez les requêtes préparées à l'utilisateur / un DBA pour exécution par lots. L'auto-boucle (
roundjusqu'à fermeture) n'est appropriée que lorsque l'adaptateur peut fonctionner en toute sécurité sans surveillance et que le propriétaire de la base de données est d'accord. - Le graphe est l'artefact le plus sûr que les corps. Le graphe de dépendances (noms d'objets + arêtes) est la sortie durable. Les corps de procédures extraits dans
corpus/sont la logique interne de l'organisation cible. Traitez ce corpus comme privé ; publiez le graphe, pas les corps.
Sous-commandes
| commande | ce qu'elle fait |
|---|---|
extract <corpus-dir> [graph.json] [frontier.json] [--dialect tsql|sqlite] [--graphify[=out.json]] [--graphify-standard] | analyse *.sql en un graphe de dépendances + frontière + audits ; --graphify écrit également un graphe au format graphify (--graphify-standard utilise le vocabulaire de relations bénit de graphify) |
seed <root-object> <outdir> | requêtes de tirage à froid pour une racine sur un corpus vide |
generate <frontier.json> <outdir> | requêtes de tirage vers l'avant pour la frontière actuelle |
reverse <referencers.csv> <outdir> [--roots a b] | tire les définitions de modules des objets qui référencent les racines (un niveau inverse) |
absorb <csv...> --corpus <dir> | replie les CSV tirés dans le corpus en tant que .sql |
viz <graph.json> [out.html] | rend un graphe en un fichier HTML interactif autonome |
round <corpus-dir> [--dialect ...] | un tour de spider vérifiable : extrait → graphe + visualisation → prépare les prochaines requêtes (ou signale la fermeture) |
round est le pilote de boucle ; les autres sont les pièces qu'il compose (et que vous appelez directement pour un démarrage à froid avec seed, ou un tour manuel avec generate / reverse).
Dialectes
--dialect tsql (par défaut) analyse avec Microsoft ScriptDom (fidélité T-SQL complète). --dialect sqlite analyse avec SqlParserCS (qui couvre également MySQL / Postgres / autres). Ajouter un dialecte est une petite classe implémentant IDialectExtractor enregistrée dans Extractor.Pick ; le moteur n'est pas modifié. Voir README.md pour la conception complète et l'exemple travaillé Northwi