aviralmansingka/c4

Vues d'architecture C4 — niveaux contexte système, conteneurs et composants — collectées à partir d'une base de code à l'aide de sous-agents scouts. Construit une échelle de niveaux (L0 contexte système, L1/L1b conteneurs, L2/L2b composants) sous forme de boîtes conteneurs sur le canevas visualize, avec les systèmes externes en dehors de chaque boîte et une description encapsulée par niveau.

Qu'est-ce que c4 ?

Cette compétence génère des diagrammes d'architecture C4 (contexte, conteneurs, composants) en utilisant le moteur `visualize` et des sous-agents scouts pour explorer la base de code. Elle est utile pour comprendre la structure d'un système logicielles, ses dépendances et ses relations, sans connaissance préalable du code. Fonctionne avec Claude Code, Cursor, Codex et d'autres agents via le moteur `visualize` et les appels `subagent`. Quatre scouts (Scope, Relationships, Boundary, Levels) collectent des preuves avec des références fichier:ligne, puis les fusionnent en un registre unique. L'échelle de niveaux (L0 à L2b) est construite avec des boîtes conteneurs, des nœuds et des arêtes, en respectant une discipline de priorisation (tests I1-I5) et de déclassement (C1-C4). Les conflits sont résolus par la source la plus forte, et les questions ouvertes sont enregistrées. Le résultat est un canevas rataflow avec cinq sections, une direction de lecture unique et des descriptions par niveau.

Compatible avec✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/aviralmansingka/dotfiles/tree/HEAD/agents/.agents/skills/c4

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · 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

Que fait c4 ?

C4 répond à "qu'est-ce que ce système, de quoi est-il fait, et qui appelle qui" à trois niveaux de zoom. La surface est le moteur visualize : un canevas rataflow, une section décrite par niveau, des boîtes containers pour la propriété. Lisez agents/.agents/skills/visualize/SKILL.md pour le rendu lui-même — cette compétence ne couvre que ce que C4 ajoute.

C4 ajoute trois choses que visualize ne fait pas :

  1. Une échelle de niveaux. Contexte L0, puis conteneurs L1/L1b, puis composants L2/L2b. Chaque niveau existe pour motiver le suivant, et le niveau où se trouve le lecteur est visible depuis la boîte, pas depuis une légende.
  2. La collecte de faits. C4 doit être complet sur qui appelle quoi et pourquoi. Les scouts lisent la base de code et produisent un inventaire d'éléments et de relations soutenu par des preuves avant que toute spécification n'existe.
  3. Le confinement comme une affirmation. Une boîte conteneur contient les propres parties du composant et rien d'autre. C'est une affirmation de propriété, donc elle a besoin de sources, et elle doit survivre à la vérification de la boîte par le lecteur contre le code.

N'inventez pas un élément, une relation ou une limite. Si les scouts ne peuvent pas le citer, il n'est pas dessiné.

Routage

DemandeUtilisation
Niveaux C4 d'un composant dans une base de code réellecette compétence
Un graphe de relations à partir de faits que vous possédez déjàvisualize
Diagramme dans la réponse du chatoutil mermaid
ANSI / PNG statiquecompétence mermaid
Page prose d'architecture ou deckcompétence artifact

/c4 <composant> ou "donne-moi une vue C4 de X" est l'invocation. La compétence fonctionne dans un dépôt qu'elle n'a jamais vu : les scouts sont le seul moyen pour elle d'apprendre quoi que ce soit, donc rien ici ne dépend d'une connaissance préalable du code.

Étape 0 — Épingler le composant

Indiquez, avant que tout scout ne s'exécute :

composant  : gestionnaire de machines
racine dep : /Users/aviral/modal
ancre      : machine_manager/  (un paquet, un déployable)
  • Composant est une chose qu'un lecteur peut pointer dans le code : un service, un paquet, une unité déployable. Si la demande nomme un sous-système qui couvre plusieurs déployables, choisissez le déployable et dites quels voisins il attire comme externes.
  • Racine dep est le point de départ des scouts. Confirmez que le checkout existe ; ne supposez pas un chemin.
  • Ancre est la preuve unique la plus forte que le composant est une seule chose (manifeste de paquet, chart Helm, module Terraform, service proto, main.go). Si vous ne pouvez pas en nommer une, le composant est probablement deux composants — demandez à l'humain plutôt que de deviner.

Posez au plus une question de clarification (la limite du composant est la seule qui vaut la peine d'être posée). Sinon, décidez et enregistrez.

Étape 1 — Lancer les scouts

Quatre invites se trouvent dans prompts/ ; chacune est une tâche complète de sous-agent. Lancez-les comme des appels subagent avec agent: "scout" (reconnaissance en lecture seule — les scouts ne doivent pas modifier le dépôt), toutes les quatre en un seul tour pour qu'elles s'exécutent en parallèle, cwd: la racine du dépôt résolue à l'étape 0, et le nom du composant substitué à <composant> :

ScoutInviteRetourne
Scopeprompts/scope.mdinventaire des éléments : id, rôle en une ligne, points d'entrée, déployables, magasins, services externes, acteurs, chemins de fichiers
Relationshipsprompts/relationships.mdlignes de → vers : verbe + transport, chacune avec fichier:ligne
Boundaryprompts/boundary.mdmembres vs externes + la limite de module/déploiement qui justifie chaque appartenance
Levelsprompts/levels.mdaffectation de niveau par élément, et quels niveaux doivent se diviser en L1/L1b (L2/L2b)

Chaque scout retourne une preuve avec des références fichier:ligne. Une ligne sans référence est une rumeur ; supprimez-la ou redemandez à ce scout une source.

Lancez les scouts depuis la racine du dépôt — exécutez la session là-bas (ou faites en sorte que cwd: soit le même répertoire où se trouve déjà la session). Un scout dont le cwd diffère de celui de la session de lancement peut mourir avant que son processus ne démarre, et l'échec se lit comme "aucun processus pi n'est apparu dans son panneau".

Ne sondez pas les sous-agents. Les résultats arrivent d'eux-mêmes ; continuez lorsque les quatre sont de retour. Si l'un échoue, dites lequel, et soit réessayez, soit enregistrez l'écart dans l'enregistrement de génération — ne comblez jamais le trou à partir de la mémoire.

Étape 2 — Reconcilier en un seul registre

Fusionnez les quatre retours en trois tables dans l'enregistrement de génération. C'est toute la base de faits ; la spécification ne peut contenir rien qui ne soit pas ici.

elements  : id | étiquette | rôle | classe (acteur|externe|membre|magasin) | preuve
relations : id | de → vers | verbe + transport | niveau | preuve
limite    : id | dedans/dehors | limite justificative | preuve
  • Les conflits sont résolus en citant la source la plus forte (un manifeste ou un graph de déploiement bat un commentaire ; un site d'appel bat une docstring), et la réclamation perdante est enregistrée, pas supprimée.
  • Les conflits non résolus et les relations sans source survivante sont enregistrés comme des questions ouvertes. Le silence est un défaut ; un doute visible ne l'est pas.
  • Gardez un identifiant par élément et réutilisez-le entre les niveaux, de sorte qu'un lecteur qui suit q → reg voie les deux mêmes boîtes à L1 et L2.

Étape 3 — Que dessiner (priorisation)

Une vue C4 est un jugement sur l'importance, pas un vidage du graphe d'appels. Le registre contient toutes les relations qu'un scout a trouvées ; le diagramme contient celles dont un lecteur a besoin, et dit à voix haute ce qu'il a omis.

Une relation gagne sa place lorsqu'elle satisfait au moins un de ces critères :

idtestexemple
I1elle traverse la limite du composant (membre ↔ externe, externe ↔ externe)webapi → API Latitude, machines → sshx.io
I2c'est un chemin de requête, de contrôle ou de données principal que la source mentionne (provision, battement de cœur, audit, réconciliation, démarrage)plan de contrôle → gRPC privé, file River → workers
I3elle porte un protocole ou un qualificatif dont le lecteur a besoin : verbe RPC, transport, port, seau, intervalle, délai d'attenteregister + battement de cœur toutes les 1 min, sync gcore toutes les 1 min
I4elle explique un magasin de données ou un acteur que le lecteur ne peut pas déduire des boîtesmagasin → Postgres, ops + mmctl → webapi
I5c'est une branche d'un chemin redondant ou parallèle qui doit rester comptablemachines → boot et boot → machines ; deux tirages indépendants

Classes de suppression — une relation ne quitte le diagramme que comme l'un de ceux-ci :

idclassece que c'est
C1détail interneentièrement à l'intérieur d'un conteneur, n'ajoute ni limite, ni protocole, ni information d'acteur (worker → magasin ligne par requête lorsque les rédacteurs du magasin sont déjà dessinés)
C2site d'appel en doublele même saut qu'une relation dessinée, ne différant que par le type de travail ou l'argument, que l'étiquette dessinée porte déjà
C3assistantun élément dont le seul travail est de rentrer dans le même conteneur (un wrapper client entre deux boîtes dessinées)
C4branche redondanteune autre branche parallèle d'un chemin dont la comptabilité n'est pas nécessaire au lecteur (un deuxième artefact du même seau, même transport)

Règles qui maintiennent le jugement honnête :

  • Une flèche peut porter plusieurs sites d'appel lorsque l'étiquette porte leurs verbes (créer / terminer / réparer). C'est un pliage C2, pas une suppression.
  • Le franchissement de limite gagne un match nul (I1 avant I3 avant I2). Un diagramme qui laisse tomber un saut externe pour faire de la place à un interne a inversé ses propres priorités.
  • En cas de doute, dessinez-le, et laissez la description du niveau dire pourquoi il est là. Le doute n'est pas une raison de suppression ; C1–C4 le sont.
  • Ne supprimez jamais en silence. Chaque ligne du registre se termine comme : dessiné, plié dans <relation dessinée> (avec le pli justifié comme C2), ou omis — C1|C2|C3|C4 avec une ligne expliquant pourquoi. La carte de couverture (Étape 7) indique les quatre comptes : dessiné, plié, omis par classe, non comptabilisé.
  • La réduction de périmètre est une chose différente et a besoin des mots de l'appelant. "Seulement la vue du plan de contrôle" ou "20 relations max" est une demande de périmètre : enregistrez-la comme base (base: périmètre de l'appelant, N relations) à côté du registre compté. La priorisation est la valeur par défaut ; un sous-ensemble est une décision que l'appelant prend, pas une que le générateur déduit.

Étape 4 — L'échelle de niveaux

La forme cible est de cinq sections, de haut en bas :

L0 · Contexte système      un nœud pour le composant + ses voisins
L1 · Le composant          le composant ouvert une fois, conteneur sur ses parties
L1b · <deuxième côté>      la même profondeur, l'autre côté du système
L2 · À l'intérieur — <tranche A>  relations entre membres, conteneur sur elles
L2b · À l'intérieur — <tranche B> la même profondeur, l'autre tranche

Voilà l'échelle : un canevas de cinq sections est le livrable. Plus de sections est un défaut à moins que la discipline de fractionnement ci-dessous soit satisfaite, avec des nombres.

Dessinez chaque niveau seulement après que celui au-dessus existe, et donnez à chacun sa description avant de passer au suivant.

NiveauDessineComportement de la boîte
L0 contexte systèmele composant comme UN nœud simple, plus chaque acteur et système externe autour, plus les flèches grossières entre euxpas de conteneur, pas de focus, pas de double bordure — le but est le monde environnant, donc le composant ressemble à n'importe quelle autre boîte
L1 conteneursle composant ouvert d'un niveau : ses propres unités déployables/exécutables à l'intérieur d'un conteneur ; les externes de L0 restent à l'extérieurboîte conteneur sur les membres
L1b vue latéralela deuxième tranche optionnelle lorsqu'un seul L1 ne peut vraiment pas contenir le flux (l'extrémité de la flotte, le plan de données, le chemin par lots) — mesurée, jamais un nouveau sujetconteneur, mêmes règles
L2 composantsles relations à l'intérieur d'un conteneur — les membres de L1, s'appelant maintenant les uns les autresboîte conteneur autour d'eux
L2bdeuxième tranche optionnelle de la même profondeur lorsqu'un L2 ne peut pas acheminer ses relations, ou que deux histoires ont besoin de rangs séparésconteneur, mêmes règles

Règles de niveau qui ne sont pas négociables :

  • L0 est le composant comme UN nœud simple. Une boîte pour tout le composant, sa bordure normale, plus les acteurs et systèmes externes autour. Pas ses parties, pas ses écouteurs, pas ses tables — ceux-ci sont le niveau suivant. Si L0 a plus d'un nœud qui appartient à l'intérieur du composant, ce n'est pas une vue de contexte. Le confinement à L0 prétendrait à des internes que le lecteur n'a pas encore vus, et focus pointerait vers un niveau qui n'existe pas encore.
  • L1/L1b ouvrent la boîte de L0. Chaque membre se trouve à l'intérieur du conteneur ; chaque élément qui était externe à L0 se trouve à l'extérieur. Un membre qui ne peut pas être dessiné en dehors de la boîte englobante obtient sa propre entrée de conteneur (voir Contiguïté) — jamais une boîte bricolée.
  • L2/L2b restent à l'intérieur d'une boîte. Les deux extrémités de chaque relation L2 sont des membres du conteneur. Si une relation quitte la boîte, elle appartient à L1/L1b.
  • Un niveau se décrit lui-même. Le titre est court (L0 · Contexte système) ; la description indique ce qui est à l'intérieur de la boîte, ce qui est à l'extérieur, et comment il se rapporte au niveau voisin. Visez 2–3 lignes encapsulées.
  • Le mouvement n'est pas une propriété C4. Les niveaux 0–1b sont statiques (points: 0). Un niveau interne dont les relations sont des flux en direct peut porter exactement un point par route (flux: oui, points: 1) ; enregistrez le choix. N'animez jamais une flèche externe pour décorer l'échelle.

Discipline de fractionnement — un niveau est une PROFONDEUR, pas un sujet

Un niveau C4 répond à une question à un zoom. Deux niveaux de la même profondeur n'existent que parce qu'une section ne pouvait pas contenir le contenu ; un nouveau sujet n'est pas une raison pour ajouter une section.

  • N'ajoutez jamais L1c, L1d, L1e ou un cinquième côté. L'échelle a trois profondeurs (contexte, conteneurs, composants) et au plus deux tranches à chaque profondeur en dessous de la première. Un canevas qui ajoute une tranche par sous-système ou par mention est une liste de sujets portant des titres de niveau.
  • Une deuxième tranche doit nommer sa mesure : les routes que --check refuse, le couloir partagé qu'elle signale, ou les rangs qui se heurtent (deux extrémités externes sans externe commun). "C'était bondé" n'en est pas une.
  • Les tranches de même profondeur partagent la boîte, les étiquettes et les identifiants. L1 et L1b dessinent le même composant avec les mêmes identifiants de membres ; L2 et L2b dessinent les mêmes membres. Seuls l'ensemble des arêtes et les rangs diffèrent, et chaque description dit de quelle tranche il s'agit.
  • Une tranche est nommée b (l1b, l2b) ; n'inventez jamais une profondeur.
  • La profondeur au-delà de L2 n'est pas dessinée. Si les internes des composants se décomposent encore, dites-le dans l'enregistrement et arrêtez : les classes de code et les fonctions ne sont pas un niveau C4 qu'un lecteur a demandé. L'échelle se termine là où la demande se termine.
  • Tout ce que le registre contient et que l'échelle ne dessine pas est une décision de périmètre, écrite (Étape 6), pas une suppression silencieuse et pas une nouvelle section.

Étape 5 — Mécanique de spécification

Un canevas, une direction de lecture, une section par niveau :

{
  "direction": "lr",
  "theme": "gruvbox",
  "diagrams": [
    {
      "id": "l0",
      "title": "L0 · Contexte système",
      "description": "Contexte système : le gestionnaire est une boîte. ...",
      "nodes": [ ... ],
      "edges": [ ... ]
    },
    {
      "id": "l1",
      "title": "L1 · Le gestionnaire",
      "description": "La boîte de L0 ouverte d'un niveau : ...",
      "containers": [ { "label": "Gestionnaire de machines", "members": ["api", "q", "db"] } ],
      "layers": [ ["actor"], ["api", "q"], ["db"], ["prov"] ],
      "nodes": [ ... ],
      "edges": [ ... ]
    }
  ]
}
  • direction: "lr" une fois, sur le canevas. Jamais de remplacement par diagramme : un lecteur qui se réoriente à chaque section a perdu l'échelle.
  • Cinq sections. l0, l1, l1b, l2, l2b, dans cet ordre. Une sixième section nécessite que la mesure de l'étape 3 soit enregistrée ; un canevas de dix ou vingt sections est une liste de sujets, pas une échelle — repliez-le à trois profondeurs, deux tranches chacune.
  • containers est une liste par diagramme de {label, members}. La boîte est un vrai rectangle à double bordure qui grandit autour des membres, avec l'étiquette placée dans son bord supérieur. Plusieurs boîtes par diagramme sont autorisées.
  • Les identifiants de membres doivent exister dans les nodes de ce diagramme. Un identifiant de membre qui ne nomme aucun nœud est silencieusement ignoré par l'analyseur — la boîte se dessine alors autour de moins de nœuds que vous n'avez déclarés et --check n'avertit pas. Comptez la boîte dessinée par rapport aux membres que vous avez déclarés.
  • Règle de contiguïté. Un conteneur est un rect ...

[Le reste du contenu original a été tronqué pour la traduction ; la compétence complète continue avec les étapes suivantes.]

Skills associés