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

# Knowledge Base Maintenance

> Update, replace, and delete stored SDK chunks as source content changes.

A RAG index goes stale when source content changes. The SDK gives you two maintenance paths:

| Need                                       | SDK method                                                    |
| ------------------------------------------ | ------------------------------------------------------------- |
| Rebuild a source and upsert the new chunks | `rag.ingest(...)` or manual stages ending in `rag.store(...)` |
| Replace known chunk IDs                    | `rag.edit(chunks=[...])`                                      |
| Remove stale chunk IDs                     | `rag.delete(ids=[...])`                                       |

## Track Source Manifests

For long-lived indexes, keep a manifest that maps each source to the chunk IDs produced from it.

```python theme={null}
manifest = {
    "policy.md": {
        "chunk_ids": ["policy-0", "policy-1"],
        "checksum": "...",
    }
}
```

When the source changes, re-ingest it, compare old IDs to new IDs, and delete stale chunks.

```python theme={null}
old_ids = set(manifest.get("policy.md", {}).get("chunk_ids", []))

result = rag.ingest(markdown=[{"text": updated_policy, "source": "policy.md"}])
new_ids = {item["id"] for item in result.store_result.items}

stale_ids = old_ids - new_ids
if stale_ids:
    rag.delete(ids=sorted(stale_ids))

manifest["policy.md"] = {"chunk_ids": sorted(new_ids)}
```

## Edit Known Chunks

Use `edit()` when you know the exact chunk IDs to replace.

```python theme={null}
edited = rag.edit(chunks=[
    {
        "id": "refund-policy-0",
        "text": "Customers can request a refund within 45 days of purchase.",
        "source": "policy.md",
        "metadata": {"title": "Refund policy"},
    }
])

edited.requested
edited.edited
edited.failed
edited.errors
```

`edit()` re-embeds the replacement chunk text before writing it back to the vector database.

## Delete Removed Chunks

Use `delete()` for exact chunk IDs that should no longer appear in retrieval.

```python theme={null}
deleted = rag.delete(ids=["refund-policy-0", "refund-policy-1"])

deleted.requested
deleted.deleted
deleted.failed
deleted.errors
```

Deletes do not perform semantic matching. They only remove exact IDs.

## Full Refresh Pattern

```python theme={null}
def refresh_source(source_id: str, text: str, manifest: dict) -> None:
    old_ids = set(manifest.get(source_id, {}).get("chunk_ids", []))
    result = rag.ingest(markdown=[{"text": text, "source": source_id}])
    new_ids = {item["id"] for item in result.store_result.items}

    stale = old_ids - new_ids
    if stale:
        rag.delete(ids=sorted(stale))

    manifest[source_id] = {"chunk_ids": sorted(new_ids)}
```

## Operational Guidance

| Concern          | SDK practice                                                                                |
| ---------------- | ------------------------------------------------------------------------------------------- |
| Stable IDs       | Preserve `source` metadata and use deterministic source inputs so chunk IDs stay traceable. |
| Partial failures | Check `failed` and `errors` on every result before updating your manifest.                  |
| Deletes          | Delete old IDs only after the replacement ingest succeeds.                                  |
| Auditing         | Store source ID, checksum, chunk IDs, and update time outside Ragrails.                     |
| Drift            | Re-query after updates to verify the expected chunks are retrieved.                         |

<CardGroup cols={2}>
  <Card title="Storing" icon="database" href="/usage/sdk/storing">Use store, edit, and delete directly.</Card>
  <Card title="Retrieval" icon="search" href="/usage/sdk/retrieval">Verify updated results.</Card>
</CardGroup>
