COMPASS-Doku

Schnellstart

Fünf Schritte: den MCP-Server anbinden, ein Regelwerk importieren, fragen was gilt und warum, Abweichungen ansehen, dann eine Regel ablösen und dieselbe Frage erneut stellen — die alte Regel ist jetzt sichtbar abgelöst, nicht verschwunden.

Jedes REST-Beispiel unten nutzt zwei Platzhalter: $COMPASS_URL für die Basis-URL des Kerns (Vertrags-Standard http://<host>:8080/api/v1) und $COMPASS_KEY für einen X-Compass-Key-Wert. Ersetze beide durch eure eigenen.

1. MCP-Server anbinden

Lokal (stdio — Claude Code, Cursor): einen Eintrag in .mcp.json (Claude Code) bzw. .cursor/mcp.json (Cursor) anlegen:

{
  "mcpServers": {
    "compass": {
      "command": "/pfad/zu/mcp/.venv/bin/python",
      "args": ["/pfad/zu/mcp/server.py"],
      "env": {
        "COMPASS_CORE_URL": "http://localhost:18080",
        "COMPASS_KEY_RO": "<Lese-Schlüssel>",
        "COMPASS_KEY_RW": "<Schreib-Schlüssel>"
      }
    }
  }
}

Gegen einen laufenden Container (streamable-http) stattdessen auf den MCP-Endpunkt zeigen und den Schlüssel als Kopfzeile senden — der Prozess selbst trägt in diesem Modus keinen eigenen Schlüssel:

{
  "mcpServers": {
    "compass": {
      "url": "http://localhost:18082/mcp",
      "transport": "http",
      "headers": { "X-Compass-Key": "<Schlüssel dieses Mandanten>" }
    }
  }
}

Das vollständige Bild, inklusive Codex' TOML-Konfiguration und was sich je Transport ändert, steht in Claude Code, Cursor und Codex anbinden.

2. Ein Regelwerk importieren

POST /import/claude-md ist ein deterministischer Scanner ohne Sprachmodell: eine Überschrift, gefolgt von einem Prosa-Satz, der mit einem Imperativ-Marker beginnt (Always, Never, Must, Immer, Kein, Muss, …), oder ein Stichpunkt/nummeriertes Element, dessen Text mit einem solchen beginnt — jedes davon wird eine vorgeschlagene Sache. Sonst nichts, und geschrieben wird noch nichts:

curl -sS -X POST "$COMPASS_URL/import/claude-md" \
  -H "X-Compass-Key: $COMPASS_KEY" \
  -F 'text=### R1 — Kein Geheimnis im Log

**Erzwingungsgrad:** verbindlich.

Kein Secret erscheint in Protokoll oder Bericht.
'
{
  "neu": [
    {"sache": "kein-secret-erscheint-in-protokoll-oder-bericht",
     "titel": "Kein Secret erscheint in Protokoll oder Bericht",
     "frage": "Was gilt für 'Kein Secret erscheint in Protokoll oder Bericht'?",
     "regel_text": "Kein Secret erscheint in Protokoll oder Bericht.", "quelle_zeile": 5}
  ],
  "unveraendert": [],
  "weicht_ab": [],
  "unklar": [],
  "art": "claude-md"
}

Nur der Satz, der mit dem Marker Kein beginnt, wurde zum Vorschlag — der Überschriftentext (R1 — Kein Geheimnis im Log) und die **Erzwingungsgrad:**-Zeile darüber für sich genommen nicht. Vorschlag prüfen, dann mit POST /import/claude-md/apply wirklich schreiben — das legt die Sache und eine regel-Aussage aus regel_text in einem Aufruf an:

curl -sS -X POST "$COMPASS_URL/import/claude-md/apply" \
  -H "X-Compass-Key: $COMPASS_KEY" -H "Content-Type: application/json" \
  -d '{"items": [{"sache": "kein-secret-erscheint-in-protokoll-oder-bericht",
       "titel": "Kein Secret erscheint in Protokoll oder Bericht",
       "frage": "Was gilt für '"'"'Kein Secret erscheint in Protokoll oder Bericht'"'"'?",
       "regel_text": "Kein Secret erscheint in Protokoll oder Bericht.", "quelle_zeile": 5}]}'
{"geschrieben": [{"sache": "kein-secret-erscheint-in-protokoll-oder-bericht", "aussage_id": 42}],
 "unveraendert": [], "abgeloest": [], "konflikt": [], "quelle_ref_widerspruch": []}

Sache und ihre regel-Aussage existieren jetzt beide — die aussage_id (hier 42) merken, Schritt 5 braucht sie zum Ablösen. Was der Scanner genau erkennt und seine ehrlich benannten Grenzen (deutlich schmaler als freie Dokumentation, und R-nummerierte Überschriften im Format ### R<n> bekommen keine eigene Sonderbehandlung) stehen in Ein Regelwerk importieren.

3. Fragen, was gilt — und warum

Schritt 2 hat für diese Sache bereits eine Regel geschrieben. Jetzt fragen, was gilt:

curl -sS "$COMPASS_URL/gilt/kein-secret-erscheint-in-protokoll-oder-bericht" -H "X-Compass-Key: $COMPASS_KEY"
{"id": 42, "text": "Kein Secret erscheint in Protokoll oder Bericht.",
 "gilt_seit": "2026-09-18T10:00:00Z", "ort": null, "pruefweg": null,
 "beleg": [], "quelle": "CLAUDE.md:5", "persona_slug": null}

Und warum:

curl -sS "$COMPASS_URL/warum/kein-secret-erscheint-in-protokoll-oder-bericht" -H "X-Compass-Key: $COMPASS_KEY"

GET /warum/{sache} liefert dieselbe Regel zusammen mit ihrem Entscheidungstext, der Historie und dem letzten Prüfweg-Ergebnis, falls eines angehängt ist. Die MCP-Werkzeuge gilt(slug) und warum(slug) rufen genau diese beiden Routen auf.

4. Abweichungen ansehen

Ein Prüfweg kann an eine Regel angehängt und regelmäßig ausgeführt werden; ein Lauf, der nicht zur Erwartung der Regel passt, wird zu einer Abweichung mit bestimmter Ursache — ein echter Verstoß, ein fehlendes Werkzeug, oder unklar. Was gerade mandantenweit abweicht:

curl -sS "$COMPASS_URL/abweichungen" -H "X-Compass-Key: $COMPASS_KEY"

Hier erscheint nichts, bevor ein Prüfweg tatsächlich gelaufen ist und der Regel widersprochen hat — siehe Prüfweg anhängen, um einen einzurichten. Das MCP-Werkzeug ist abweichungen(seit?).

5. Regel ablösen, erneut fragen

Eine neue Aussage schreiben, ersetzt zeigt auf die id der alten Aussage (42 aus Schritt 2) — die alte wird im selben Aufruf automatisch auf abgeloest gesetzt:

curl -sS -X POST "$COMPASS_URL/aussagen" \
  -H "X-Compass-Key: $COMPASS_KEY" -H "Content-Type: application/json" \
  -d '{"sache": "kein-secret-erscheint-in-protokoll-oder-bericht", "art": "regel",
       "text": "Secret-Längen dürfen genannt werden, Werte nie.",
       "herkunft": "entschieden", "angelegt_von": "quickstart", "ersetzt": 42}'

Dieselbe Frage erneut stellen:

curl -sS "$COMPASS_URL/gilt/kein-secret-erscheint-in-protokoll-oder-bericht" -H "X-Compass-Key: $COMPASS_KEY"

Der Text hat sich geändert. Die Sache selbst holen, um beide Aussagen auf einmal zu sehen — die alte ist nicht weg, sie steht unter abgeloest:

curl -sS "$COMPASS_URL/sachen/kein-secret-erscheint-in-protokoll-oder-bericht" -H "X-Compass-Key: $COMPASS_KEY"
{
  "slug": "kein-secret-erscheint-in-protokoll-oder-bericht", "...": "...",
  "aussagen": {
    "gilt": [{"id": 43, "text": "Secret-Längen dürfen genannt werden, Werte nie."}],
    "abgeloest": [{"id": 42, "text": "Kein Secret erscheint in Protokoll oder Bericht.", "gilt_bis": "2026-09-18T10:05:00Z"}],
    "offen": [], "hypothesen": []
  }
}

Nichts wurde gelöscht, und eine zweite regel-Aussage für diese Sache ohne ersetzt zu schreiben wäre mit 409 gescheitert — die Datenbank erlaubt genau eine geltende Regel je Sache und Subjekt. Die volle Mechanik, inklusive dem Fall, dass eine Regel ganz ohne Nachfolger enden muss, steht in Regel setzen und ablösen.