Agno Knowledge's inspect_page_source() shows which llms.txt URL a page store namespace is bound to, and migrate_page_source() rebinds it. Both have async versions, ainspect_page_source() and amigrate_page_source(). Say your docs move from docs.example.com to public.example.com. The published pages, catalog rows and vectors in your page store are all fine, but the namespace stays bound to the old llms.txt URL, and changing that binding used to take hand-written SQL. migrate_page_source() now does it behind a set of guards.

old = "https://docs.example.com/llms.txt"
new = "https://public.example.com/llms.txt"
knowledge.inspect_page_source() # source=old, revision=1
knowledge.migrate_page_source(expected_source=old, target_source=new) # dry run, changed=False
knowledge.migrate_page_source(expected_source=old, target_source=new, dry_run=False)
# changed=True, after.source=new, after.revision=2
knowledge.sync_pages(url=new) # citations now use public.example.comWhat migrate_page_source() checks
Every call, dry run or not, runs the same guards before it touches anything. Against a local PostgreSQL page store, three of them raise these errors:
http:// target ValueError: invalid_source_url
different path on the new host ValueError: source relocation must preserve the discovery path
current source is neither URL ValueError: page source does not match the expected source or relocation target- Both URLs must use HTTPS, and the path must match exactly. Only the host can change. The comparison is literal, so an encoded spelling of the same path fails.
- The namespace must use the catalog and vector tables that this
Knowledgeis configured with. - The current source must equal
expected_source, or already equaltarget_source. The second case makes a repeated call safe. It returnschanged=Falseand leaves the revision alone. migrate_page_source()takes the namespace lock that sync uses. During an active sync or another relocation it raisesPageSourceBusy. A sync that starts while a relocation holds the lock waits for it, and readers keep working throughout.
migrate_page_source() makes no network request, so Agno can't confirm that you own the new host or that it serves the same documentation. Check both before you apply.
What happens after you apply
An applied relocation changes only the binding's source and bumps its revision. Pages, catalog rows and stored vectors stay as they are, so citations keep naming the old host until the next sync. The new revision also makes open list_pages cursors report restart_required.
Point every sync producer at the new URL and run a normal sync_pages() or async_sync_pages() with the same transform and index_version. In a real run, that sync republished the page with public.example.com citation URLs and made 0 embedding calls. A producer still configured with the old URL fails with "filesystem namespace is bound to another documentation source", and sync never rewrites the binding itself.
If an apply fails partway (a timeout, a lost connection), don't assume it rolled back. Call inspect_page_source(), or repeat the same request. Agno adds no HTTP route or model tool for relocation, so it stays an operator action.
See the cookbook, and learn more about Published Pages in the documentation.
Frequently asked questions
Call knowledge.migrate_page_source(expected_source=old, target_source=new) to run a dry run, then repeat it with dry_run=False to apply. Then point your sync at the new URL and run a normal sync_pages, which refreshes citation URLs.
Both URLs must be HTTPS and share the same discovery path, the namespace must use the configured catalog and vector tables, and the current source must equal expected_source or already equal target_source. The namespace lock rejects the call with PageSourceBusy during an active sync or another relocation.
No. migrate_page_source changes only the source binding and its revision. The follow-up sync with the same transform and index_version republishes unchanged pages with new citation URLs and reuses their embeddings.
After a relocation, Agno Knowledge refuses a sync that still uses the old URL with "filesystem namespace is bound to another documentation source". Point every sync producer at the new URL.




