- Who holds the vendor credential — Obol’s vault, or a third party.
- Who executes the call — the gateway, a trusted worker planning a request the gateway then issues, or a broker outside Obol entirely.
- What each tool’s effect is — declared as a required
EffectSpecon every tool (ADR-0019). See EffectSpec. - What evidence could ever prove that effect happened — which fixes the ceiling on every receipt the connector will ever mint.
What is tier-independent
Whatever tier serves a tool, an agent reaches it the same way: one Obol virtual key against the MCP endpoint. Everything Obol guarantees before a call is the same on every tier, because the gateway sits upstream of all of them: one identity, default-deny Cedar authorization with argument conditions, CEL visibility, approvals for destructive tools, budgets, environment separation, an Obol idempotency key per call, and one attributed invocation history.tools/list never
shows a tool the key cannot call, whatever tier serves it.
What is tier-dependent
What Obol can prove after a call is not the same on every tier. Evidence trust is derived from the configured route, never from what the upstream claims (ADR-0019):
Federated evidence is
untrusted or broker_attested. Both fail the verifier’s
authoritative-trust check, so a purely federated invocation with no separately
authenticated asynchronous stage concludes inconclusive — never verified, and never
contradicted (ADR-0019, ADR-0021, ADR-0025, ADR-0030). Write “receipts prove what a
tool call did” only about a native route; never unqualified.
Routing enforces the same ceiling before selection: a binding declaring an evidence floor
above its connection’s tier ceiling is excluded (obol-types/src/routing.rs, reason
EvidenceFloor). See Routing and the catalog.
Catalog brokers are vendors, never authority
Invariant 9 governs every federated connector. A broker never mints a receipt, assigns evidence trust, enforces a policy decision, chooses a target, or supplies idempotency. Idempotency is always Obol’s — neither Nango nor Composio offers one, and their retry knobs generate duplicate writes, so broker-side retries are disabled on every call. The gateway screens a broker’s connect-session response for authority-shaped keys (target, policy, evidence, receipt, idempotency,
idempotency_key, retry, credential) at any depth and refuses the call if one is
present (ADR-0038).
The three tiers at a glance
Native
OpenAPI import plus a reviewed overlay. Obol vaults the credential, the gateway
issues the request, evidence is gateway-observed.
Trusted worker
An out-of-process worker that plans requests and normalizes responses. Reserved
design — no package, no image, no deployed service, and ADR-0024’s
credential boundary is not yet implemented.
Federated
A catalog broker or remote MCP server holds the vendor connection. Cheap breadth,
bought with evidence.
ConnectionSnapshot::tier() reads custody, kind, and target
(apps/gateway/crates/obol-types/src/snapshot.rs).
SnapshotValidationError::FederatedCustodyOnNativeTarget), so a brokered route cannot
be authored as custody: federated over an OpenAPI target and quietly keep a
gateway_observed stamp. Work through the ordered table in
Connector tiers before authoring anything.
The connector pack layout
Reviewed connector packs live inpackages/connectors/<slug>/. The slug is the ADR-0015
tool prefix: dot-free, [a-z0-9_-], and every tool in the pack is named
{connector}.{tool}.
overlay.json and bundle.json are both hand-authored: there is no bundle compiler and
no obol-bundle binary, so nothing derives one from the other and nothing derives
BundleTool.destructive from effect.kind. Set both by hand and validate by
round-tripping through the schemas in packages/proto/.
A bundle carries the reviewed data the runtime pins:
tier and custody must agree with the connection it activates.
CONNECTOR.md records the vendor brief the tier decision cites, and help.json is the
operator’s note — what they must do on the vendor’s own site before Obol can reach it.
Neither is remote text; both are reviewed, committed, diffable repo content, and neither
may be fetched at render time.
The federated catalog
packages/connectors/catalog/ is a different shape, deliberately. It is one frozen index
plus one overlay template applied to every catalog-sourced tool — not a pack per
vendor, because a pack per vendor is the iPaaS treadmill the PRD forecloses.
index.json is generated by generate.py from two inputs: vendored public broker
catalogs for the federated long tail, and the reviewed native packs on disk for the
routes Obol custodies itself (generate.py::native_packs() walks every
packages/connectors/*/bundle.json whose tier is native and custody is obol). Broker
catalog text is untrusted input; the index is discovery data, never live authority for
effect or verification semantics.
All structurally valid native and federated capability bindings are eligible
(ADR-0063). A workspace still needs an active matching connection, a concrete tool,
and permission. The historical broker review in
packages/connectors/catalog/CATALOG.md
remains evidence about execution readiness: federated completion returns
409 broker_verification_unavailable until authenticated account verification
exists. Eligibility does not imply that a broker connector has been live-verified.Where to go next
Pick a tier
The ordered decision table, and the Gate 0 risk class that runs before it.
Author an EffectSpec
Shape, fields, validation errors, and the traps no validator catches.
Add a connector
Vendor brief, contract-first order, Cedar, fixtures, probes.
Read a receipt
What the receipt records about tier, custody, evidence, and conclusion.