CommunityCodierung & Entwicklunggithub.com

aviralmansingka/c4

C4-Architekturansichten – Systemkontext, Container- und Komponentenebenen – gesammelt aus einer Codebasis mit Scout-Subagenten. Baut eine Ebenenleiter (L0 Systemkontext, L1/L1b Container, L2/L2b Komponenten) als Container-Boxen auf der Visualisierungs-Leinwand auf, mit externen Systemen außerhalb jeder Box und einer beschriebenen Beschreibung pro Ebene.

Was ist c4?

Dieses Skill automatisiert die Erstellung von C4-Architekturdiagrammen (nach Simon Brown) direkt aus dem Code eines Repositorys. Es verwendet vier spezialisierte Scout-Subagenten (Scope, Relationships, Boundary, Levels), die die Codebasis parallel lesen, um Fakten zu sammeln, anstatt sich auf vordefinierte Modelle zu verlassen. Das Ergebnis ist eine fünfstufige Ebenenleiter, die auf der vorhandenen Visualisierungs-Engine basiert: Systemkontext (L0), Container (L1/L1b) und Komponenten (L2/L2b). Jede Ebene wird als eigener Abschnitt auf der Leinwand mit einheitlicher Leserichtung dargestellt, wobei externe Systeme außerhalb der Container-Boxen positioniert werden. Der Skill erzwingt strenge Regeln: Elemente und Beziehungen müssen durch Datei- und Zeilenreferenzen belegt sein, Container-Boxen repräsentieren echte Eigentumsansprüche, und die Ebenentiefe ist auf drei Ebenen mit jeweils maximal zwei Slice-Bildern (z. B. L1 und L1b) beschränkt, um thematische Listen anstelle von Architekturdiagrammen zu verhindern. Er ist ideal für Entwickler, die ein neues Repository verstehen oder an der Technikdokumentation arbeiten, ohne bestehende Modelle zu benötigen.

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

Installed? Explore more Codierung & Entwicklung skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Was macht c4?

C4 beantwortet „Was ist dieses System, woraus besteht es und wer ruft wen?" auf drei Zoomstufen. Die Oberfläche ist die visualize-Engine: eine rataflow-Leinwand, ein beschriebener Abschnitt pro Ebene, containers-Boxen für Eigentum. Lies agents/.agents/skills/visualize/SKILL.md für den Renderer selbst – dieses Skill deckt nur ab, was C4 hinzufügt.

C4 fügt drei Dinge hinzu, die visualize nicht tut:

  1. Eine Ebenenleiter. L0-Kontext, dann L1/L1b-Container, dann L2/L2b- Komponenten. Jede Ebene dient dazu, die nächste zu motivieren, und die Ebene, auf der sich ein Leser befindet, ist an der Box erkennbar, nicht an einer Legende.
  2. Fakten sammeln. C4 muss vollständig sein, was wer wen warum ruft betrifft. Scouts lesen die Codebasis und erstellen ein beleggestütztes Element- und Beziehungsinventar, bevor eine Spezifikation existiert.
  3. Enthaltung als Behauptung. Eine Container-Box enthält die eigenen Teile der Komponente und nichts anderes. Das ist eine Eigentumsbehauptung, also benötigt sie Quellen, und sie muss überleben, dass ein Leser die Box gegen den Code prüft.

Erfinde kein Element, keine Beziehung und keine Grenze. Wenn die Scouts es nicht zitieren können, wird es nicht gezeichnet.

Routing

FrageVerwenden
C4-Ebenen einer Komponente in einer echten Codebasisdieses Skill
Ein Beziehungsdiagramm aus bereits vorhandenen Faktenvisualize
Diagramm in der Chat-Antwortmermaid-Tool
Statisches ANSI / PNGmermaid-Skill
Architektur-Prosa-Seite oder Präsentationartifact-Skill

/c4 <Komponente> oder „Gib mir eine C4-Ansicht von X" ist der Aufruf. Das Skill funktioniert in einem Repository, das es noch nie gesehen hat: Die Scouts sind die einzige Möglichkeit, wie es etwas lernt, also hängt hier nichts von Vorkenntnissen des Codes ab.

Schritt 0 – Die Komponente festlegen

Gib an, bevor ein Scout läuft:

component: Maschinenverwaltung
repo root: /Users/aviral/modal
anchor:    machine_manager/  (ein Paket, eine bereitstellbare Einheit)
  • Komponente ist eine Sache, auf die ein Leser im Code zeigen kann: ein Dienst, ein Paket, eine bereitstellbare Einheit. Wenn die Anfrage ein Subsystem benennt, das mehrere bereitstellbare Einheiten umfasst, wähle die bereitstellbare Einheit und sage, welche Nachbarn sie als externe Systeme einbezieht.
  • Repo root ist der Startpunkt für die Scouts. Bestätige, dass das Checkout existiert; nimm keinen Pfad an.
  • Anchor ist das stärkste einzelne Beweisstück dafür, dass die Komponente eine Sache ist (Paketmanifest, Helm-Chart, Terraform-Modul, Proto-Dienst, main.go). Wenn du keinen nennen kannst, ist die Komponente wahrscheinlich zwei Komponenten – frage den Menschen statt zu raten.

Stelle höchstens eine klärende Frage (die Komponentengrenze ist die einzige, die sich lohnt zu fragen). Ansonsten entscheide und dokumentiere.

Schritt 1 – Die Scouts starten

Vier Prompts befinden sich in prompts/; jeder ist eine vollständige Subagenten- Aufgabe. Starte sie als subagent-Aufrufe mit agent: "scout" (schreibgeschützte Erkundung – Scouts dürfen das Repository nicht bearbeiten), alle vier in einem Schritt, damit sie parallel laufen, cwd: die in Schritt 0 aufgelöste Repository-Wurzel, und der Komponentenname für <component> eingesetzt:

ScoutPromptRückgabe
Scopeprompts/scope.mdElementinventar: ID, Einzeiler-Rolle, Einstiegspunkte, bereitstellbare Einheiten, Datenspeicher, externe Dienste, Akteure, Dateipfade
Relationshipsprompts/relationships.mdvon → nach : Verb + Transport-Zeilen, jeweils mit Datei:Zeile
Boundaryprompts/boundary.mdMitglieder vs. Externe + die Modul-/Bereitstellungsgrenze, die jede Mitgliedschaft rechtfertigt
Levelsprompts/levels.mdEbenenzuweisung pro Element und welche Ebenen in L1/L1b (L2/L2b) aufgeteilt werden müssen

Jeder Scout gibt Belege mit Datei:Zeile-Referenzen zurück. Eine Zeile ohne solche ist ein Gerücht; verwerfe sie oder frage diesen Scout erneut nach einer Quelle.

Starte die Scouts vom Repository-Stammverzeichnis aus – führe die Sitzung dort aus (oder setze cwd: auf dasselbe Verzeichnis, in dem sich die Sitzung bereits befindet). Ein Scout, dessen cwd sich von dem der startenden Sitzung unterscheidet, kann sterben, bevor sein Prozess startet, und der Fehler erscheint als „In seinem Fenster erschien kein Pi-Prozess".

Befrage die Unteragenten nicht. Die Ergebnisse treffen von selbst ein; fahre fort, wenn alle vier zurück sind. Wenn einer fehlschlägt, sag welcher, und wiederhole ihn entweder oder dokumentiere die Lücke im Generierungsprotokoll – fülle das Loch niemals aus dem Gedächtnis.

Schritt 2 – In ein Hauptbuch abgleichen

Führe die vier Rückgaben in drei Tabellen im Generierungsprotokoll zusammen. Dies ist die gesamte Faktenbasis; die Spezifikation darf nichts enthalten, was nicht hier ist.

elemente:   id | label | rolle | klasse (akteur|extern|mitglied|speicher) | beleg
beziehungen: id | von → nach | verb + transport | ebene | beleg
grenze:     id | innen/außen | rechtfertigende grenze | beleg
  • Konflikte werden gelöst, indem die stärkere Quelle zitiert wird (ein Manifest oder Bereitstellungs-Chart schlägt einen Kommentar; eine Aufrufstelle schlägt einen Docstring), und die verlierende Behauptung wird aufgezeichnet, nicht gelöscht.
  • Ungelöste Konflikte und Beziehungen ohne überlebende Quelle werden als offene Fragen aufgezeichnet. Stille ist ein Fehler; ein sichtbarer Zweifel ist keiner.
  • Behalte eine ID pro Element bei und verwende sie über Ebenen hinweg wieder, damit ein Leser, der q → reg verfolgt, auf L1 und L2 dieselben zwei Boxen sieht.

Schritt 3 – Was zu zeichnen ist (Priorisierung)

Eine C4-Ansicht ist ein Urteil über die Wichtigkeit, kein Auszug des Aufrufgraphen. Das Hauptbuch enthält jede Beziehung, die ein Scout gefunden hat; das Diagramm enthält die, die ein Leser braucht, und sagt laut, was es weggelassen hat.

Eine Beziehung verdient einen Platz, wenn sie mindestens eines dieser Kriterien erfüllt:

IDTestBeispiel
I1Sie überschreitet die Komponentengrenze (Mitglied ↔ Extern, Extern ↔ Extern)webapi → Latitude API, machines → sshx.io
I2Es ist ein primärer Anforderungs-, Steuerungs- oder Datenpfad, den die Quelle ausdrücklich nennt (Provisionierung, Heartbeat, Audit, Abgleich, Boot)control plane → private gRPC, River queue → workers
I3Sie trägt ein Protokoll oder einen Qualifizierer, den der Leser braucht: RPC-Verb, Transport, Port, Bucket, Intervall, Timeoutregister + heartbeat alle 1 Min, gcore sync alle 1 Min
I4Sie erklärt einen Datenspeicher oder einen Akteur, den der Leser nicht aus den Boxen ableiten kannstore → Postgres, ops + mmctl → webapi
I5Es ist ein Zweig eines redundanten oder parallelen Pfades, der zählbar bleiben mussmachines → boot und boot → machines; zwei unabhängige Züge

Fallklassen – eine Beziehung verlässt das Diagramm nur als eine dieser:

IDKlasseWas es ist
C1internes Detailvollständig innerhalb eines Containers, fügt keine Grenz-, Protokoll- oder Akteursinformationen hinzu (worker → store pro Abfragezeile, wenn die Schreiber des Speichers bereits gezeichnet sind)
C2doppelte Aufrufstellederselbe Sprung wie eine gezeichnete Beziehung, der sich nur in Auftragstyp oder Argument unterscheidet, den die gezeichnete Beschriftung bereits trägt
C3Helferein Element, dessen einzige Aufgabe darin besteht, denselben Container erneut zu betreten (ein Client-Wrapper zwischen zwei gezeichneten Boxen)
C4redundanter Zweigein weiterer paralleler Zweig eines Pfades, dessen Zählbarkeit der Leser nicht benötigt (ein zweites Artefakt aus demselben Bucket, derselbe Transport)

Regeln, die das Urteil ehrlich halten:

  • Ein Pfeil kann mehrere Aufrufstellen tragen, wenn die Beschriftung ihre Verben trägt (erstellen / beenden / reparieren). Das ist eine C2-Faltung, keine Löschung.
  • Grenzüberschreitung gewinnt einen Gleichstand (I1 vor I3 vor I2). Ein Diagramm, das einen externen Sprung fallen lässt, um Platz für einen internen zu schaffen, hat seine eigenen Prioritäten umgekehrt.
  • Im Zweifel zeichne es, und lass die Beschreibung der Ebene sagen, warum es da ist. Zweifel ist kein Grund zum Fallenlassen; C1–C4 sind es.
  • Niemals stillschweigend fallen lassen. Jede Hauptbuchzeile endet als: gezeichnet, gefaltet in <gezeichnete Beziehung> (mit der Rechtfertigung der Faltung als C2), oder weggelassen – C1|C2|C3|C4 mit einer Zeile warum. Die Abdeckungskarte (Schritt 7) gibt die vier Zählungen an: gezeichnet, gefaltet, nach Klasse weggelassen, nicht berücksichtigt.
  • Umfangsreduzierung ist eine andere Sache und benötigt die Worte des Anrufers. „Nur die Steuerungsebene" oder „maximal 20 Beziehungen" ist eine Umfangsanfrage: dokumentiere sie als Grundlage (basis: caller scope, N relations) zusammen mit dem gezählten Hauptbuch. Priorisierung ist der Standard; eine Teilmenge ist eine Entscheidung, die der Anrufer trifft, nicht eine, die der Generator ableitet.

Schritt 4 – Die Ebenenleiter

Die Zielform sind fünf Abschnitte, von oben nach unten:

L0 · Systemkontext       ein Knoten für die Komponente + ihre Nachbarn
L1 · Die Komponente      die Komponente einmal geöffnet, Container auf ihren Teilen
L1b · <zweite Seite>     dieselbe Tiefe, die andere Seite des Systems
L2 · Innen – <Slice A>   Beziehungen zwischen Mitgliedern, Container auf ihnen
L2b · Innen – <Slice B>  dieselbe Tiefe, der andere Slice

Das ist die Leiter: eine Leinwand mit fünf Abschnitten ist das Ergebnis. Mehr Abschnitte sind ein Fehler, es sei denn, die unten stehende Aufteilungsdisziplin ist mit Zahlen erfüllt.

Zeichne jede Ebene erst nachdem die darüber liegende existiert, und gib jeder ihre Beschreibung, bevor du fortfährst.

EbeneZeichnetBox-Verhalten
L0 Systemkontextdie Komponente als EINEN einfachen Knoten, plus jeden Akteur und jedes externe System darum herum, plus die groben Pfeile zwischen ihnenkein Container, kein focus, keine Doppelrand – der Punkt ist die umgebende Welt, also sieht die Komponente aus wie jede andere Box
L1 Containerdie Komponente eine Ebene geöffnet: ihre eigenen bereitstellbaren/laufzeit Einheiten innerhalb eines Containers; die L0-Externen bleiben außenContainerbox auf den Mitgliedern
L1b Seitenansichtder optionale zweite Slice, wenn ein L1 den Fluss wirklich nicht halten kann (das Fleet-Ende, die Datenebene, der Batch-Pfad) – gemessen, niemals ein neues ThemaContainer, gleiche Regeln
L2 Komponentendie Beziehungen innerhalb eines Containers – die Mitglieder von L1, die sich nun gegenseitig aufrufenContainerbox um sie herum
L2boptionaler zweiter Slice derselben Tiefe, wenn ein L2 seine Beziehungen nicht routen kann oder zwei Geschichten separate Ränge benötigenContainer, gleiche Regeln

Ebenenregeln, die nicht verhandelbar sind:

  • L0 ist die Komponente als EINEN einfachen Knoten. Eine Box für die gesamte Komponente, ihre normale Umrandung, plus die Akteure und externen Systeme um sie herum. Nicht ihre Teile, nicht ihre Listener, nicht ihre Tabellen – das sind die nächste Ebene. Wenn L0 mehr als einen Knoten hat, der innerhalb der Komponente liegt, ist es keine Kontextansicht. Eine Containment bei L0 würde Interna beanspruchen, die dem Leser noch nicht gezeigt wurden, und focus würde auf eine Ebene zeigen, die noch nicht existiert.
  • L1/L1b öffnen die Box von L0. Jedes Mitglied sitzt innerhalb des Containers; jedes Element, das auf L0 ein Externes war, sitzt außerhalb. Ein Mitglied, das nicht innerhalb der Begrenzungsbox der Box gezeichnet werden kann, erhält einen eigenen Containereintrag (siehe Kontiguität) – niemals einen gefälschten.
  • L2/L2b bleiben innerhalb einer Box. Beide Endpunkte jeder L2-Beziehung sind Containermitglieder. Wenn eine Beziehung die Box verlässt, gehört sie auf L1/L1b.
  • Eine Ebene beschreibt sich selbst. Titel ist kurz (L0 · Systemkontext); die Beschreibung gibt an, was sich in der Box befindet, was außerhalb und wie sie sich zur benachbarten Ebene verhält. Ziel sind 2–3 umbrochene Zeilen.
  • Bewegung ist keine C4-Eigenschaft. Ebenen 0–1b sind statisch (dots: 0). Eine interne Ebene, deren Beziehungen Live-Flüsse sind, darf genau einen Punkt pro Route tragen (flow: true, dots: 1); dokumentiere die Wahl. Animiere niemals einen externen Pfeil, um die Leiter zu dekorieren.

Aufteilungsdisziplin – Eine Ebene ist eine TIEFE, kein Thema

Eine C4-Ebene beantwortet eine Frage auf einem Zoom. Zwei Ebenen derselben Tiefe existieren nur, weil ein Abschnitt den Inhalt nicht aufnehmen konnte; ein neues Thema ist kein Grund, einen Abschnitt hinzuzufügen.

  • Füge niemals L1c, L1d, L1e oder eine fünfte Seite hinzu. Die Leiter hat drei Tiefen (Kontext, Container, Komponenten) und höchstens zwei Slice-Bilder auf jeder Tiefe unterhalb der ersten. Eine Leinwand, die einen Slice pro Subsystem oder pro Erwähnung wächst, ist eine Themenliste, die Ebenentitel trägt.
  • Ein zweiter Slice muss seine Messung nennen: die Routen, die --check verweigert, den gemeinsamen Korridor, den er meldet, oder die Ränge, die kollidieren (zwei externe Enden ohne gemeinsames Externes). „Es fühlte sich überladen an" ist keine.
  • Slice-Bilder derselben Tiefe teilen sich die Box, die Beschriftungen und die IDs. L1 und L1b zeichnen dieselbe Komponente mit denselben Mitglieds-IDs; L2 und L2b zeichnen dieselben Mitglieder. Nur die Kantenmenge und die Ränge unterscheiden sich, und jede Beschreibung sagt, welcher Slice es ist.
  • Ein Slice wird b genannt (l1b, l2b); erfinde niemals eine Tiefe.
  • Tiefe über L2 hinaus wird nicht gezeichnet. Wenn Komponenteninterna immer noch zerfallen, sage dies im Protokoll und höre auf: Code-Klassen und Funktionen sind keine C4-Ebene, nach der ein Leser gefragt hat. Die Leiter endet dort, wo die Frage endet.
  • Alles, was das Hauptbuch enthält und die Leiter nicht zeichnet, ist eine Umfangsentscheidung, schriftlich festgehalten (Schritt 6), keine stillschweigende Löschung und kein neuer Abschnitt.

Schritt 5 – Spezifikationsmechanik

Eine Leinwand, eine Leserichtung, ein Abschnitt pro Ebene:

{
  "direction": "lr",
  "theme": "gruvbox",
  "diagrams": [
    {
      "id": "l0",
      "title": "L0 · Systemkontext",
      "description": "Systemkontext: Der Manager ist eine Box. ...",
      "nodes": [ ... ],
      "edges": [ ... ]
    },
    {
      "id": "l1",
      "title": "L1 · Der Manager",
      "description": "Die Box von L0 eine Ebene geöffnet: ...",
      "containers": [ { "label": "Maschinenverwaltung", "members": ["api", "q", "db"] } ],
      "layers": [ ["akteur"], ["api", "q"], ["db"], ["prov"] ],
      "nodes": [ ... ],
      "edges": [ ... ]
    }
  ]
}
  • direction: "lr" einmal, auf der Leinwand. Niemals eine Überschreibung pro Diagramm: Ein Leser, der sich bei jedem Abschnitt neu orientiert, hat die Leiter verloren.
  • Fünf Abschnitte. l0, l1, l1b, l2, l2b, in dieser Reihenfolge. Ein sechster Abschnitt benötigt die in Schritt 3 gemessene Aufzeichnung; eine Leinwand mit zehn oder zwanzig Abschnitten ist eine Themenliste, keine Leiter – falte sie zurück auf drei Tiefen mit je zwei Slice-Bildern.
  • containers ist eine Liste pro Diagramm von {label, members}. Die Box ist ein echtes, doppelt umrandetes Rechteck, das um die Mitglieder gewachsen ist, mit der Beschriftung in die Oberkante eingefügt. Mehrere Boxen pro Diagramm sind erlaubt.
  • Mitglieds-IDs müssen in den nodes dieses Diagramms vorhanden sein. Eine Mitglieds-ID, die keinen Knoten nennt, wird vom Parser stillschweigend fallen gelassen – die Box zeichnet dann um weniger Knoten herum, als du behauptet hast, und --check warnt nicht. Zähle die gezeichnete Box gegen die von dir declarierten Mitglieder.
  • Kontiguitätsregel. Ein Container ist ein Rechteck aus rect, das vom Mittelpunkt des Containers aus gemessen wird. Wenn der durch die Mitglieder definierte Bereich den Container überläuft, ist er kein gültiger Container – die Mitglieder passen nicht hinein. Ordne die Mitglieder innerhalb eines Containers so an, dass der Container sie mit mindestens 10–20 Pixeln Abstand auf jeder Seite umschließt. Wenn die Mitglieder nicht in die Begrenzungsbox des Containers passen, teile den Container auf oder ordne die Mitglieder neu an; niemals members außerhalb der Box des Containers zeichnen.

Schritt 6 – Das Protokoll

Ein Generierungsprotokoll muss existieren. Es sollte enthalten:

  • Die ID der Komponente, den Repo-Pfad und den Anker
  • Die Anzahl der von jedem Scout gefundenen Elemente und Beziehungen
  • Die Anzahl der gelösten und ungelösten Konflikte
  • Die Anzahl der gezeichneten, gefalteten, weggelassenen (nach Klasse) und nicht berücksichtigten Beziehungen
  • Falls zutreffend den Grund für die Aufteilung in Slice-Bilder (gemessen)
  • Alle offenen Fragen oder bekannten Lücken

Schritt 7 – Abdeckungskarte (Bonus)

Wenn die Zeit es erlaubt, füge am Ende eine kurze Zusammenfassung hinzu:

Beziehungen: 34 gefunden, 18 gezeichnet, 6 gefaltet (C2), 8 weggelassen (2 C1,
3 C3, 3 C4), 2 nicht berücksichtigt (Scouts nicht ausgeführt)
Konflikte: 3 (alle gelöst: Manifest schlägt Kommentar)
Offene Fragen: 1 – wohin streamt `audit_logger`? Keine Aufrufstelle gefunden

Diese Karte ist die letzte Zeile des Protokolls. Ein fehlender Wert ist eine Lücke, die aufgezeichnet werden muss.

Verwandte Skills