Quickstart
Start in five minutes
- Create a free account at
compass.athron.io/registrierenand choose Start with a sample company. You get Nordlicht, a small shop with three agents, rules and open decisions. All of its data is invented. - Connect Claude. Sign-in runs in the browser via OAuth.
- Claude Code:
claude mcp add --transport http compass https://compass.athron.io/mcp, then run/mcpin Claude Code and sign in. - Claude Desktop and claude.ai: Settings → Connectors → Add custom connector → URLhttps://compass.athron.io/mcp→ sign in. - Claude Code plugin:/plugin marketplace add Athron-new/compass-agents, then/plugin install compass@compass. The plugin adds a skill and loads a persona's brief at session start; its setup is described in the README in theplugin/folder ofgithub.com/Athron-new/compass-agents. - Ask: "What holds at Nordlicht for discounts above 10 %?" The answer names the rule, since when it holds, and what held before.
The developer path: five steps
Five steps against your own installation: connect the MCP server, import a rule set, ask what holds and why, look at deviations, then supersede a rule and ask the same question again — the old rule is now visibly superseded, not gone.
Every REST example below uses two placeholders: $COMPASS_URL for the Core's
base URL (the contract's default is http://<host>:8080/api/v1) and
$COMPASS_KEY for an X-Compass-Key value. Substitute your own.
Rules are set by a human. A key alone cannot create a rule (the Core answers 403). Sign in once and keep the
session token as $COMPASS_SESSION; the calls below that write a rule send it as Authorization: Bearer instead of
the key:
curl -sS -X POST "$COMPASS_URL/auth/anmelden" -H "Content-Type: application/json" \
-d '{"email": "you@example.com", "passwort": "<your password>"}'
# → {"sitzungs_token": "...", ...} that value is $COMPASS_SESSION
An agent proposes a rule instead (lehre_regel_vorschlagen, or a question with regel_vorschlag); a human confirms
it with a click. Reading, Sachen, decisions and facts stay with the key.
1. Connect the MCP server
Locally (stdio — Claude Code, Cursor), add an entry to .mcp.json (Claude
Code) or .cursor/mcp.json (Cursor):
{
"mcpServers": {
"compass": {
"command": "/path/to/mcp/.venv/bin/python",
"args": ["/path/to/mcp/server.py"],
"env": {
"COMPASS_CORE_URL": "http://localhost:18080",
"COMPASS_KEY_RO": "<read-only key>",
"COMPASS_KEY_RW": "<read-write key>"
}
}
}
}
Against a running container (streamable-http), point at the MCP endpoint
instead and send the key as a header — the process itself carries no key in
this mode:
{
"mcpServers": {
"compass": {
"url": "http://localhost:18082/mcp",
"transport": "http",
"headers": { "X-Compass-Key": "<key for this tenant>" }
}
}
}
See Connect Claude Code, Cursor, and Codex for the full picture, including Codex's TOML config and what changes under each transport.
2. Import a rule set
POST /import/claude-md is a deterministic, model-free scanner: a heading followed by a prose sentence that
starts with an imperative marker (Always, Never, Must, Immer, Kein,
Muss, …), or a bullet/numbered item whose text starts with one — each
becomes one proposed Sache. Nothing else does, and nothing is written yet:
curl -sS -X POST "$COMPASS_URL/import/claude-md" \
-H "X-Compass-Key: $COMPASS_KEY" \
-F 'text=### R1 — No secret in the log
**Enforcement:** binding.
Never log or report a secret.
'
{
"neu": [
{"sache": "never-log-or-report-a-secret",
"titel": "Never log or report a secret",
"frage": "Was gilt für 'Never log or report a secret'?",
"regel_text": "Never log or report a secret.", "quelle_zeile": 5}
],
"unveraendert": [],
"weicht_ab": [],
"unklar": [],
"art": "claude-md"
}
Note that only the sentence starting with the marker Never became a
proposal — the heading text (R1 — No secret in the log) and the
**Enforcement:** line above it did not, by themselves. Review the
proposal, then write it for real with POST /import/claude-md/apply — this
writes the Sache and a regel Aussage from regel_text in one call:
curl -sS -X POST "$COMPASS_URL/import/claude-md/apply" \
-H "Authorization: Bearer $COMPASS_SESSION" -H "Content-Type: application/json" \
-d '{"items": [{"sache": "never-log-or-report-a-secret",
"titel": "Never log or report a secret",
"frage": "Was gilt für '"'"'Never log or report a secret'"'"'?",
"regel_text": "Never log or report a secret.", "quelle_zeile": 5}]}'
{"geschrieben": [{"sache": "never-log-or-report-a-secret", "aussage_id": 42}],
"unveraendert": [], "abgeloest": [], "konflikt": [], "quelle_ref_widerspruch": []}
Both the Sache and its regel Aussage exist now — keep the aussage_id
(42 here), step 5 needs it to supersede this rule. See
Import a rule set for the exact two patterns
the scanner recognizes and its honestly-named limits — it is much narrower
than full free-form documentation, and gives rule-numbered headings in the
### R<n> format no special treatment of their own.
3. Ask what holds — and why
Step 2 already wrote a rule for this Sache. Ask what holds:
curl -sS "$COMPASS_URL/gilt/never-log-or-report-a-secret" -H "X-Compass-Key: $COMPASS_KEY"
{"id": 42, "text": "Never log or report a secret.",
"gilt_seit": "2026-09-18T10:00:00Z", "ort": null, "pruefweg": null,
"beleg": [], "quelle": "CLAUDE.md:5", "persona_slug": null}
And why it holds:
curl -sS "$COMPASS_URL/warum/never-log-or-report-a-secret" -H "X-Compass-Key: $COMPASS_KEY"
GET /warum/{sache} returns the same rule together with its decision text,
history, and the last check result, if one is attached. The MCP tools
gilt(slug) and warum(slug) call exactly these two routes.
4. Look at deviations
A check (Prüfweg) can be attached to a rule and run periodically; a run
that doesn't match what the rule expects becomes an Abweichung
(deviation) with a determined cause — a real violation, a missing tool, or
unclear. List what currently deviates across the tenant:
curl -sS "$COMPASS_URL/abweichungen" -H "X-Compass-Key: $COMPASS_KEY"
Nothing shows up until a check has actually run and disagreed with its rule
— see Attach a check to wire one up. The MCP
tool is abweichungen(seit?).
5. Supersede the rule, ask again
Write a new statement with ersetzt pointing at the old Aussage's id
(42 from step 2) — the old one is automatically marked abgeloest
in the same request:
curl -sS -X POST "$COMPASS_URL/aussagen" \
-H "Authorization: Bearer $COMPASS_SESSION" -H "Content-Type: application/json" \
-d '{"sache": "never-log-or-report-a-secret", "art": "regel",
"text": "Secret lengths may be named, values never.",
"herkunft": "entschieden", "angelegt_von": "quickstart", "ersetzt": 42}'
Ask the same question again:
curl -sS "$COMPASS_URL/gilt/never-log-or-report-a-secret" -H "X-Compass-Key: $COMPASS_KEY"
The text has changed. Fetch the Sache itself to see both statements at
once — the old one is not gone, it is filed under abgeloest:
curl -sS "$COMPASS_URL/sachen/never-log-or-report-a-secret" -H "X-Compass-Key: $COMPASS_KEY"
{
"slug": "never-log-or-report-a-secret", "...": "...",
"aussagen": {
"gilt": [{"id": 43, "text": "Secret lengths may be named, values never."}],
"abgeloest": [{"id": 42, "text": "Never log or report a secret.", "gilt_bis": "2026-09-18T10:05:00Z"}],
"offen": [], "hypothesen": []
}
}
Nothing was deleted, and trying to write a second regel for this Sache
without ersetzt would have failed with 409 — the database allows exactly
one current rule per Sache and subject. See
Set and supersede a rule for the
full mechanics, including what happens when a rule needs to end with no
successor at all.