Integration ecosystem

September 20, 2026 · View on GitHub

ActionGate aims to make specialized decision models useful through a plug-and-play authorization layer. Every integration should reuse the same tenant identity, tool registry, policy, decision evidence, and Action Grant lifecycle instead of reimplementing safety logic in each framework.

The target shape is a hub with a connector catalog: one small core that owns identity, policy, and enforcement, plus many thin connectors that plug into it. A connector should be something a developer adds in minutes and removes without residue — never a framework they have to adopt. If a connector needs its own policy engine, its own notion of tenant, or its own permit format, it is doing the core's job and the design is wrong.

Integration levels

Not every connector provides the same security boundary. Documentation and package names should state the level explicitly.

LevelBehaviorSecurity value
ObserveSends proposed actions in Shadow Mode and records wouldHaveDecisionFast evaluation; no execution control
GuardAuthorizes and consumes a grant immediately before invoking a handlerStrong in-process boundary if the raw handler stays private
IsolateOwns the network path or downstream credential and refuses access without grant consumptionMakes bypass materially harder
GovernConnects identity, registry, review, audit, incident, and observability systemsOperable control plane across teams

The target is broad compatibility at Observe/Guard and a smaller set of high-confidence Isolate integrations.

Common adapter contract

Every action adapter should provide:

  • a stable tool name and normalized operation;
  • JSON Schema for canonical arguments;
  • owner, data sensitivity, and risk classification;
  • authenticated tenant, environment, actor, and role context;
  • user intent and a minimal set of decision-relevant resources;
  • deterministic facts obtained from trusted application services, preferably through a server-side fact provider rather than the request body;
  • a unique request ID and idempotency key;
  • a private execution function or isolated credential boundary;
  • execution outcome metadata for the evidence loop.

The registry—not the agent—owns operation, schema, risk, sensitivity, and policy linkage. An adapter may send those fields for explicit binding, but ActionGate rejects mismatches.

Connector manifest

Every connector declares itself the same way so the catalog stays machine-readable and a developer can tell what they are installing before they install it. A connector that cannot fill this out honestly is not ready to publish.

FieldMeaning
nameStable connector identifier
levelobserve, guard, isolate, or govern
protectsThe handler, endpoint, or credential behind the boundary
bypassRemaining unguarded paths, stated plainly
requiresProvider key, Redis, PostgreSQL, or nothing
toolsTool names and operations the connector proposes
factsDeterministic facts it supplies and where each originates
setupSteps a developer performs, counted honestly

bypass is mandatory and may not be empty. "None known" is a claim that must be backed by the connector's negative tests.

Worked example: the MCP proxy manifest

FieldValue
name@actiongate/mcp-proxy
levelisolate
protectsThe upstream MCP server's network endpoint and its credential, which stay inside the proxy process
bypassAnything that can reach the upstream MCP server directly. The proxy only isolates if the upstream endpoint is not routable from the agent. Relayed user intent is agent-supplied, so it is semantic evidence, not trusted input; it can never override a hard rule.
requiresAn ActionGate API key, an upstream URL and credential, and one downstream proxy token. Nothing else.
toolsWhatever the tenant registry enables and the upstream server also exposes; the intersection, never the union
factsThe fake-provider development server has a small labeled local fixture for the bundled refund demo. Configure ACTIONGATE_FACT_PROVIDER_URL for every non-demo deployment so RBAC, spend, and duplicate checks are resolved rather than asserted; without one, any tool carrying hard rules fails closed.
setupPoint the MCP client at the proxy URL and give it a proxy token. No application code changes.

What the proxy refuses, in every case without calling upstream: an unknown or disabled tool, a tool the registry does not own, a BLOCK or REVIEW decision, an enforced allow with no grant, a failed consumption, an unreachable ActionGate, an unauthenticated caller, and any JSON-RPC method it does not explicitly handle.

Connector friction rules

The catalog is only useful if adding a connector is cheaper than hand-rolling the same protection. Budgets come from the adoption friction budget.

  1. Work at Tier 0. Every connector must run against the fake provider with no key, no database, and no container. A connector that only works against a full production stack cannot be evaluated, and will not be adopted.
  2. One screen to adopt. The smallest working example fits on one screen. If it does not, the connector needs a preset, not a longer README.
  3. No new required configuration. Defaults cover the common case. A connector that needs more than three settings at any tier ships a preset instead.
  4. Removable. Document how to take the connector out. A connector that cannot be removed without rewriting application code is a framework.
  5. No parallel safety logic. Thresholds, risk classes, retries that change semantics, and local permit caches belong in the core or nowhere.
  6. Honest level. Claim guard only when the raw callable is private. Claim isolate only when the connector owns the network path or the credential. When unsure, claim observe.

Shipped integrations

IntegrationLevelStatusNotes
REST APIObserve / Guard building blockShippedLanguage-neutral authorize, consume, registry, key, review, audit, and retention endpoints
TypeScript clientGuardShipped in workspacewrapTool authorizes, consumes, then calls a private function
MCP gatewayGuardShipped in workspaceOwns tool metadata and keeps the grant outside model-visible arguments
MCP proxyIsolateShipped in workspaceStandalone network service; holds the upstream credential and consumes a grant before forwarding
Redis runtime adapterGovernShippedDistributed idempotency, decision state, revocation, and one-time consumption
Python clientGuardShipped in workspacewrap_tool authorizes, consumes, then calls a private handler; standard library only
PostgreSQL control-plane adapterGovernShippedTenant keys, policies, registry, reviews, corrections, encrypted audit
HTTP reverse proxy / sidecarIsolateShipped in workspaceDeclarative route-to-tool mapping; an unmapped route is a 404, never a pass-through
Credential brokerIsolateShippedExchanges a consumed grant for a short-lived signed request bound to the exact action
Trusted fact providersGovernShippedFunction and HTTP adapters resolve RBAC, spend, and duplicate facts server-side
Signed webhooksGovernShippedHMAC-signed deliveries with a replay window, bounded retries, and dead-lettering

Every connector ships a manifest, validated in CI by pnpm manifests:validate. Packages build with declared exports (pnpm build:packages, checked by pnpm packages:check) but are not yet published to a registry; until a release exists, use the REST contract, the generated client, or workspace dependencies.

Priority integration map

P1: hard execution boundaries

All four shipped. See the quickstarts and each package's manifest.

  1. Standalone MCP proxy — shipped.
  2. HTTP reverse proxy and sidecar — shipped, with a sidecar preset.
  3. Credential broker — shipped as POST /v1/grants/exchange plus verifySignedRequest for the downstream side.
  4. Webhook gateway — shipped, with signing, a replay window, retries, destination allowlisting, and dead letters.

P2: developer frameworks

  • Python SDK with the same authorize/consume/wrap contract as TypeScript;
  • adapters for popular TypeScript/Python agent and workflow frameworks;
  • server middleware for common web frameworks;
  • automation-platform actions and triggers;
  • generated clients from an explicit, versioned API description.

Framework adapters are Guard integrations only when the raw callable is private. Otherwise they must be labeled Observe.

P2/P3: enterprise control plane

  • identity providers and workload identity;
  • API gateways and service meshes;
  • secret managers and cloud credential services;
  • review/incident systems and signed notification webhooks;
  • telemetry exporters and data warehouses;
  • policy-as-code repositories and controlled environment promotion.

Adapter conformance

A connector claims an integration level. @actiongate/conformance checks the claim by driving the adapter against a scripted ActionGate and asserting the handler ran only when it should have.

import { createScriptedGate, runConformance } from "@actiongate/conformance";

const gate = createScriptedGate();
const result = await runConformance({
  name: "my-adapter",
  level: "guard",
  attempt: async ({ tool, arguments: args }) => ({ executed: await myAdapter(tool, args) })
}, gate);

if (!result.conformant) console.error(result.checks.filter((check) => check.status === "fail"));

The checks that apply to guard and isolate: executes on allow, consumes exactly one grant, and does not execute on BLOCK, on REVIEW, on an allow carrying no grant, when consumption fails, or when ActionGate is unreachable. An observe adapter is checked the other way round — if it blocks, its level is wrong and it should be labelled guard.

Every adapter this project ships is run through the suite in CI, so the checks are calibrated against real implementations rather than only against examples.

Trusted facts

Deterministic facts decide whether a hard rule passes, so where they come from matters more than what they say.

  • Caller-supplied facts are untrusted. Anything in the request body was asserted by whoever called the API. An agent that can reach ActionGate can claim its own RBAC.
  • Provider-resolved facts are trusted. A TrustedFactProvider runs inside the ActionGate API and asks a service the deployment operates. Its answer overrides the caller's claim about the same fact.
  • Provenance is evidence. Every decision records which facts were resolved and by which provider, so an audit can tell a vouched-for fact from a claimed one.
  • Every hard-rule fact must be trusted. requireTrustedFacts remains in the versioned policy contract for compatibility, but it is no longer an opt-in switch: caller assertions never satisfy hard rules. Add maxFactAgeSeconds where a stale answer would be dangerous.
  • A failing provider fails closed. It contributes no facts, so the rule it would have satisfied is unevaluable and blocks, with FACT_PROVIDER_UNAVAILABLE explaining why.

A connector cannot make its own facts trusted. Facts sent by an adapter — including the MCP proxy — arrive as caller provenance, because from the API's perspective an adapter is just a client. Trust is established by running a provider on the API side.

Adapter design rules

  1. Normalize before authorization. The exact canonical arguments being authorized must be the arguments later executed.
  2. Keep credentials behind the boundary. The agent and caller should never receive the downstream secret.
  3. Consume at the last responsible moment. Consumption belongs immediately before the side effect, after local validation and before credentials are used.
  4. Fail closed on ambiguity. Unknown tool, missing grant, registry mismatch, invalid schema, changed arguments, expiry, revocation, and replay stop execution.
  5. Preserve idempotency. Retries reuse the same key only for the same canonical request. Changed payloads need a new key after reconciliation.
  6. Record outcomes separately. Authorization success is not proof that the business operation completed.
  7. Do not leak model-visible permits. Prefer combined server-side authorize-and-execute flows; otherwise carry grants in protected metadata.
  8. Test the negative path. Every adapter needs assertions that the handler is not called after authorization, consumption, mutation, tenant, or dependency failure.

Definition of done for a new integration

  • example works against the fake provider with zero external spend;
  • tool metadata is server-owned or synchronized through an authenticated administrator path;
  • tenant and environment come from authenticated context;
  • exact arguments are schema-validated and bound to consumption;
  • no raw API key, grant, or downstream credential appears in logs, errors, fixtures, or model-visible fields;
  • BLOCK, REVIEW, missing grant, mutation, expiry, revocation, replay, and cross-tenant use never call the handler;
  • restart and concurrent-consumption behavior is tested when the adapter is networked;
  • README states its integration level and bypass assumptions;
  • latency and provider cost are reported separately from security correctness;
  • the connector has been exercised against the configured live provider (pnpm test:jev:live for OpenRouter or pnpm test:typesafe:live for direct TypeSafe), and resolved model, latency, tokens, and available cost data are recorded;
  • the connector manifest is complete, including a non-empty bypass statement;
  • the setup steps were counted against the friction budget and the count is published.

Contributing an adapter

Start with a concrete side effect and threat boundary, not a framework logo. A proposal should identify:

  1. the handler or credential being protected;
  2. where trusted identity and deterministic facts originate;
  3. how tool metadata enters the registry;
  4. where grant consumption occurs;
  5. what unguarded bypass paths remain;
  6. the positive, failure, cross-tenant, replay, and restart tests;
  7. the smallest copy-paste example a new adopter can run.

The delivery order is tracked in roadmap.md; the architecture invariants are in AGENTS.md.