RAGBackend. Its shared document and query types let you change storage without rewriting Agent Tools.
The extension chunks and embeds documents, scopes access by namespace, and delegates search to the backend. Your application decides which operations to expose as tools.
Choose RAG or long-term memory
Use RAG for ranked document retrieval. Usecontext.memory for user facts and preferences, searched by literal text. Neither adds retrieved data to prompts automatically.
rag.memory(...) is a process-local RAG test backend, separate from context.memory.
Install the extension
0.1.3 requires Harnest >=1.0.0,<2 and loads asyncpg when the PostgreSQL resource starts.
Supply an embedder
Implement the small provider-neutralEmbedder contract in application code:
lib/embeddings.py
Configure PostgreSQL
Create one application lifecycle resource and publish it to trusted agent code:lifecycle/knowledge.py
pgvector is not required.
Pass an existing asyncpg pool with pool=... when the application already owns connection lifecycle. Set setup_schema=False only when operators provision the same table shape before startup.
See rag.postgres configuration for connection, embedding, chunking, and namespace options.
Retrieve from an Agent Tool
tools/search_knowledge.py
Choose a search mode
search accepts a result limit from 1 to 100, portable metadata filters, and an optional finite min_score. A scalar filter requires equality. A tuple such as {"kind": ("manual", "release-note")} performs membership matching. Different fields combine with AND; tuple values within one field combine with OR. Nested metadata and caller-authored SQL or datastore query syntax are rejected.
Fetch exact chunks
Useawait knowledge.fetch(("manual-2026:0", "manual-2026:3")) when application code already knows chunk IDs. PostgreSQL returns existing chunks in caller order, omits missing IDs, and applies the active namespace without relevance ranking.
Replace documents from trusted code
await knowledge.delete(("manual-2025",), trigger="user"). The active namespace applies to the complete mutation.
Customize chunking
The defaultFixedSizeChunker(size=2000, overlap=200) splits near whitespace with stable IDs. Supply a synchronous Chunker for format-specific boundaries. It must return non-empty strings within ingestion bounds.
Use rag.memory(max_chunks=...) for unit tests and small demos. Its data is lost on exit.
Add another datastore extension
A provider extension depends onrag instead of redefining its public API:
extensions/company-search/extension.yaml
RAGService validates returned hits and namespace isolation. Declare harnest-extension-rag as a distribution dependency; Harnest starts it before dependent extensions.
See the RAG API reference for service methods, data contracts, provider protocols, and ingestion bounds. Validate workload sizes against those bounds before sending large batches.
API reference
Reference:harnest.agent.