Reading a page in full
A search's snippet tells the agent whether a page is the right one; the page holds the fact. jevlin fetch --stdin reads up to five pages a search returned, in full, and answers with the same envelope a search does.
jevlin fetch --stdin takes one JSON object and answers with one envelope carrying the same header as a search, with command set to fetch. It sends POST /v1/fetch to the configured router with the same key, deadline, redirect policy and user agent as a search. The router serves only pages from this account's own recent search results, and only to an account that can fetch. The skill teaches it.
jevlin fetch --stdin <<< '{"version":1,"pages":[{"source_id":"s_…"}],"query":"the fact you need"}'
The request
| field | value |
|---|---|
version | 1, required. |
pages | 1 to 5 entries, required. Each is exactly one of {"source_id": "s_…"}, a page's source_id from a search's result.merged, or {"url": "https://…"}, an absolute http or https URL. |
max_chars | 1000 to 50000: how many characters of each page to return. Absent, the router's default. |
offset | 0 or more: where in each page's text to start. Pass a page's next_offset to read on. |
query | Up to 500 characters, not blank: the router starts a long page's text near the part that matches. |
Every malformed value, and any other field, answers fix_input before the router is called. A field is spelled exactly as above: Pages or VERSION is unknown_field, naming the key, exit 2, and the router is never called.
The answer
On success, result.pages is the router's pages in its order. Each has source_id, url, title, status, content, offset, next_offset (absent at the end of the text), content_length, truncated and full_length (present when the upstream cut the page), reason (on a failed page), provider, cached and cost_micros. result.usage has the call's cost_micros and latency_ms.
A page's status is ok, failed, invalid, or not_recent:
okcarries the page'scontent.failedcarries areason:upstream_failed, which a later try may fix, orunrendered, a page that needs a browser.not_recentis a page not among this account's recent results, so use the host's own fetch tool for it.
A page that did not come back is not a failed call: ok stays true.
What it costs
Each page carries its own cost_micros, and result.usage.cost_micros is the call's, in millionths of a dollar. The price per page is on Pricing and credit.
When it fails
| router answer | code | retryable | action |
|---|---|---|---|
403 fetch_unavailable | fetch_unavailable | false | connect: this account cannot fetch, and error.message says why |
| 404 or 405 | fetch_not_supported | false | report: this router has no fetch |
503 fetch_disabled | fetch_disabled | false | report: this router has fetch switched off |
| 502, or any other 5xx (another 503 too) | the router's code, else router_error | true | retry |
| 401 | the router's code, else unauthorized | false | login |
402 search_credit_only | search_credit_only | false | report: the credit left this week is reserved for search; fetch resumes at the weekly reset or after a top-up |
| any other status | as for a search |
A fetch is one request and is never retried by the client. A failed fetch leaves the search's results standing: the skill tells the agent to answer from them, and on fetch_unavailable, fetch_not_supported or fetch_disabled to stop fetching for the task and tell you once, without running connect.
search_credit_only means the credit left is the part of the weekly allowance kept for search: search still works, and fetch resumes at the weekly reset or when credit is added. See Rate limits and spend caps.
See also
- The envelope: the header every answer shares, and the failure codes.
- The MCP server: the same request as the
fetchtool. - In Claude Code, a request holding a
'or a$goes through a file in therequestsfolder; see Claude Code.