Published Pages
Keep published Markdown and search vectors in sync, then search and read the same page revision.
Use published pages when your knowledge source is a documentation site with llms.txt and clean Markdown endpoints. Knowledge can synchronize that source, search its sections, and read the full page behind a result. Page text and vectors are published together, one page at a time.
uv pip install -U "agno[os,mcp,pages,openai]"Set OPENAI_API_KEY and DATABASE_URL before running the example. Use a PostgreSQL database with the pgvector extension available and permission to create the required tables and indexes.
Configure the page store
from os import environ
from agno.db.postgres import PostgresDb
from agno.fs import FileSystem
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.knowledge.knowledge import Knowledge
from agno.vectordb.pgvector import PgVector
db = PostgresDb(db_url=environ["DATABASE_URL"])
knowledge = Knowledge(
content_db=db,
page_store=FileSystem(db=db, namespace="product-docs"),
vector_db=PgVector(
db=db,
table_name="product_doc_vectors",
embedder=OpenAIEmbedder(id="text-embedding-3-small"),
),
)
knowledge.setup()Published pages require a synchronous PostgresDb, a PostgreSQL-backed FileSystem with an explicit namespace, and PgVector in the same logical database. Keep their storage tables distinct. setup() prepares the page store and search indexes; async applications use await knowledge.asetup() before serving or syncing.
content_db is the preferred spelling. contents_db remains a supported read/write alias. If you supply both constructor arguments, they must refer to the same database object.
Synchronize published Markdown
Continue in pages.py:
report = knowledge.sync_pages(url="https://docs.agno.com/llms.txt")
print(report.model_dump_json(indent=2))
if report.status == "partial":
raise RuntimeError("Some documentation pages could not be synchronized")Sync discovers the index and supported sub-indexes, fetches pages, prepares chunks and embeddings, and reconciles the published namespace. Unchanged generations are reused. Each changed page is published atomically; the entire site is not one transaction. Inspect the returned SyncReport, including failed and removed pages.
| Option | Purpose |
|---|---|
public_url | Set the public URL used for citations when the fetch origin differs |
transform | Apply an application-owned Markdown transformation before indexing |
index_version | Change the index-format version when your transformation or indexing contract changes |
reindex=True | Rebuild existing pages even when their source has not changed |
validate_discovery | Check discovered and previously published page counts before fetching or publication; raise ValueError to reject the discovery |
The async method is await knowledge.async_sync_pages(...). Supply a fast synchronous validate_discovery(discovered_count, published_count) callback when your application needs a policy for unexpectedly small indexes.
When page_store is configured, change managed pages through sync. Ordinary insert, content metadata patching, and content deletion methods do not mutate this coordinated page store.
Search, then read the matching revision
result = knowledge.search_pages(
"How do agents use tools?",
alternatives=["Agent tools configuration"],
)
for hit in result.results:
print(hit.path, hit.url, hit.revision)
if result.results:
hit = result.results[0]
page = knowledge.read_page(hit.path, revision=hit.revision)
print(page.text)
while page.next_offset is not None:
page = knowledge.read_page(
hit.path,
revision=page.revision,
offset=page.next_offset,
)
print(page.text)Search combines indexed vector and full-text retrieval and fuses results from the supplied phrasings. Alternative queries come from the caller; this API does not call a language model to invent them. max_output_bytes bounds the serialized search result, including metadata, from 24,000 to 32,000 UTF-8 bytes.
Use the returned revision when expanding a hit. If a sync replaced that revision, handle the page error by searching again or retaining the original excerpts. Do not silently substitute a newer page while presenting it as the evidence returned by the earlier search.
Read offsets count Unicode code points. Continue with both the returned revision and next_offset until next_offset is None. Search results can be partial or truncated; an empty or incomplete result does not prove that the docs contain no answer.
List pages and find literal text
catalog = knowledge.list_pages(prefix="/agents", limit=20)
for page in catalog.pages:
print(page.path, page.title)
matches = knowledge.grep_pages("tool_call_limit", prefix="/agents")
print(matches.model_dump_json(indent=2))Listing returns a namespace-revision-bound cursor for the next page. If a later response requests a pagination restart, begin again without the cursor. grep_pages finds literal text in a bounded scan; check its completeness before drawing a conclusion from no matches.
The async counterparts are asearch_pages, aread_page, alist_pages, and agrep_pages. Page result types and errors are exported from agno.knowledge.page.
Expose retrieval explicitly
Configuring a page store does not insert a retrieval prompt or choose a product's tool policy. Wrap the public APIs in the tools your agent needs. Catch PageError and invalid input at the tool boundary and use tool_error() to return a bounded error response.
For command-style exploration, use PageFileSystem with the configured Knowledge instance:
from agno.agent import Agent
from agno.knowledge.page import PageFileSystem
page_files = PageFileSystem(knowledge=knowledge)
print(page_files.run_command("ls /"))
print(page_files.run_command('rg "tool_call_limit" /agents'))
agent = Agent(tools=[page_files.tools()])PageFileSystem interprets read-only commands such as ls, tree, find, cat, head, tail, rg, grep, and wc. It does not invoke a shell or write files. Its output and regex execution are bounded. Use arun_command() from async code.
The general FileSystem also supports writes and agent-scoped namespaces. PageFileSystem is specifically for reading published Knowledge pages. See how we built our Docs Agent for explicit first-turn retrieval and citation policy.