Search
One ranked answer fused across every source for a natural-language query.
Search runs a natural-language query across one or more sources and returns a single ranked list of hits. It blends semantic and keyword retrieval behind the scenes — the caller sends a question, not a query syntax.
Request
POST /projects/:project_id/knowledge/searchHeaders:
| Header | Required | Description |
|---|---|---|
X-API-Key | One of | Service-level key for server-to-server calls |
Authorization | One of | Bearer <jwt> for user-scoped calls |
Content-Type | Yes | application/json |
Body:
{
"query": "where do we validate session tokens?",
"sources": ["code", "work_items"],
"top_k": 10
}| Field | Type | Required | Description |
|---|---|---|---|
query | string | Yes | Natural-language question |
sources | string[] | No | Filter to specific sources. Omit to search all |
top_k | number | No | Maximum hits to return. Default: 10. Max: 50 |
Response
{
"query": "where do we validate session tokens?",
"hits": [
{
"ref": "code:github:acme/api:main:src/auth/verify.ts:verifySession",
"source": "code",
"title": "verifySession",
"snippet": "Validates a JWT session token against the signing key and returns the decoded principal. Called by every authenticated endpoint.",
"score": 0.94,
"entity_type": "function",
"metadata": {
"file_path": "src/auth/verify.ts",
"repository": "acme/api",
"language": "typescript"
}
},
{
"ref": "work_items:jira:PROJ-412",
"source": "work_items",
"title": "PROJ-412: Rotate session tokens on privilege change",
"snippet": "A token stays valid after a role downgrade. Invalidate and reissue the session when a member's role changes.",
"score": 0.82,
"entity_type": "issue",
"metadata": {
"status": "done",
"assignee": "maria.garcia"
}
}
],
"sources_searched": ["code", "work_items"],
"total_hits": 2
}Hit fields
Every hit, regardless of source, carries these normalized fields:
| Field | Type | Description |
|---|---|---|
ref | string | Opaque reference. Pass to fetch for the full object |
source | string | Which source produced this hit |
title | string | Human-readable title |
snippet | string | Relevant excerpt or summary |
score | number | Relevance score, 0–1, comparable across sources |
entity_type | string | The kind of entity: function, module, issue, table, commit, etc. |
metadata | object | Source-specific fields (file path, repository, status, etc.) |
Ranking and fusion
Hits from different sources use different internal scoring methods. Echo normalizes these into a single 0–1 scale so hits from code, work items, and databases are comparable. The fusion is designed so a highly relevant code hit and a highly relevant ticket can both appear near the top, rather than one source always dominating.
Empty result
When no hits match, the response is a valid object with an empty list — not an error:
{
"query": "quantum flux capacitor",
"hits": [],
"sources_searched": ["code", "graph", "docs", "work_items", "commits", "database"],
"total_hits": 0
}Next: Fetch.

