ariadne
Ariadne
Ariadnes Faden — ein Ausweg aus dem Microservice-Labyrinth.
Dienstübergreifender API-Abhängigkeitsgraph und semantische Codenavigation für Microservice-Architekturen. MCP-stdio-Server für KI-Coding-Assistenten (Claude Code, Cursor, Windsurf), mit einem CLI-Zwilling für Skripte. Statische Read-only-Analyse auf Basis von SQLite + TF-IDF + Embeddings.
Für wen ist das gedacht?
KI-Coding-Assistenten (Claude Code, Cursor, Windsurf) — eine strukturierte, dienstübergreifende Abhängigkeitsansicht, die in das Kontextfenster passt, anstelle von roher
grep-Ausgabe.Backend-Entwickler, die ein Feature über 4+ Dienste hinweg verfolgen — GraphQL-, REST-, Kafka- und Frontend-Aufrufe in einer einzigen Abfrage aufgelöst.
Plattform- und Review-Teams, die dienstübergreifende Auswirkungsanalysen durchführen — zeigen Sie die gesamte Aufrufkette auf, die eine Änderung in einem Dienst betrifft, bevor sie veröffentlicht wird.
Neue Entwickler (Onboarding), die eine unbekannte Microservice-Topologie ausgehend von einem einzigen Geschäftsbegriff kartieren.
Related MCP server: TempoGraph
Warum?
Ariadne indexiert nur die Vertragsebene — GraphQL-Mutationen, REST-Endpunkte, Kafka-Topics, Frontend-Abfragen — sonst nichts. Diese Fokussierung sorgt dafür, dass die Ergebnisse in ein KI-Kontextfenster passen.
Ansatz | Problem, das Ariadne löst |
| Ertrinkt in DTOs, Tests, Konfigurationen |
IDE "Find Usages" | Stoppt an Dienstgrenzen |
Service-Mesh-Dashboards | Benötigt Produktionsdatenverkehr; kein Feature-Mapping |
Vollständige AST / Call-Graph-Tools | Langsam im Aufbau; zu viele Details |
Beispiel
Sie fragen Claude: "Wo lebt createOrder im gesamten Stack?" Claude ruft mitten im Gespräch query_chains auf und erhält:
Top Cluster #1 [confidence: 0.91]
Services: gateway, orders-svc, billing-svc, web
- [web] Frontend Mutation: createOrder
- [gateway] GraphQL Mutation: createOrder
- [orders-svc] HTTP POST /orders: createOrder
- [orders-svc] Kafka Topic: order-created
- [billing-svc] Kafka Listener: order-created → chargeCustomerClaude fasst dann zusammen: "createOrder ist eine GraphQL-Mutation im gateway, die via POST /orders an orders-svc weitergeleitet wird, welcher ein order-created Kafka-Event veröffentlicht, das von billing-svc konsumiert wird, um den Kunden zu belasten."
~500 Token Round-Trip. Ein äquivalenter grep -r createOrder über vier Repos hinweg würde 40+ Treffer in DTOs, Tests und Konfigurationen bei ~2000 Token liefern, wobei die Vertragsebene verborgen bliebe.
Der goldene Pfad
Der beabsichtigte Workflow, wenn ein KI-Assistent Ariadne über den MCP-Server steuert.
1. query_chains(hint="createOrder")
→ ranked clusters across services. Start here for cross-service context.
2. expand_node(name="order-created")
→ one-hop neighbours of a known node. Within 10 min of a matching
query_chains, this auto-logs positive feedback — the expand IS the signal.
3. Read the files the returned clusters / neighbours point at.
4. log_feedback(hint, accepted=False, ...)
→ manual thumbs-down only. Positive feedback is captured in step 2.Bei einer stale_warning rufen Sie rescan() auf und versuchen es erneut. Siehe FAQ.
Schnellstart
Drei Befehle, dann Claude Code neu starten.
pip install mcp onnxruntime tokenizers huggingface_hub
cp ariadne.config.example.json ariadne.config.json # edit repos inside
python3 main.py install ariadne.config.json ~/your-workspaceinstall ist idempotent — führen Sie es nach dem Abrufen von neuem Code erneut aus oder lassen Sie den Assistenten rescan aufrufen, wenn er eine stale_warning sieht. Siehe --help für Flags (--no-scan, --force, --snippet, --marker).
Tools
Was der Assistent sieht, sobald install abgeschlossen und Claude Code neu gestartet wurde:
Tool | Argumente | Zweck |
|
| Geschäftsbegriff → dienstübergreifende Cluster |
|
| Nachbarn eines bekannten Knotens (ein Hop) |
| (keine) | Aktualisiert den Index, wenn eine Antwort eine |
| (keine) | Einrichtungsanleitung + Laufzeit-Konfigurationsdiagnose (fehlende DB, leerer Index, veralteter Scan) |
|
| Manuelles "Daumen runter" (positives Feedback ist implizit — siehe Feedback-Boost unter Architektur) |
Konfiguration
Konfigurationsformat
{
"repos": [
{
"name": "gateway",
"path": "../gateway",
"scanners": ["graphql"]
},
{
"name": "orders-svc",
"path": "../orders-svc",
"scanners": [
"http",
"kafka",
{
"type": "backend_clients",
"client_target_map": { "billing": "billing-svc", "user": "user-svc" }
}
]
},
{
"name": "web",
"path": "../web",
"scanners": [
"frontend_graphql",
{
"type": "frontend_rest",
"base_class_service": { "OrdersApiService": "orders-svc" }
}
]
}
]
}Die Pfade werden relativ zur Konfigurationsdatei aufgelöst. Jedes Repo listet einen oder mehrere Scanner auf — entweder nach Namen (String) oder als Objekt mit zusätzlichen Optionen.
Verfügbare Scanner
Scanner | Sucht nach |
|
|
| Spring |
| Spring |
| Spring |
| TypeScript |
|
|
|
|
Benutzerdefinierte Scanner
Jede Sprache oder jedes Framework, das oben nicht abgedeckt ist, kann hinzugefügt werden, ohne den Quellcode von Ariadne zu ändern. Implementieren Sie scanner.BaseScanner, legen Sie das Modul an einen Ort, den Python importieren kann, und referenzieren Sie die Klasse über den punktierten Pfad in ariadne.config.json:
{
"name": "my-go-service",
"path": "../my-go-service",
"scanners": [
{
"type": "my_scanners.go_scanner:GoRouteScanner",
"route_file": "cmd/server/routes.go"
}
]
}"type" ist "module.path:ClassName". Jeder andere Schlüssel wird an __init__ übergeben.
# my_scanners/go_scanner.py
from scanner import BaseScanner
class GoRouteScanner(BaseScanner):
def __init__(self, route_file: str = "routes.go"):
self.route_file = route_file
def scan(self, repo_path: str, service: str) -> list[dict]:
# parse repo_path/self.route_file, return node dicts
return [{"id": f"{service}::http::GET::/ping", "type": "http_endpoint",
"raw_name": "ping", "service": service,
"source_file": self.route_file,
"method": "GET", "path": "/ping", "fields": []}]FAQ
Benötigt Ariadne einen laufenden Cluster, Server oder Netzwerk?
Nein. Reine statische Analyse. Quelle → lokales SQLite (ariadne.db, embeddings.db, feedback.db). Keine Netzwerkaufrufe, keine Uploads.
Woher weiß es, wann ein erneuter Scan erforderlich ist?
Wenn der älteste Scan älter als 7 Tage ist, enthalten MCP-Antworten ein stale_warning-Feld (das CLI gibt dieselbe Warnung an stderr aus). Rufen Sie aus einem KI-Gespräch rescan() auf; von der Shell aus python3 main.py scan --config <path>.
Die Ergebnisse wirken anfangs generisch — werden sie besser?
Ja. expand_node-Folgeaufrufe protokollieren implizit positives Feedback; der Boost-Rerank-Schritt (confidence + 0.15 * boost) fördert Cluster, die für ähnliche Hinweise nützlich waren. Die Ergebnisse am ersten Tag sind rein lexikalisches Ranking; nach einigen Wochen spiegeln sie die Navigationsmuster Ihres Teams wider. Zählerbasiert, kein gelerntes Modell.
Kann ich es ohne KI-Assistenten verwenden — nur als CLI?
Ja. python3 main.py scan / query / expand / stats — null Abhängigkeiten über Python 3.10 hinaus. MCP ist dennoch der empfohlene Weg.
Architektur
ariadne/
├── scanner/ # per-framework extractors → node dicts
├── normalizer/ # camelCase/snake/kebab → tokens
├── scoring/ # IDF-Jaccard engine + bge-small embedder
├── store/ # SQLite: ariadne.db / embeddings.db / feedback.db
├── query/ # query / expand entry points
├── mcp_server.py # MCP stdio server
├── main.py # CLI
└── tests/ # pytest suiteScoring
Die Mathematik dahinter ist Information Retrieval, nicht Graphentheorie. Knotennamen werden tokenisiert (createOrder → ["create", "order"]) und mit IDF-gewichteter Jaccard-Ähnlichkeit verglichen:
idf_jaccard(A, B) = Σ idf(t) (t ∈ A ∩ B) / Σ idf(t) (t ∈ A ∪ B)
idf(t) = log(N / df(t))Seltene Token dominieren; hochfrequente Domänenwörter (task, id, service) dämpfen sich selbst, keine Stoppwortliste erforderlich.
base = idf_jaccard(name) * 0.55 + idf_jaccard(fields) * 0.45
score = min(base * role_mult * service_mult, 1.0)
role_mult = 1.3 for complementary pairs
(GraphQL Mutation ↔ Kafka topic ↔ HTTP POST,
GraphQL Query ↔ Cube Query ↔ HTTP GET)
service_mult = 1.25 cross-service / 0.8 same-serviceClustering
Zweistufig, O(Anker × Nachbarn), unabhängig von der Anzahl der Repos.
Tokenisiere den Hinweis, bewerte ihn gegen alle Knoten, behalte die Top 30 Anker mit
score ≥ 0.15.Ziehe für jeden Anker seine Kanten aus der DB (einzelne
IN-Abfrage) und behalte die Top 12 Nachbarn mitedge_score ≥ 0.25.Führe Anker-Nachbarschaften zusammen, die sich zu ≥ 25% überschneiden.
Nimm pro Cluster die Top 2 Knoten pro
(service, type), begrenzt auf 12.Konfidenz = mittlerer Kantenscore · 0.6 + Typ-Diversität · 0.2 + Dienst-Diversität · 0.2.
Embeddings
TF-IDF ist der primäre Abrufkanal. bge-small-en-v1.5 (ONNX int8 quantisiert) wird für zwei enge Aufgaben verwendet:
Abruf-Fallback: Wenn die Token-Überschneidung schwach ist, finde Synonyme (z. B.
assignHomework↔assignStudentsToTask) und füge sie dem Anker-Set hinzu.Reranking: Erstelle zuerst
top_n × 2Cluster, sortiere dann neu nach0.6 · confidence + 0.4 · max_cos(hint, cluster_nodes)und kürze auftop_n.
Das ONNX-Modell ist ~34 MB groß (int8 quantisiert) und läuft auf der CPU via onnxruntime. Kaltstart ~0.3s. Vektoren werden in embeddings.db zwischengespeichert; nur der Abfragehinweis wird zur Abfragezeit eingebettet.
Feedback-Boost
Ein abschließender Rerank-Schritt, der das Ranking an das Vokabular Ihres Teams anpasst — kein Modelltraining, keine Uploads. feedback.db ist lokal pro Entwickler.
Jeder query_chains-Aufruf speichert zurückgegebene Cluster für 10 Minuten zwischen. Ein nachfolgender expand_node(name), der einen Teilstring-Treffer eines Knotens in einem ausstehenden Cluster findet, schreibt automatisch eine accepted=True-Zeile — das Expandieren IST das Signal. log_feedback(hint, accepted, ...) ist der manuelle Ausweg für "Daumen runter".
Beim nächsten query() für denselben Hinweis:
final_score = confidence + 0.15 * sum(prior_accepted_count per node in cluster)Gewichtung (0.15) und Zerfallsfenster (90 Tage) sind bewusst konservativ gewählt — lexikalische Konfidenz dominiert weiterhin. Deaktivieren mit export ARIADNE_FEEDBACK_BOOST=0.
Tests
python3 tests/test_semantic_hint.py
python3 tests/test_feedback_boost.py
python3 tests/test_implicit_feedback.py
python3 tests/test_onnx_embedder.pyA Pre-Commit-Hook unter hooks/pre-commit führt test_semantic_hint.py aus — einmal pro Klon aktivieren mit:
ln -sf ../../hooks/pre-commit .git/hooks/pre-commitRoadmap
Mehr Kafka-Quellen über
application.yaml+@KafkaListener+KafkaTemplate.sendhinausTF-IDF-Gewichtungsoptimierung für sehr hochfrequente Domänen-Token
Stärkeres Feedback-Signal: Zerfalls-Tuning, dienstspezifische Gewichtung, hinweisübergreifende Generalisierung (der aktuelle Boost ist zählerbasiert innerhalb desselben Hinweises)
Watch-Modus: Hook in Git Post-Commit / Datei-Events, um
rescanautomatisch auszulösen, anstatt auf einestale_warningzu wartenexpand_nodeProdukt-Politur: klarere Auslösebedingungen, kleinere Eingabeoberfläche, Ausgabe, die auf den nächsten Schritt hinweistParameterübergabe über alle Tools hinweg: aufgabenorientierte Namen statt Implementierungsnamen; Vereinheitlichung von Verb-Präfixen für Namenskonsistenz
Nicht-Ziele
LLM als primärer Richter (langsam, teuer, nicht reproduzierbar)
Visualisierung / Graph-Datenbank-Backend
Vollständige AST-Call-Graph-Extraktion
Lizenz
MIT — siehe LICENSE.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/whyy9527/ariadne'
If you have feedback or need assistance with the MCP directory API, please join our Discord server