Reference links
Attach a URL to an agent and Aethex crawls it into the agent's knowledge base. Nothing is fetched during a call.
How it works
You attach one or more URLs to an agent. A background job fetches each page, converts it to clean markdown, splits it into chunks, embeds them, and files each page as an ordinary knowledge-base document. From there it is the same retrieval as an uploaded PDF: a local search of a few tens of milliseconds, with nothing fetched while the call is running. A link can be a single page, or a whole site: in `site` mode the crawler follows the page's internal links, bounded by the limits below.
Attaching links
Send a list, not one URL at a time. `crawl_mode` is per link, because a documentation root is worth crawling as a `site` while a pricing page is not. The request returns immediately with each link `queued`: a fifty-page crawl with embedding does not fit inside an HTTP request.
curl -X POST "$BASE_URL/agents/$AGENT_ID/reference-links" \
-H "X-API-Key: $AETHEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"links": [
{ "url": "https://docs.example.com/", "crawl_mode": "site" },
{ "url": "https://example.com/pricing", "crawl_mode": "page" }
]
}'Nothing is served until you approve it
A crawl does not put anything in front of your callers. Every page it stores waits in `pending_review` until you approve the link, because a bad scrape that lands silently poisons all future calls. The preview sorts anomalies first rather than by crawl order. A held candidate, then anything awaiting review, and within each group the shortest extraction first, since a page that came back nearly empty is the likeliest bad scrape. Approving takes the whole link, minus the pages you exclude; an excluded page is remembered as rejected and loses its chunks, so the index carries nothing that will never be served.
# What the crawl found, anomalies first.
curl "$BASE_URL/agents/$AGENT_ID/reference-links/$LINK_ID/pages" \
-H "X-API-Key: $AETHEX_API_KEY"
# Put them into service, minus the ones you do not want.
curl -X POST "$BASE_URL/agents/$AGENT_ID/reference-links/$LINK_ID/approve" \
-H "X-API-Key: $AETHEX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "exclude": ["doc-uuid-of-a-page-you-reject"] }'Re-crawling
Every link is re-read on a fixed interval so a page that changes does not go stale. There is no per-link setting: the interval is the same for every link, which means a link cannot be pinned to never re-crawl. A pass that finds the page unchanged does nothing at all: it does not re-embed, and it does not ask you to approve anything again.
When a page collapses
One case gets neither treatment: a re-crawl that comes back with a fraction of the text it had before. That is what a broken template or a site migration looks like, and replacing good content with it would be worse than doing nothing. So the page keeps serving what it had, and the new extraction is held aside as a candidate. The preview then shows both sides: the size before, the size now, and the candidate's own title, so you can judge which one is the real page.
{
"id": "doc-uuid",
"source_url": "https://docs.example.com/pricing",
"status": "completed",
"size_bytes": 7178,
"chunk_count": 4,
"candidate": {
"at": "2026-08-31T12:19:22Z",
"title": "Pricing",
"size": 501,
"previous_size": 7178
}
}# Accept it, and the shorter version takes over without the page
# ever leaving service.
curl -X POST \
"$BASE_URL/agents/$AGENT_ID/reference-links/$LINK_ID/pages/$DOC_ID/accept-candidate" \
-H "X-API-Key: $AETHEX_API_KEY"Reading a link's state
`crawl_state` answers one question only: did the crawl work. It is written by a crawl and nothing else, so every value it can hold is settled the moment a pass ends.
queuedAttached, waiting for its first pass.
crawlingA pass is running right now.
readyThe crawl reached every page it meant to.
partialThe crawl lost something: it stopped at the page limit or its time budget, or some pages failed. `last_crawl_error_detail` names which.
failedThe crawl brought back nothing. `last_crawl_error_code` says why.
pages.flagged > 0, not on crawl_state. The flagged count is what says a human needs to look, and it is recomputed on every read, so it drops to zero the instant you accept a candidate, without waiting for the next crawl. A page whose extraction collapsed leaves the link ready, because the crawl itself worked.Why a link failed
A failure on a discovered page does not stop the crawl: it is recorded and the pass continues, and `last_crawl_error_detail` summarises what went wrong. A failure on the URL you attached fails the link, and `last_crawl_error_code` carries one of the following.
| Code | What happened | What you can do |
|---|---|---|
unreachable | DNS failed, the connection was refused, or the redirects never resolved to a page we can fetch. | Check the URL resolves and answers from outside your network. |
timeout | The page did not answer inside its budget. | Retry later, or attach a page that responds faster. |
http_4xx | The server answered 4xx. Most often the page does not exist. | Fix the URL. |
http_5xx | The server answered 5xx. | The site is broken or overloaded; wait and retry. |
paywalled | 401, 402 or 403: there is content here we are not allowed to read. | Attach a publicly readable page instead. |
js_only | The fetch succeeded but the HTML carried no readable text: the page renders in the browser, so what arrived is a shell. | Attach a URL that serves HTML. On a portal root, `site` mode often reaches the real pages one click in. |
robots_disallowed | `robots.txt` forbids this path for our crawler. | Nothing: we respect it. Attach a different URL. |
too_large | The page body passed the size ceiling while being read. | Attach a narrower page. |
blocked_host | The URL resolved to a private, internal or cloud-metadata address. | Nothing: refused on security grounds. Attach a public URL. |
internal_error | The crawl job itself failed. This one is ours, not the site's. | Nothing: the pass is rescheduled automatically. |
Limits
Ten links per agent. A `site` crawl reads up to 50 pages, three levels deep, and gives up after ten minutes. A single page is read up to 5 MB. The crawler identifies itself, honours `robots.txt` including `Crawl-delay`, and makes one request at a time per host with a pause between them. It is reading someone else's site, not stress-testing it. These are the same for every account and are not configurable.
Next
Reference links and uploaded files land in the same place. See the knowledge base for what happens to a document once it is in service, and how retrieval uses it.
