Your tools.One contract.Any system.
An adapter is what lets Company Runtime act on a tool your company already uses — and prove that it did. Agents ask for an outcome; the adapter knows how to get it from Slack, from your ERP, or from a rule your own team wrote.
- 1Ask
An agent asks for an outcome —
Capability request · actor · inputresource.update— never for a tool or a vendor. - 2Check
The runtime checks who may ask and what your policy says. High-impact actions wait for a person.
Authority deny-by-default · policy auto | approval | deny - 3Resolve
It picks the adapter your organization installed for that intent.
Deterministic resolver · one installation per organization - 4Execute
The adapter runs in its own sealed container. The key is handed over for this call only, and only its declared hosts are reachable.
http/0.1 provider API · CredentialRef · egress allowlist - 5Prove
The adapter returns evidence. Without it, nothing counts as done.
provider_receipt · state_observation · unknown → reconcile - 6Record
A receipt enters the event log: who asked, under which authority, what happened, at what cost.
Integrity-protected receipt · replayable events
Your tools stay. Agents learn to use them.
An adapter is a translator between what an agent wants to happen and how one specific system makes it happen. Your technical team writes it once; from then on, every agent in your company can use that system within the authority you give it.
- 01
Keep the tools you run on
CRM, ERP, team chat, spreadsheets or a system built in-house: your technical team wraps each one in an adapter. Nothing is migrated.
- 02
Agents never hold the keys
Access is granted on each vendor's own consent screen and kept by the runtime. An agent only ever sees a reference to it.
- 03
Every action leaves a receipt
Who asked, under which authority, what happened and at what cost is recorded — auditable and replayable.
- 04
Change vendors, not workflows
Agents ask for outcomes such as
communication.send. Replace one chat tool with another and nothing that asks for it changes.
What you have, what agents ask for.
Every tool maps to a few intents from the protocol's shared vocabulary. Official adapters cover some systems; your technical team, or any publisher, covers the rest.
- Team chatSlackOfficial adapter
communication.send - Issue trackerGitHub, GitLabOfficial adapter
work.creatework.assignwork.complete - AI modelsOpenAI, AnthropicOfficial adapter
reasoning.generatereasoning.classify - CRMDeals, contacts, accountsYour team, or a publisher
resource.searchresource.update - ERP or billingOften on your own networkYour team
resource.readresource.create - Documents and knowledgeWikis, manuals, policiesYour team, or a publisher
knowledge.search - Business rulesDiscounts, credit, complianceYour team · no vendor
policy.evaluate
An adapter doesn't have to call anyone.
Most adapters translate to a vendor's API. Some reach a system inside your company. And some carry the logic themselves: a container that holds one business rule, answers an intent, and never leaves its sandbox.
A vendor's service
Translates an intent into a SaaS API call — Slack, GitHub, your CRM. The container reaches only the hosts its release declares.
communication.send · work.createA system inside your company
Talks to an ERP, a database or a legacy service your team runs. On-premise it reaches it on your network; hosted, it calls a public HTTPS endpoint you declare.
resource.read · resource.updateA rule of your own
Packages one piece of business logic — discount approval, credit limits, a compliance check — as a container. No vendor, no key, no Internet.
policy.evaluate
Your business logic, with the same guarantees as any action.
Take a discount policy. Up to 10% is fine; up to 25% on large orders needs a manager; more is refused. Written as an adapter for policy.evaluate, it becomes something every agent can consult — and every answer is recorded.
- People and agents ask for it exactly as they ask for anything else — by intent.
- It is versioned and pinned by image digest, so every past decision can be reproduced.
- It returns evidence and lands in a receipt, like any action on any system.
- Swap the rule, or put a model behind the same intent, without touching a single caller.
import { defineProvider } from "@runtime-protocol/sdk";
// A business rule, shipped as an adapter: no vendor, no key, no Internet.
export const provider = defineProvider({
id: "acme-discount-rule",
version: "1.0.0",
capabilities: [
{
capability: "policy.evaluate",
evidence: { claims: ["execution"], types: ["provider_receipt"] },
},
],
credentials: { required: false, accepts: [] },
handlers: {
"policy.evaluate": async (input, ctx) => {
const { discount_pct, order_total } = input.subject as {
discount_pct: number;
order_total: number;
};
const decision =
discount_pct <= 10
? "allow"
: discount_pct <= 25 && order_total >= 5_000
? "require_approval"
: "deny";
return {
output: {
decision,
reasons: [`${discount_pct}% on an order of ${order_total}`],
matched_rules: [`discount.${decision}`],
},
evidence: [ctx.evidence.providerReceipt(["execution"], { decision })],
};
},
},
});
// Its marketplace release declares no hosts at all:
// "egressHosts": []Same adapter. Your choice of ground.
An adapter ships as an immutable container image. The hosted runtime and an on-premise installation run that same image under the same contract — what changes is who operates it and what it can reach.
- We operate the runtime and the connector host.
- Adapters reach public HTTPS hosts their release declares.
- Credentials are encrypted in the runtime, under a key kept outside the database.
- Your team operates the same runtime on your infrastructure.
- Adapters can reach internal systems your operator allows — without exposing them.
- Credentials, events and receipts are stored on your own servers.
| Hosted | On-premise | |
|---|---|---|
| Who operates it | Company Runtime | Your team, on your infrastructure |
| Where adapters run | Our connector host, one container per installation | The same connector host, inside your network |
| What adapters can reach | Declared public HTTPS hosts | Declared hosts, including internal ones you allow |
| Where credentials live | Encrypted in the hosted runtime | In your runtime's keyring, on your servers |
| Updates | Each organization chooses when to update an adapter | You pull new releases and images, pinned by digest |
| Adapter images | The same image, digest for digest | The same image, digest for digest |
From a tool to an agent's hands, in six steps.
No change to Company Runtime is needed. A container that speaks the Runtime Protocol's http/0.1 provider binding is enough.
- 01
Pick the intent
Find the capability in the protocol registry —
resource.update,communication.send,policy.evaluate. An adapter never invents vocabulary; vendor-only behaviour goes undervendor.<vendor>.*. - 02
Implement the provider
Write it with
defineProviderfrom the Runtime SDK. Input is validated against the capability schema before your handler runs; read the key only throughctx.credential()and return evidence for every claim. The official adapters are the template. - 03
Test it against a simulated API
The provider harness checks requirements
PC-001–PC-010: schemas, evidence, honest failures, idempotency, reconciliation. No test calls a real vendor.terminal runtime-conformance provider ./dist/provider.js \ --export provider --samples samples.yaml - 04
Package it as a container
Serve the
http/0.1provider API on port8789, run as UID65532with a read-only filesystem, and verify every invocation token with the broker. Push the image to GHCR and pin itssha256digest — tags are refused.server.mjs (excerpt) import { createProviderHttpHandler, toNodeListener } from "@runtime-protocol/sdk/http"; import { createServer } from "node:http"; const handler = createProviderHttpHandler(provider, { publicRoutes: ["manifest", "health"], authenticate: async (request) => verifyWithBroker(request), credentials: (request) => ({ materialize: (ref) => credentialFromBroker(ref, request), }), }); createServer(toNodeListener(handler)).listen(8789, "0.0.0.0"); - 05
Publish a release
Submit its capabilities, the agent tools it offers, the hosts it may reach and, when it needs one, an OAuth descriptor. The runtime checks the digest, the manifest and that unauthenticated calls are refused. Every version is immutable.
release.json (excerpt) { "providerId": "acme-crm", "version": "1.0.0", "imageRef": "ghcr.io/acme/crm-adapter@sha256:…", "agentTools": [ { "capability": "resource.update", "name": "connector_acme_crm_update_deal", "description": "Update a deal in the CRM." } ], "egressHosts": ["api.crm.example"] } - 06
Install it, per organization
A founder reviews the capabilities, hosts and image digest, installs the release and, if it needs one, approves access on the vendor's consent screen. Only then do that organization's agents get its tools — and policy still decides every call.
What an adapter
can't do.
Whoever wrote it, an adapter runs with nothing but its own code and the one call it was given. The same limits apply to an official adapter, to one from a publisher, and to yours.
- 01No database URL, encryption key, session secret, Docker socket or host mount.
- 02No route to the Internet: outbound HTTPS only to declared hosts, through the broker — no redirects, responses capped at 1 MiB.
- 03Non-root user
65532, a read-only filesystem, and/tmpas the only writable path. - 04A short-lived token per call, bound to one organization, installation, connection and invocation.
- 05An uncertain effect is reconciled, never blindly repeated.
Start from what's already open.
Everything an adapter needs is public, Apache-2.0, and depends on no product — ours included.
defineProvider, the provider harness and the HTTP binding.Read the guideSource of truthRuntime ProtocolThe registry of intents every adapter implements.Read the guide