REST API
POST /v1/search
Hybrid retrieval over your team's memory graph.
Run a hybrid (BM25 + vector + graph traversal) search across the active team and project's memory. Returns ranked edges with attribution.
Scope required: read (implicit on every key)
Request
POST /v1/search
Authorization: Bearer ck_live_...
Content-Type: application/json{
"query": "What does Sridhar think about Rust?",
"group_id": "default",
"limit": 10
}| Field | Type | Required | Notes |
|---|---|---|---|
query | string, ≥ 1 char | yes | Natural-language question or keyword list. |
group_id | string | no ("default") | Sub-namespace within your project. |
limit | int, 1–100 | no (10) | Maximum number of edges to return. |
Response — 200 OK
{
"edges": [
{
"edge_uuid": "0cb65218-6cfa-4ec6-9802-1b24d6d0cb93",
"source_node": "Sridhar Cheeti",
"target_node": "Rust",
"fact": "Sridhar Cheeti prefers async Rust over Go for IO-heavy services",
"name": "prefers",
"intent_meta": {
"edge_kind": "preference",
"cognitive_pattern": "cost-vs-quality tradeoff",
"why_connected": "Tail latency matters more than ramp-up time for this team."
},
"_tier": "hot"
}
],
"_cache": {
"tier": "hit",
"hot_hits": 1,
"cold_hits": 0,
"group_id": "default"
}
}| Field | Meaning |
|---|---|
edges[].fact | Natural-language summary of the relationship. |
edges[].source_node / target_node | Entity names involved. |
edges[].name | Predicate label (e.g. "prefers", "reports_to"). |
edges[].intent_meta | Present iff the edge was written with extract_intent: true. Carries edge_kind, cognitive_pattern, why_connected, director_vision. |
edges[]._tier | "hot" if served from the Valkey active-subgraph cache, "cold" if from a fresh Neo4j query. |
_cache.tier | "hit" / "warmed" / "disabled". |
If your query is subjective ("what do I think about…"), the response also carries director_profile — a pre-computed personality / working-style summary distilled from prior writes.
Behaviour notes
- Search is scoped to the caller's
(team, project)automatically. You cannot escape the partition. - The
group_idfield narrows the search within your project; it doesn't relax the tenancy boundary. - Hybrid ranking: BM25 + vector cosine + graph centrality. The exact weights are tuned per result type; semantic queries lean on vectors, exact-name queries lean on BM25.
Errors
| HTTP | Slug | When |
|---|---|---|
| 400 | invalid_request | Missing query |
| 401 | unauthenticated | Bad Bearer |
| 429 | quota_exceeded | Monthly retrievals cap hit — kind: "retrievals" |
Examples
curl -X POST https://api.thebreeth.com/v1/search \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{"query": "What does Sridhar think about Rust?", "limit": 5}'r = httpx.post(
"https://api.thebreeth.com/v1/search",
headers={"Authorization": f"Bearer {KEY}"},
json={"query": "What does Sridhar think about Rust?", "limit": 5},
)
for e in r.json()["edges"]:
print(f"{e['source_node']} -[{e['fact']}]→ {e['target_node']}")const r = await fetch("https://api.thebreeth.com/v1/search", {
method: "POST",
headers: {
"Authorization": `Bearer ${KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ query: "What does Sridhar think about Rust?", limit: 5 }),
});
const { edges } = await r.json();
edges.forEach(e => console.log(e.fact));Related
POST /v1/episodes— writePOST /v1/retract— remove an edge from results- Knots — pre-synthesized narratives that appear inline on hub entities