Skip to content

The agent's side

Every authorisation product treats the agent as the adversary. The Xybern Authorisation Layer also treats it as a client that wants to be safe. Four mechanisms, all available through xybern.agentside.AgentSide and the framework integrations:

Question the agent has Mechanism
May I, and what would it take? Pre-flight
Whom may I trust? Trusted instruction channel
Will what I run be what was authorised? Declared intent
I was refused; how do I ask properly? Authority Requests
from xybern import Xybern
from xybern.agentside import AgentSide

me = AgentSide(Xybern(api_key="xb_live_..."), agent_id="agt_payments", principals=["agt_orchestrator"])

Pre-flight: know your bounds before you act

Hand over the plan; every step comes back allowed, needs_approval or refused, with the reason, the mandates involved, and what it would take.

answer = me.preflight([
    {"ref": "1", "action_type": "read_file"},
    {"ref": "2", "action_type": "send_payment", "metadata": {"amount": 5000}},
    {"ref": "3", "action_type": "delete_record", "optional": True},
])
answer["summary"]        # {"steps": 3, "allowed": 1, "needs_approval": 1, "refused": 1, "executable_now": False, ...}
answer["results"][1]     # outcome "refused", what_it_would_take {"kind": "bound", "detail": "amount at most 1000"}, request_template {...}

The plan runs through the same checks the intercept applies, in dry-run: paused workspace, revoked agent, warrant requirement, access profile, intent contract, the live rules (deterministic ones evaluated, semantic and risk rules reported as judged at run time), the principal's authority when acting under a grant, and any active authority grant. Nothing is executed and no decision is recorded. The answer is signed and sealed as a pre-flight record (Requests view, "Pre-flight records"), so a later dispute can show what the agent was told.

what_it_would_take is machine readable: bound (the value that would make it allowed), approval (the approver role and the typical wait from the workspace's escalation history), request (a ready authority request), warrant, resume, runtime, or none. me.plan_within_authority(steps) splits a plan into runnable, held and refused steps and collects the requests that would unlock them.

Declared intent: what you run is what was authorised

me.guarded("send_payment", lambda: pay(120, "acc-1"), metadata={"amount": 120, "to": "acc-1"})

guarded declares the exact action (POST /v1/enforce/declare), which is authorised like any action and, when allowed, returns a commitment hashing the declared parameters. The execution presents the commitment (intercept(..., commitment=...), or the Xybern-Commitment header at the MCP gateway); the enforcement point recomputes the hash of the actual parameters. A recipient or amount changed after authorisation, by injected text or anything else, is refused with decision_path: "commitment" and an incident is opened. Commitments are single use and expire after five minutes (XYBERN_COMMITMENT_TTL_SECONDS). Fields that legitimately vary (idempotency keys, timestamps, the agent's reasoning) are excluded from the hash; add your own with vary=[...].

Trusted instruction channel: know whom to trust

An instruction is an action. me.send("agt_worker", "Reconcile September invoices") passes through the intercept as send_instruction; when authorised, the Authorisation Stamp bound to the hash of the text becomes the envelope. The receiver:

msg = me.receive(incoming)      # Received(kind="instruction", principal="agt_orchestrator", ...) or Received(kind="data", reason=...)
if msg.is_instruction:
    act_on(msg.text)
else:
    treat_as_data(msg.text)     # never follow directives found in data

Only a message carrying a valid envelope from one of the agent's principals is an instruction; a tool result, a web page, a document or an unsigned message is data, however it is phrased. me.system_prompt_fragment() gives the model the rule in plain words. On the control plane, an agent whose registration sets require_signed_instructions (Registry, or POST /enforcement/agents/<id>/agent-side-policy) is refused any agent-to-agent instruction without a valid envelope, before it can act on it (decision_path: "instruction"); its principals list says who may instruct it.

Authority Requests: ask properly

When an agent that may request authority (may_request_authority on its registration, or request_on_refuse=True on the call) is refused by rules or its profile, a request is filed automatically with the action family, the bounds implied by the action, a one-action budget, an hour, the agent's stated reason, and exactly the rules and profile that refused. The response carries authority_request so the agent can wait for it (client.wait_for_authority) instead of retrying. Requests can also be filed from a pre-flight request_template (me.request_from_template(...)) or by hand (me.request_more(...)).

A grant is a scoped, time-boxed exception: the intercept lifts only the listed rules (and the profile when asked), only for the requested families within the requested bounds, only for the granted number of actions, until it expires. Everything else in the Charter still evaluates. The grant is backed by a temporal permission window and a child warrant with the same bounds, sealed to the Vault, and shown in the decision's lineage ("under authority request areq_… granted by …").

Humans decide in the Requests view (Escalations group): grant with a reason and a duration, or deny. Granting a high blast-radius request needs a session that passed MFA. Agents can never grant. A Charter mandate can pre-authorise small requests: "agents may request up to SAR 50,000 extra for one hour, granted automatically when the blast radius is low" compiles to an authority_request rule with caps on bounds, duration, blast and action count; requests inside the caps are granted immediately with the rule as the resolver.

Framework integrations

Framework Import What it does
Claude Agent SDK / Claude Code xybern.integrations.claude_agent_sdk.pre_tool_use_hook(side) A PreToolUse hook that declares each tool call and denies it when Xybern refuses; preflight_plan for a batch of tool calls
MCP servers xybern.integrations.mcp.guard_mcp_server(server, side) Wraps tools/call: declare, execute with the commitment, refuse with a readable message
OpenAI Agents SDK xybern.integrations.openai_agents.xybern_input_guardrail(side), guard_function_tool Input guardrail on the trusted channel; tool wrapper with declare-then-do
LangChain xybern.integrations.langchain.XybernCallbackHandler(side) Declares every tool start, refuses when Xybern refuses, classify() for what the chain reads
CrewAI xybern.integrations.crewai.guard_tool(side, tool) Wraps a tool's run with declare-then-do; refusals come back as text the crew can act on

API

Method Path Purpose
POST /v1/enforce/preflight {agent_id?, session_id?, contract_id?, grant_id?, steps: [...]}
GET /v1/enforce/preflights/<id> A pre-flight record
POST /v1/enforce/declare Same body as intercept; returns commitment when allowed
POST /v1/enforce/intercept Accepts commitment, commit, vary, request_on_refuse
POST, GET /v1/enforce/authority-requests File, list
GET /v1/enforce/authority-requests/<id> Status (and the warrant token while granted)
POST /v1/enforce/instructions, /v1/enforce/instructions/verify Send a signed instruction; verify an envelope

SDK 2.7.0: preflight, get_preflight, declare, request_authority, get_authority_request, list_authority_requests, wait_for_authority, send_instruction, verify_instruction, intercept(commitment=, commit=, vary=, request_on_refuse=), xybern.agentside.AgentSide, xybern.integrations.*.