3.9 KiB
Phase 4 — Capabilities (the scraper APIs)
Build first; every other phase calls this registry. Sibling:
05-access.md(the doors). Reuses Phases 3a/3b/3c (shipped):WebCrawlerConnector.crawl_url -> CrawlOutcome, the proxy/stealth/ captcha tiers, and theWebCrawlCreditServicebilling seam. Locate code by symbol/grep.
Objective
Expose the Acquisition engine as a small set of typed, stateless scraper verbs (web.*, maps.*) that
return cleaned, AI-ready structured data. One capability = one function you call and get data back from.
Verb set (MVP)
Two namespaces: web.* (generic crawler) and maps.* (Google Maps actor). Future platforms slot in as
their own namespace.
| Verb | Input → Output (cleaned) | Executes over | Billing unit |
|---|---|---|---|
web.scrape(urls[]) |
[{url, status, content, metadata}] |
loop crawl_url |
per success |
web.discover(query, top_k) |
[{url, title, snippet, provider}] |
search providers | per search / free |
maps.search(query, location) |
[place] |
Maps actor | per place |
maps.place(place_id|url) |
place |
Maps actor | 1 |
maps.reviews(place) |
[review] (paged) |
Maps actor | per page |
maps.* returns typed structured objects ({name, rating, review_count, hours, price_level, …}).
web.scrape takes a URL array.
Execution
Each verb is a direct async call that returns its cleaned result. Slow verbs (large web.scrape arrays,
maps.reviews paging) are bounded/streamed at the endpoint.
Registry
One entry per verb, and the single source of truth the doors (05) and the agent (07) read from:
Capability {
name # dotted, e.g. "web.scrape", "maps.search"
input_schema # Pydantic
output_schema # Pydantic (cleaned, AI-ready)
executor # async fn; wraps Acquisition / Maps actor; returns data directly
billing_unit # how the billing service charges this call
}
Adding a verb once lights it up on every door.
Billing
A verb declares a billing_unit; charging is delegated to the billing service (03c first provider).
web.scrape→ perSUCCESS(web_crawlunit).maps.*→ new per-place / per-page unit registered with the billing service.- captcha attempts → existing per-attempt
web_crawl_captchaunit (03d). web.discover→ per-search unit (or free).
Location
New Apache-2 package app/capabilities/ (registry, schemas, executors) — open-source and self-hostable.
Executors import the proprietary Acquisition engine and Maps extractor (app/proprietary/…).
Work items
- Registry package:
Capabilitydataclass + registry, imported by05and07. web.scrapeexecutor: loopcrawl_urlover the URL array → per-URL cleaned rows;web_crawlunit.web.discoverexecutor: wrap the search-provider core (SearXNG/Linkup/Baidu, env-keyed); its unit.maps.*contracts: input/output schemas + executor stubs against the Maps actor.- Output normalization: each executor returns AI-ready structured output.
- Billing seam: honor
billing_unitvia the billing service.
Tests
web.scrape([a,b,c])returns one cleaned row per URL inline; partial failures don't fail the batch.- Each
SUCCESSbills oneweb_crawlunit;EMPTY/FAILEDfree; disabling the flag no-ops. - A door and the agent hit the same executor for a verb.
web.discoverreturns{url,title,snippet,provider}; self-disables when no provider key is set.maps.*returns typed structured objects against fixtures.
Out of scope
- Doors →
05. Keep-watching mode →06. Agent →07. - Google Maps actor build (incl. sourcing legality) — net-new, separate effort;
maps.*are contracts. - Additional platform namespaces; recursive site crawl; a generic
web.extractverb.
Open questions
web.discovermetered vs free.- How large
web.scrape/maps.reviewsresponses are bounded/streamed.