Agent Skill
Use afhttp first when the user gives a concrete URL, or refers to a previous
URL/site, and asks to read, inspect, summarize, extract, verify, open, visit, or
directly access it. Do not start with web search for a supplied URL unless the
user explicitly asks for search/discovery, the URL is incomplete, or the afhttp
path fails and you clearly label search as fallback evidence.
For command details, prefer discovery over memorization:
afhttp --help
afhttp fetch --help
afhttp container --help
Fetch A Page
Start with a structured fetch:
afhttp fetch "$URL"
Read content.md first when content_file is present; it is the
agent-oriented composed page view and should include visible text from open
shadow DOM, same-origin frames, cards, tables, and links. If the fetch stayed on
the HTTP fast path, read body_file first and only retry with --render always
or explicit --want content,content_json,observation,network,console when the
raw body looks incomplete, placeholder-like, or contradicted by warnings. Use
content.json when present and you need to choose a follow-up link/action.
Inspect observation.json, network.json, and console.json only when needed.
Use rendered_html as a debug artifact, not as the authoritative rendered page.
Before answering, sanity-check the artifact you read against stdout warnings. If
the main facts look incomplete, placeholder-like, or contradicted by
readiness/network warnings, do not treat the capture as final. Prefer a more
specific same-site link from content.json.links when available, one
longer-wait or browser-render retry, or clearly state that the page did not
fully settle.
Treat status: 200 as transport only. If the page is a login, consent gate,
security check, captcha, or bot wall, do not answer as if the target page was
verified.
Stay On Task
Keep the crawl bounded by the user’s actual question. For follow-ups like “that provider too” or “compare them”, use the same product class and the previously gathered facts; do not broaden into unrelated product lines unless the user asks.
Stop as soon as official artifacts contain enough target content to answer
confidently. A single --render always retry is fine when the HTTP fast path or
the first render omits useful content.md, but do not keep drilling into app
bundles, JavaScript source, or extra APIs after prices/specs/products are
already visible in content.md, content.json, observation.json, or captured
network-bodies.
First-party network endpoints are acceptable only when they were observed in
that page’s network.json, are public (2xx without authentication), and
directly explain the same visible page. Do not call authenticated/private APIs,
admin endpoints, or token-required APIs to answer a page-reading question; if
one returns unauthorized, token required, forbidden, or similar, abandon
that endpoint and answer from the official page artifacts you already have.
Fetch raw JS/CSS bundles only for debugging an afhttp/site rendering problem or when the user explicitly asks for implementation details. Do not reverse engineer site bundles just to answer normal pricing/product questions.
When the task needs a deeper same-site page, choose from
content.json.links first. Prefer visible, same-site links whose kind matches
the task (product_detail, pricing, or docs). Do not infer follow-up URLs
from JS bundles when content.json.links already contains relevant candidates.
Direct Browser Access
When the user asks to open/visit/directly access a URL, use a managed host tab so the agent can observe and continue. Do not open the target URL directly in an unmanaged local browser.
Check for a reusable host:
afhttp container status
If no host is running, start one:
afhttp container install
Open a persistent tab and give/open the returned next_action.takeover_url.
The URL is a short-lived handoff; tell the user its expiry if
next_action.takeover_url_expires_at_rfc3339 is present. The standard local
afhttp-host endpoint and token are discovered automatically:
afhttp fetch "$URL" --takeover
After the human finishes, run the returned next_action.recommended_command to
read the same tab before summarizing.
Bot Walls And Human Takeover
If afhttp reports a next_action.kind: "human_takeover" (or only page_kind: "bot_wall_detected" / "security_challenge_detected"), or artifacts clearly
show captcha/security verification (Cloudflare, “verify you are human”,
“checking your browser”, “access denied”, etc.), enter a hard stop: do not keep
fetching the target, do not web-search for substitute answers, and do not use
third-party mirrors/proxies/readability services. The only allowed next step is
re-running the fetch with human takeover against a takeover-ready host:
afhttp fetch "$URL" --takeover
afhttp container install builds a takeover-ready host (Brave + KasmVNC real
display) by default. When --endpoint-url is omitted, fetch --takeover
discovers the standard local afhttp-host and reads its token; it does not
start containers for you. It opens a persistent tab and fetches once. By default
each site gets its own isolated profile (the URL’s registrable domain /
eTLD+1), so logins and cookies don’t leak across sites; pass
--profile work only to intentionally share browser state across sites. If the
warmed profile already reaches the target it returns the content directly (no
next_action); use that instead of bothering the user. If it returns
next_action.kind: "human_takeover", give/open the complete
next_action.takeover_url (it normally expires after about 15 minutes), ask the
user to complete or confirm the visible browser state, then stop and wait. Only
after the user explicitly confirms should you run
next_action.recommended_command (a re-fetch of the same --tab).
If takeover still fails, report that the target page could not be verified and name likely external causes such as IP/network reputation, account state, or site policy.
Host State
Inline afhttp fetch is one-shot and non-persistent. Use a container host when
you need session reuse, a warmed/authenticated profile, human takeover, or CDP
state inspection. A host serves one active profile at a time but switches at
runtime when a fetch passes --profile (the browser is relaunched under it);
persistent profile storage is scoped by backend, so work under Brave and
work under Chromium are separate identities.
Use afhttp health, afhttp capabilities, afhttp tabs, or afhttp cdp only
when the task needs that detail; check the relevant --help before doing so.