{"slug":"index-and-search","title":"Index and search","path":"index-and-search.md","markdown":"# Index and search\n\nUploading files puts bytes in the knowledgebase tree. **Search uses the index**, which updates when you sync (and as background processing runs). After ingest or deletes, sync and wait until the knowledgebase is searchable before expecting new results.\n\n## Status\n\n```bash\nkobold-cli index status -kb kb_qc0rp0gz\n```\n\n```http\nGET /v1/knowledgebases/kb_qc0rp0gz/status\nAuthorization: Bearer \u003capi_key\u003e\n```\n\nExample fields you will see:\n\n| Field | Meaning |\n| ----- | ------- |\n| `id` | Knowledgebase id |\n| `status` | `pending`, `checking`, `digesting`, `halted`, `error`, or `complete` |\n| `statusInfo` | Human-readable progress or error detail |\n| `indexedHash` / `filesystemHash` | Digests used to detect drift between index and files |\n| `fileCount` / `vectorCount` | How much is indexed |\n| `files` | Per-path indexing progress (`path`, `indexed`, `vectorCount`, …) |\n\nA brand-new knowledgebase may report `pending` with empty `files` until the first sync/index run.\n\n## Sync\n\nAsk for an immediate sync check: compare the file tree to the last indexed state and enqueue work for changes.\n\n```bash\nkobold-cli index sync -kb kb_qc0rp0gz\n```\n\n```http\nPOST /v1/knowledgebases/kb_qc0rp0gz/sync\nAuthorization: Bearer \u003capi_key\u003e\n```\n\nNo request body. Acceptance is asynchronous. A successful accept looks like:\n\n```json\n{\n  \"accepted\": true,\n  \"status\": \"checking\",\n  \"statusInfo\": \"sync accepted\"\n}\n```\n\nHTTP status is `202`. The CLI prints the JSON body.\n\nYou can accept at most **one sync per knowledgebase per second**. Faster repeats → `429`. Poll `index status` until `status` is `complete` (or handle `error` / `halted`).\n\nRecommended flow after uploads:\n\n```bash\nkobold-cli files ingest -kb kb_qc0rp0gz -file ./doc.md\nkobold-cli index sync -kb kb_qc0rp0gz\n# poll until ready\nkobold-cli index status -kb kb_qc0rp0gz\nkobold-cli search query -kb kb_qc0rp0gz -query \"…\"\n```\n\n## Search\n\n```bash\nkobold-cli search query -kb kb_qc0rp0gz -query \"how does billing work\"\nkobold-cli search query -kb kb_qc0rp0gz -query \"how does billing work\" -mode sparse -limit 10\nkobold-cli search query -kb kb_qc0rp0gz -query \"how does billing work\" -mode full -byte-length 512\n```\n\n```http\nPOST /v1/knowledgebases/kb_qc0rp0gz/search\nAuthorization: Bearer \u003capi_key\u003e\nContent-Type: application/json\n\n{\n  \"query\": \"how does billing work\",\n  \"limit\": 10,\n  \"minScore\": 0.0,\n  \"mode\": \"sparse\",\n  \"byteLength\": 512\n}\n```\n\n| Field | Required | Notes |\n| ----- | -------- | ----- |\n| `query` | yes | Non-empty search string |\n| `limit` | no | Max hits; default `10`, max `100` |\n| `minScore` | no | Drop hits below this score; default `0` |\n| `mode` | no | `sparse` (default) or `full` |\n| `byteLength` | for `full` | Bytes of snippet per hit; `1`–`1024` |\n\n### Sparse mode (default)\n\nEach hit is a coordinate map—no file body:\n\n```json\n{\n  \"hits\": [\n    {\n      \"path\": \"docs/billing.md\",\n      \"byteStart\": 1024,\n      \"byteEnd\": 2048,\n      \"score\": 0.87,\n      \"kind\": \"chunk\"\n    }\n  ]\n}\n```\n\nUse these ranges with [files content](files.md) if you want exact bytes.\n\n### Full mode\n\nSame fields, plus a short hydrated snippet starting at `byteStart`:\n\n```json\n{\n  \"path\": \"docs/billing.md\",\n  \"byteStart\": 1024,\n  \"byteEnd\": 2048,\n  \"score\": 0.87,\n  \"kind\": \"chunk\",\n  \"content\": \"Billing is invoiced monthly…\",\n  \"contentBytes\": 512\n}\n```\n\nSnippet length is at most `byteLength`, and never more than **1024** bytes per hit. Search never returns a whole file; use `files content` for larger reads.\n\nIn the CLI, `-mode full` without `-byte-length` defaults to **512**.\n\nIf a snippet is not valid UTF-8, the API may return base64 in `content` with `\"encoding\": \"base64\"`.\n\n### When search works\n\n| Situation | Result |\n| --------- | ------ |\n| Index `complete` | Searchable |\n| `checking` / `digesting` with existing vectors | Searchable (may be slightly stale vs in-flight work) |\n| `pending` / `halted` / `error`, or `checking`/`digesting` with zero vectors | `409` — not searchable yet |\n| Searchable but nothing matches | `200` with `\"hits\": []` |\n\nInvalid query/mode/`byteLength` → `400`.\n\n## Related\n\n- [Files](files.md) — ingest and ranged content reads\n- [Errors](errors.md) — `409`, `429`, and others\n"}
