COMPASS docs

Search

There are three separate search surfaces — they cover different tables and don't share a single index.

Statements and events — GET /suche

curl -sS "$COMPASS_URL/suche?q=timeout" -H "X-Compass-Key: $COMPASS_KEY_RO"

Full-text search (Postgres tsvector) over Aussagen and Ereignisse together. The answer always names the total, not just the page:

{
  "treffer": [{"typ": "aussage", "id": 4711, "text": "…", "sache": "…",
               "status": "gilt", "gilt_seit": "…", "gilt_bis": null, "rang": 0.71}],
  "gesamt": 290,
  "abgeschnitten": true,
  "weiter": 100
}

The MCP tool is suche(q, subjekt_id?, persona_slug?, alle=False, limit?, offset?); it adds a hinweis in words ("100 von 290 Treffern. Weiter mit offset=100.").

gesamt counts after the visibility filter, not before — the page you hold and the number next to it describe the same set. abgeschnitten says whether anything stands behind this page, and weiter names the offset for the next one, or is null when there is nothing left. To get everything, page until weiter is null — you never have to do the arithmetic to find out whether you are done.

Changed 2026-10-05 (breaking). The answer used to be a list and was truncated silently at 100 hits: measured 290 hits present, 100 delivered, no indication — the list looked complete. A half measurement must not look like a whole one.

persona_slug filters the statement hits to that persona's visibility (sichtfeld) by joining through each statement's Sache. Event hits are never filtered this way — events don't carry a bereich field, so there's nothing to filter on. This is a documented limit, not an oversight: a persona-scoped search here can under-represent events, and the contract says so rather than implying full coverage. alle=true lifts the statement-side filter and is logged as an event when it actually changes what's visible.

limit sets the page size (default 100). Combined with persona=, it's also capped at that persona's model-class ceiling (small 20 / medium 50 / large 200) — an explicit value above the ceiling is rejected with 422 rather than silently truncated. The ceiling limits the page, not the set: even a small persona can reach everything via offset.

A persona's own memory — GET /personas/{slug}/gedaechtnis

curl -sS "$COMPASS_URL/personas/atlas/gedaechtnis?q=deploy" -H "X-Compass-Key: $COMPASS_KEY_RO"

Full-text search (German tsvector) over one persona's memory entries — newest first, only currently-held entries (gilt_bis null) unless alle=true. Returns the persona's own entries plus visible company memory (an entry with persona_slug=null is visible only if it carries at least one tag inside the reading persona's sichtfeld, or the persona's sichtfeld is empty). The MCP tool is memory_search(persona_slug, q, art?, limit=20, lesende_persona?, alle=False) — note the parameter is lesende_persona here, not persona_slug twice; persona_slug already answers "whose memory," so the visibility filter needs its own name.

Lessons — GET /lehren?q=

curl -sS "$COMPASS_URL/lehren?q=timeout" -H "X-Compass-Key: $COMPASS_KEY_RO"

Full-text search over lesson titel+was+lehre. Visibility here follows a slightly different rule than memory: a lesson with no bereich at all is considered general and stays visible to everyone — a lesson is written as a general statement by form, a memory note is not. The MCP tool is lehren_suche(q?, art?, status?, bereich?, lesende_persona?, limit?).

What isn't searched together

There is no single call that searches statements, memory, and lessons at once — pick the surface that matches what you're looking for. If you're not sure which table something lives in, GET /suche is the broadest single call (statements + events across the whole tenant), followed by checking the relevant persona's memory or the lesson log directly.