---
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.