--- title: "Built-in tools" description: "Web search, page reading, image generation and OCR that Obol operates itself, priced per action in Obol credits and governed like every other tool." --- **Rolling out.** Obol Cloud does not run the built-in tools service yet, so no workspace on Obol Cloud lists a built-in tool today. This page describes the feature as it is built. **Connectors → Built-in tools** in the dashboard shows what your workspace can call right now. Built-in tools are four tools Obol operates itself, in the `obol` namespace, so an agent can search the web, read a page, generate an image, or read text in an image with nothing but its Obol key. You do not open a vendor account for them. Each call is charged a published fee in Obol credits, paid from your organization's monthly included allowance and then from prepaid credits. They are ordinary native tools. They are default-deny until your policy allows them, and every call goes through the same policy, approval, idempotency, and receipt path as any other tool (ADR-0182). Workspaces that existed before built-in tools shipped start with them turned off. ## The tools One credit is $0.01, or 10,000 `usd_micros`. The prices below come from the reviewed catalog `builtin_v1` (`packages/proto/builtin/builtin_tools.json`). The dashboard and the gateway read that file, and the docs site's claim check fails when a price or allowance on these pages disagrees with it. | Tool | What it does | Effect | Unit | Price | Source | |---|---|---|---|---:|---| | `obol.web_search` | Searches the public web and returns up to 10 results | read | search | 1 credit ($0.01) | SearXNG (AGPL-3.0), open source, operated by Obol. Alternative backend: Brave Search API, on Obol's account | | `obol.web_fetch` | Fetches one public page and returns its main text as Markdown | read | page | 0.5 credit ($0.005) | Scrapling (BSD-3-Clause), open source, operated by Obol | | `obol.image_generate` | Generates one image from a text prompt with FLUX.1 [schnell] | create, destructive: needs approval in prod | image | 2 credits ($0.02) | MuAPI hosted API, on Obol's account | | `obol.image_text` | Extracts printed text from one image with OCR | read | image | 0.5 credit ($0.005) | Tesseract OCR (Apache-2.0), open source, operated by Obol | Obol runs open-source software where it can. A hosted API on Obol's own account is used only where it is cheaper than operating the open-source equivalent and the published fee still covers it. The fee is Obol's own price for the action. It is not a pass-through of a vendor's price and never a percentage of any bill. ### Arguments and results ```json Arguments { "obol.web_search": { "query": "1–400 characters", "count": 5 }, "obol.web_fetch": { "url": "https://…", "max_chars": 20000 }, "obol.image_generate": { "prompt": "1–2000 characters", "width": 1024, "height": 1024 }, "obol.image_text": { "image_url": "https://…", "lang": "eng" } } ``` | Tool | Limits | Result | |---|---|---| | `obol.web_search` | `count` 1–10, default 5 | `results` (`title`, `url`, `snippet`) and the `backend` that answered | | `obol.web_fetch` | public `http(s)` URL up to 2,048 characters; `max_chars` 1,000–50,000; up to 5 redirects; 5 MiB page; 15 s | `url`, `final_url`, `status`, `title`, `content_markdown`, `truncated` | | `obol.image_generate` | `width` and `height` each 512, 768, or 1024 | `image_url`, `content_type`, `width`, `height`, `model`, `backend` | | `obol.image_text` | public `http(s)` image URL; 10 MiB image | `text`, `chars`, `backend` | `obol.web_fetch` and `obol.image_text` refuse private, loopback, link-local, carrier-grade NAT, multicast and cloud-metadata addresses, and re-check every redirect. A refused URL fails with `blocked_destination`. ### Where your arguments go A built-in call sends its arguments to the named source. Your search query goes to SearXNG and the search engines it queries (or to Brave, when that backend is configured). The page or image URL is fetched by Obol's service. Your image prompt goes to MuAPI. If your workspace cannot accept that, leave the tools out of your policy or turn them off. Search results and fetched pages are untrusted source material, never evidence that anything in them is true. A generated `image_url` is MuAPI's hosted URL; Obol does not store or guarantee the image. ## Turn them on An owner or admin turns built-in tools on or off for a workspace on **Connectors → Built-in tools**. When they are off, the workspace's next snapshot carries no built-in tool, whatever its policy says. - **A workspace that existed before built-in tools shipped starts with them off.** No existing workspace gains a tool without an admin's decision. - **A workspace created afterwards starts with them on.** It still lists none until a policy allows them. Review the workspace's permits before you turn built-in tools on. A permit that matches by action or effect alone, such as one that allows every tool call or every read, also matches the built-in tools once they are on. `obol.web_fetch` can send any URL, and any data in it, to any public host, and every built-in call draws your organization's allowance and then prepaid credits. ## Allow them in policy No policy permits a built-in tool by default, and Obol never publishes one for you. Until your policy allows them, `tools/list` does not show them and a call fails exactly as an unknown tool does. **Connectors → Built-in tools** in the dashboard shows a reviewed Cedar permit you can copy into the [policy editor](/policy/publishing). It grants the four named tools and nothing that merely shares the `obol.` prefix: ```cedar @id("obol-builtin-tools") permit( principal is Obol::Agent, action in [Obol::Action::"list", Obol::Action::"call"], resource is Obol::Tool ) when { resource in [ Obol::Tool::"obol.web_search", Obol::Tool::"obol.web_fetch", Obol::Tool::"obol.image_generate", Obol::Tool::"obol.image_text" ] }; ``` To allow one agent only, replace `principal is Obol::Agent` with `principal == Obol::Agent::""`. Narrow it further with the same [Cedar conditions](/policy/cedar) you use for any tool. Each tool carries a reviewed effect, so [approvals](/policy/approvals) behave as for any tool. Search, fetch and OCR are reads. Image generation is a create, and Obol declares every mutation destructive, so in a `prod` workspace each image waits for an approval unless your policy explicitly grants the call. The approval inbox also needs an approval policy rule that covers `obol.image_generate` in `prod`; without one, the request closes as `default_deny`. Holding a call for approval charges nothing: the fee is admitted only when the call is dispatched. Image generation honours an idempotency key, so a retried call does not buy a second image. On the built-in connection the gateway sends Obol's service a key derived from your workspace and the call's own key, never the caller's key verbatim, so one workspace's key can neither replay nor block another workspace's call. ## What a call costs, and who pays A built-in call counts against two separate meters: - **The built-in fee** above, in credits. - **One ordinary tool call** against your plan's call allowance, counted as a read or a write by the tool's reviewed effect, like any other tool call. The fee is funded in this order: 1. **The monthly included allowance**, one per organization and UTC calendar month, shared across the organization's workspaces. Creating another workspace does not add credits, and one busy workspace can use the allowance up for its siblings. It does not roll over. 2. **Your prepaid credit balance**, when the workspace has a credit account and enforcement is on. 3. **Nothing else.** When neither covers the fee, the call is refused before it is dispatched, with the error code `builtin_credits_exhausted`. There is no automatic overage, and a built-in fee is never invoiced in arrears or added to a Team or Enterprise invoice. | Plan | Included built-in allowance per month, per organization | |---|---:| | Free | 100 credits ($1.00) | | Team | 2,000 credits ($20.00) | | Enterprise | 2,000 credits ($20.00), unless a signed agreement sets its own number | The fee is charged once per logical call, when the call is admitted, however many times the call is retried: - **Given back** when nothing was sent, and when Obol's service answers with a 4xx. The service answers 4xx only when it performed nothing: an invalid request, a refused URL, an unconfigured backend, a rate limit, or an idempotency conflict. - **Kept** on a success, and on every uncertain outcome: a 5xx, a transport failure, or a timeout after the request was sent. The upstream may already have done the work, so you can pay for a call that returned no result. - **Never charged twice.** A retry of a call whose fee stands runs under that fee. A retry of a call whose fee was given back is admitted, and charged, again. A changed fee applies only to calls admitted after it is published. Enforcement starts in a dry run. While it is off, a call draws only the included allowance and never your prepaid credits. A call the allowance does not cover still runs and is recorded as `unenforced` rather than refused, and Obol bears its cost. No money moves until a deployment turns enforcement on. Every usage event for a built-in call records the fee and which source paid it. See [Metering](/billing/metering#built-in-tool-fees). | `builtin_charge_source` | Meaning | |---|---| | `included` | Drawn from the organization's included allowance for the month | | `prepaid` | Debited from your prepaid credit balance, with enforcement on | | `unenforced` | Not covered by the included allowance, and admitted because enforcement is off; prepaid credits are not drawn | | `not_chargeable` | A self-hosted deployment, where built-in fees are never charged | ## Availability A built-in tool exists for your workspace only when the deployment runs Obol's built-in tools service and that tool's backend is configured and reports itself available. Control reads the service's capabilities, caches the answer for a minute, and publishes only the tools that are both enabled and available. Control provisions each workspace's system-managed "Obol built-in tools" connection itself: when a workspace or environment is created, and on a reconcile job every five minutes. The same job republishes a workspace whose built-in tools no longer match what control would publish now, for example after the service comes up or a backend is configured. You never create, edit, or delete that connection. An unavailable tool is never in `tools/list`; the dashboard shows it with one of these reasons instead: | Reason | Meaning | |---|---| | `not_configured` | This deployment does not run the built-in tools service | | `service_unreachable` | Control could not read the service's capabilities | | `backend_not_configured` | The service runs, but this tool's backend is not set up, for example image generation before Obol's MuAPI account is configured | | `catalog_mismatch` | The service reports a different catalog version, or a different backend than the reviewed catalog names, so control does not publish the tool | | `not_offered` | The service does not offer this tool | | `not_provisioned` | The workspace's system-managed connection is not ready yet | | `disabled` | An owner or admin turned built-in tools off for the workspace | **Connectors → Built-in tools** is the source of truth for what your workspace can call right now, with this month's calls and spend per tool. {/* TODO: name which built-in backends are live on Obol Cloud once the production apps are deployed (infra/fly/README.md, "Built-in tools"). Do not list a tool as available before then (ADR-0182 §8). */} ## Receipts and evidence Every built-in call gets an idempotency key and a [receipt](/receipts/overview), like any native tool. The receipt records what the gateway observed: Obol's own service answering the request. It is not an independent observation of the search engines, MuAPI, or the site that was fetched, and it never claims to be. The `builtin_v1` tools declare no readback or webhook stage, so no built-in receipt reaches `verified`. See [Evidence](/receipts/evidence) for what each evidence class means. ## Self-hosting The Free Self-hosted bundle does not include built-in tools in v1. No workspace on a self-hosted installation lists a built-in tool, and the installation never calls Obol's hosted service for them. An operator who builds Obol from source can run the service with the `builtin-tools` Compose profile (see [Docker Compose](/deploy/docker-compose#built-in-tools-and-searxng)). They supply their own upstream accounts; Obol never ships its keys to a self-hosted installation. On a self-hosted deployment every built-in call is recorded `not_chargeable`: it is never refused for credits, never debited from a prepaid balance, and never sent to Stripe. ## What built-in tools never do - **Replace your connections.** Obol never substitutes a built-in tool for a connection you made, or the reverse. A built-in tool runs only when it is called by its own name. - **Share your vendor accounts.** If you connect Brave Search or Exa yourself, that connection keeps your key, your quota and your vendor bill. It shares nothing with Obol's account behind `obol.web_search`. - **Expose Obol's upstream keys.** They live only in the built-in tools service: never in your vault, a snapshot, a log, a receipt, or a response. - **Act in a third-party system.** A built-in tool reads public information or produces an artifact for the caller. It never sends, posts, pays, or logs in anywhere in your name or Obol's. Paste the permit, review the diff, and publish it to the gateway. Built-in fees beside the per-call usage rates. How tools are listed, called, and namespaced. The one origin the gateway exempts for built-in tools.