> ## Documentation Index
> Fetch the complete documentation index at: https://docs.evermind.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Knowledge Bases

> Ingest documents into a searchable topic library and query it alongside memory

A knowledge base is a searchable document library with its own category taxonomy. Where memory captures what happened in a conversation, a knowledge base holds the material an agent needs to *consult* — a handbook, a spec, a policy — broken into topics an LLM extracted from it.

Both live behind the same API key and the same base URL.

## How a document becomes searchable

<Steps>
  <Step title="Create a knowledge base">
    ```python theme={null}
    from everos_cloud import EverOS

    client = EverOS(api_key="your_api_key")

    kb = client.kb_create("Employee Handbook", description="HR policies")
    kb_id = kb.id
    ```
  </Step>

  <Step title="Ingest a document">
    `content` takes inline text, or a file you uploaded first (see [Multimodal](/cloud/multimodal-support)).

    ```python theme={null}
    ack = client.doc_ingest(
        kb_id,
        "Leave policy",
        "Employees accrue 20 days of paid leave per year. Unused days roll over once.",
    )
    # ack.status == "queued", ack.task_id == "0217..."
    ```

    <Note>
      Ingest is always asynchronous. The call answers `202` with a `task_id`, and the
      document id is minted downstream — so the ack does **not** carry one.
    </Note>
  </Step>

  <Step title="Wait for it to be processed">
    ```python theme={null}
    task = client.task_wait(ack.task_id, timeout=300)
    print(task.status)   # "success"
    ```

    `task_wait` polls until the task reaches a terminal state, backs off between polls,
    rides out a transient rate limit, and raises if the task fails or outlives the
    timeout. Pass `raise_on_failure=False` to inspect a failure instead of raising.
  </Step>

  <Step title="Find the document">
    The ingest ack has no document id, so resolve it by title once the task finishes.

    ```python theme={null}
    docs = client.doc_list(kb_id, page=1, page_size=20)
    doc = next(d for d in docs.documents if d.title == "Leave policy")
    print(doc.id, doc.topic_count)
    ```

    <Tip>
      `topic_count` greater than 0 is the authoritative signal that ingest finished — a
      document row can exist before its topics do.
    </Tip>
  </Step>

  <Step title="Search it">
    ```python theme={null}
    hits = client.kb_search(kb_id, "how much leave do I get", top_k=5)

    for hit in hits.hits:
        print(hit.name, hit.summary)
        print(hit.document.title)   # parent document context, no second call needed
    ```
  </Step>
</Steps>

## What comes back

The unit of retrieval is the **topic**, not the document. Each hit carries its parent document's title and summary, so a result list needs no follow-up request.

Topic bodies are omitted by default. Ask for them when you actually need the text:

```python theme={null}
hits = client.kb_search(kb_id, "leave policy", include=["content"])
```

<Note>
  Results can include the document-root topic — `depth` 0, the document's own title.
  It is a container, not a section, so its `content` is always null even with
  `include=["content"]`. Skip hits whose `depth` is 0 if you only want real sections.
</Note>

Or read one topic directly:

```python theme={null}
topics = client.knowledge.list_topics(kb_id, doc.id).data
topic  = client.knowledge.get_topic(kb_id, doc.id, topics.topics[-1].id).data
print(topic.content)
```

<Note>
  The topic list includes one synthetic document-root item (`type` is `"root"`), so it
  returns exactly one more entry than the document's `topic_count`, which counts real
  topics only. Build the tree from each item's `parent_id`.
</Note>

## Reading the score

`hit.score` is not a raw keyword or vector score. Every retrieval method reranks its
candidates with a cross-encoder and then normalizes **within that response**, so:

* scores compare inside one response, never across responses or queries;
* the best hit of any response sits near the top of the range by construction, however weak the pool actually is;
* `score_threshold` therefore cuts a relative position, not an absolute relevance bar.

Tune a threshold against real results rather than from a BM25 or cosine intuition.

## Categories

A category is a bucket a document is filed under. **A new knowledge base starts with
none**, so until you create some, every document stays uncategorized (`category_id`
comes back as an empty string) and the classifier has nothing to choose from.

```python theme={null}
hr = client.knowledge.create_category(
    kb_id,
    {"name": "HR", "description": "Policies about people, leave and benefits"},
).data

cats = client.knowledge.list_categories(kb_id).data
for c in cats.categories:
    print(c.id, c.name, c.document_count)
```

With categories in place, ingest classifies each document into one of them — pass
`category_id` on the upload to pin it instead. A category's description is not
decoration: it is what the classifier matches a document against.

Re-file a document at any time:

```python theme={null}
client.doc_update(kb_id, doc.id, category_id=hr.id)
```

Deleting a category does **not** delete its documents — they, and their topics, are
reassigned to uncategorized first.

## Maintenance

```python theme={null}
client.doc_update(kb_id, doc.id, title="Leave policy (2026)")  # metadata only
client.doc_delete(kb_id, doc.id)                                # topics and index go too
client.kb_update(kb_id, description="HR policies, 2026 revision")
client.kb_delete(kb_id)                                         # cascades to everything inside
```

To change a document's *content*, re-ingest it under the same id with
`client.knowledge.replace_document(...)` — the swap is atomic and idempotent per
document id.

## What's next

<CardGroup cols={2}>
  <Card title="Multimodal support" icon="file-arrow-up" href="/cloud/multimodal-support">
    Upload a PDF or an image first, then ingest it by object key.
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/introduction">
    Every knowledge-base operation, with parameters and responses.
  </Card>
</CardGroup>
