Tools — substrate, not resold APIs.
Open-source primitives for the agent's hands. Cheerio scrape, Playwright browse via BullMQ queue, Readability parse, and a sandboxed execute for JS / Python / bash. We don't proxy LLMs, search APIs, or commercial proxy networks — bring your own keys via vault.
We charge for the infra surface — storage, compute time, queue, network egress. Not for a markup on a third-party SaaS we resell.
Scrape — static HTML
Cheerio-based static-HTML extraction. 30× cheaper than browse — use this when the page returns full HTML without JS rendering.
| Field | Type | Description |
|---|---|---|
| urlrequired | string | The URL to fetch. |
| selectorsoptional | object | CSS selectors mapped to output keys: {"title": "h1", "body": "article"}. |
| headersoptional | object | Extra request headers. |
Browse — JS-rendered pages
Playwright-based browse. Queued via BullMQ to a single in-process worker. Returns when the page settles or when a selector matches.
| Field | Type | Description |
|---|---|---|
| urlrequired | string | Target URL. |
| wait_foroptional | string | CSS selector to wait for before extracting (e.g. article.loaded). |
| screenshotoptional | boolean | Include a full-page screenshot in the response (base64). |
| selectorsoptional | object | CSS selectors → output keys. |
Browse jobs return a job_id. Poll /v1/jobs/:id for status, or pass ?wait=true for synchronous return (capped at 60s).
Document — Readability + plain-text
Mozilla Readability + plain-text conversion. Pass HTML or a URL; receive cleaned title, byline, and body text.
| Field | Type | Description |
|---|---|---|
| urloptional | string | URL to fetch + parse. Either url or html required. |
| htmloptional | string | Raw HTML to parse without fetching. |
| formatoptional | "text" · "markdown" | Output shape. Default text. |
Execute — sandboxed runtime
Run code in a sandboxed runtime. Node vm for JavaScript; isolated child_process for Python and bash. Time-limited; resource-capped.
| Field | Type | Description |
|---|---|---|
| runtimerequired | "javascript" · "python" · "bash" | Sandbox to run in. |
| coderequired | string | The script source. |
| envoptional | object | Environment variables. Vault secrets are auto-injected when you reference them by name via {vault: ["openai-key"]}. |
| timeout_msoptional | int | Default 10000, max 60000. |
| stdinoptional | string | Stdin to feed the process. |
curl -X POST https://api.agenttool.dev/v1/execute \
-H "Authorization: Bearer $AT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"runtime": "python",
"code": "import os; from openai import OpenAI;\nc = OpenAI(api_key=os.environ[\"OPENAI_KEY\"]);\nprint(c.embeddings.create(input=\"hi\", model=\"text-embedding-3-small\").data[0].embedding[:8])",
"env": { "vault": ["openai-key"] },
"timeout_ms": 15000
}'
Why execute exists. The agent needs to call paid third-party APIs (OpenAI, Brave, Anthropic, etc.). We don't proxy those — we'd become a bottleneck and a privacy hole. Instead, the agent stores its keys in vault and calls out from execute. We never see the traffic.
Jobs (queued execution)
Poll a queued job (browse, long-running execute). Returns status, progress, and result on completion.
What we dropped
Earlier versions of agenttool included /v1/search (Brave / SerpAPI proxy) and a Bright Data proxy network. Both were paid-third-party-API resale, which violates promise 6 of IDENTITY-ANCHOR.md. They were dropped in the consolidation. The substrate that remains — scrape, browse, document, execute — is open-source primitives running on our infra.
If you want search, store a Brave/SerpAPI key in vault and call it from /v1/execute. You pick the provider; we never see the query.