Regent ControlSDK & Integration

SDK & Integration

Three ways to integrate, one decision contract. Goal: integrated in under 30 minutes, or zero-code via MCP.

SurfaceWho holds the provider keyUse when
Python SDK (regent-control)your code, or the sidecarPython agents/services
TypeScript SDK (@regent/control-sdk)your codeNode/TS agents
MCP (sidecar /mcp)the sidecar onlyMCP-native agents — zero code

Python — gate-direct

from regent_control import RegentControl
 
control = RegentControl(api_key="rgnt_ctrl_…", agent_id="agent_refund_bot")
 
d = control.authorize(
    tool="payments", action="refund.create",
    amount_usd=50, mandate_id="mnd_support_refunds",
    idempotency_key="T-8842:ch_aaa",          # a retry won't double-refund
    user_token=rep_id_token,                  # the human's OIDC token — gate-verified
    intent="refund the duplicate charge on ticket 8842",
    facts={"account_status": "active", "refund_to_original": True},
)
if not d.allowed:
    raise RuntimeError(f"{d.code}: {d.reason}")
do_refund(scoped_token=d.token)
control.complete(d.decision_id, status="success", downstream_ref=refund_id)

A deny is a return value, not an exception — call d.raise_for_status() (or control.authorize_or_raise(...)) to turn a non-allow into a typed error (MandateExceeded, PolicyDenied, Escalated, …).

Develop with zero prod traffic: regent-control dev --deny-over 200 --escalate-over 1000, then point the client at base_url="http://localhost:8009". In tests, from regent_control.dev import run_mock_control.

Python — sidecar-routing (the agent holds no key)

from regent_control import SidecarSession, MandateExceeded
 
sc = SidecarSession(base_url="http://localhost:8080",
                    user_token=rep_id_token, intent="refund duplicate charge")
try:
    resp = sc.call("payments", "refunds", method="POST",
                   json={"charge": "ch_aaa", "amount": 50},
                   facts={"account_status": "active", "refund_to_original": True})
except MandateExceeded as e:
    ...   # the sidecar injected the real credential; you never saw it

TypeScript — gate-direct

import { RegentControl, ControlDenied } from '@regent/control-sdk';
 
const control = new RegentControl({ apiKey, agentId: 'agent_refund_bot' });
const d = await control.authorize({
  tool: 'payments', action: 'refund.create',
  context: { amountUsd: 50, mandateId: 'mnd_support_refunds',
             idempotencyKey: 'T-8842:ch_aaa', userToken: repIdToken,
             intent: 'refund duplicate charge',
             accountStatus: 'active', refundToOriginal: true },
});
if (!d.allowed) throw new ControlDenied(d.code, d.reason, d.decisionId);
await control.complete(d.decisionId, { status: 'success', downstreamRef: refundId });

MCP — zero code

Point the MCP-native agent at the sidecar’s /mcp endpoint. Each catalogued tool is an MCP tool whose inputSchema accepts path, method, body, and the control fields intent, user_token, and facts. A deny comes back as an MCP tool error (isError: true).

Verify the scoped token at your service edge

The complement to the client: your downstream service validates the gate-issued scoped JWT against Regent’s JWKS and enforces the scope itself — least privilege at the edge.

from regent_control.verify import TokenVerifier, ScopeError  # pip install "regent-control[verify]"
 
verifier = TokenVerifier(jwks_url="https://api.regentprotocol.org/.well-known/jwks.json")
scoped = verifier.verify(token, expected_tool="payments", expected_action="refund.create")
# TokenError → 401, ScopeError → 403; scoped.agent_id / scoped.decision_id are audit-ready

Human-in-the-loop (escalation)

Any policy can return escalate. The action is parked for a human; the idempotency key is the resume handle: the agent retries the same action with the same key, and once approved it returns allow (denied → a terminal deny). Set the sidecar’s CONTROL_ESCALATION_WAIT_SECONDS > 0 to briefly poll inline; default 0 is the async/retry model. Approve/deny in Control → Approvals.

Error-code catalog

Every non-allow decision carries a stable code, mapped to a typed error by the SDKs.

codeMeaning
IDENTITY_NOT_RESOLVEDagent id unknown
AGENT_NOT_ACTIVEagent suspended/revoked
POLICY_DENIEDa Cedar rule forbade it
TOOL_NOT_ALLOWEDtool not in the catalog
MANDATE_NOT_FOUNDmoney action without a mandate
MANDATE_LIMIT_EXCEEDEDover a spend cap
RISK_THRESHOLD_EXCEEDEDrisk score too high
ESCALATION_REQUIREDneeds a human approval
INTERNAL_ERRORtransport/plane failure — retry

Transport failures (timeout, DNS, 5xx, bad key) are always raised; the gate fails closed.

The agent contract — checklist

  • agent_id + tool/action (the SDK attaches the agent id).
  • amount_usd + mandate_id for any money action.
  • user_token — the human’s OIDC id_token when acting on someone’s behalf (gate-verified).
  • intent — why the agent is doing this (compliance, never trusted as enforcement).
  • facts — verified context the policy keys on (account_status, refund_to_original).
  • idempotency_key — a stable key per logical action; a retry replays the prior decision.
  • handle deny + escalate; for ESCALATION_REQUIRED, park and resume on approval.
  • call complete(...) to close the audit and reconcile counters.