Use the SDKs
For an agent that can't run an MCP server (or just wants a direct dependency instead of a subprocess), two thin client libraries call the Core's REST API directly — no MCP in between. They cover the same seven verbs the MCP exposes for the common path: check what holds, ask why, create a Sache, set/supersede a rule, record a lesson, search, and export the rule book.
Both live in sdk/ in this repo, are not published to a registry yet
(open license, but no PyPI/npm release so far — install straight from the
path or a Git checkout), and share the same auth model as everything else
in COMPASS: header X-Compass-Key, one key per call.
Python — compass_client
from compass_client import Compass
c = Compass("http://localhost:18080", "<your-key>")
regel = c.gilt("deploy-freigabe")
Install locally with pip install -e sdk/python. Only runtime dependency:
httpx. An async twin, AsyncCompass, mirrors every method as async def.
TypeScript — @athron/compass
import { Compass } from "@athron/compass";
const c = new Compass("http://localhost:18080", "<your-key>");
const regel = await c.gilt("deploy-freigabe");
Built with tsc (npm run build in sdk/typescript) into dist/ (ESM,
with .d.ts). No runtime dependencies — uses the global fetch.
The package is not published. npm install @athron/compass fails (the
registry answers 404, measured 02.10.2026) — @athron/compass is the name
inside the repo, not a source to install from. Until it is published,
pull the SDK in locally, the way its Python twin already does:
npm install ./sdk/typescript, or a "@athron/compass":
"file:../sdk/typescript" entry in your own package.json. The import
above stays unchanged.
Method-to-route map
Both SDKs expose the same seven calls, in each language's own naming
convention (snake_case in Python, camelCase in TypeScript):
| Python | TypeScript | Route |
|---|---|---|
c.gilt(sache, ...) |
c.gilt(sache, ...) |
GET /gilt/{sache} |
c.warum(sache, ...) |
c.warum(sache, ...) |
GET /warum/{sache} |
c.sache_anlegen(slug, titel, frage, bereich=None, ...) |
c.sacheAnlegen(slug, titel, frage, bereich?, ...) |
POST /sachen |
c.regel_setzen(sache, text, ersetzt=None, ...) |
c.regelSetzen(sache, text, { ersetzt?, ... }) |
POST /aussagen (art=regel) |
c.lehre_festhalten(art, titel, was, lehre, ...) |
c.lehreFesthalten(art, titel, was, lehre, ...) |
POST /lehren |
c.suche(q, ...) |
c.suche(q, ...) |
GET /suche — returns {treffer, gesamt, abgeschnitten, weiter}, not an array (since 2026-10-05) |
c.export(art="claude-md-section0", ...) |
c.export(art?, ...) |
GET /export/claude-md-section0 (also agents-md, cursor-rules) |
Every non-2xx response raises a structured error — CompassFehler in
Python, CompassError in TypeScript — carrying status, detail (the
plain-language sentence, "Fehlerform"), feld (the field a 409/422 names,
if any), and everything else the response body carried (e.g. the
currently-held rule on a 409 from regel_setzen).
When to use the SDK instead of the MCP
The MCP (mcp/server.py, see Connect Claude Code, Cursor, and
Codex) is the right fit for an agent that already
speaks MCP — Claude Code, Cursor, Codex. The SDKs are for everything
else: a CI job, a backend service, a script that just needs gilt()
before it acts, without a subprocess or an MCP client library in the
loop. Both talk to the same Core, over the same REST contract — neither
one is a second source of truth.
Tests
Each SDK ships its own test suite next to the source
(sdk/python/tests, sdk/typescript/tests) — request shape (path,
method, header, body) and error mapping against a mocked Core, plus a
static check that every route the SDK calls actually exists in the
running Core (the same cross-check this documentation site runs on its
own REST mentions).