Skip to main content

Framework-agnostic authorization middleware for AI agents

Project description

agent-guard

Framework-agnostic authorization middleware for AI agents.

Intercept, inspect, and enforce policies on any agent action before it executes — whether you're using LangChain, OpenAI, Anthropic, or a bare Python function.

from agent_guard import Guard
from agent_guard.backends import StubBackend

guard = Guard(backend=StubBackend().block(["delete_*", "drop_table"]))

@guard.intercept("send_email")
def send_email(to, subject, body):
    ...  # only runs if the action is allowed

Why

AI agents make real-world calls — they write to databases, send emails, execute trades, call APIs. Without a policy layer between the agent's decision and the actual execution, there's no safety net.

agent-guard sits at that boundary. Every action goes through a check() before it runs. The backend decides: allow, block, or escalate. Your code doesn't change — just wrap it.


Install

pip install agent-guard

No required dependencies. Zero. The core library uses only the Python standard library.

Optional extras for framework adapters:

pip install agent-guard[langchain]
pip install agent-guard[openai]
pip install agent-guard[anthropic]
pip install agent-guard[all]

Quick start

Decorator

from agent_guard import Guard
from agent_guard.backends import StubBackend

guard = Guard(backend=StubBackend(default="allow").block(["delete_*"]))

@guard.intercept("write_file")
def write_file(path, content):
    with open(path, "w") as f:
        f.write(content)

@guard.intercept("delete_file")
def delete_file(path):
    os.remove(path)  # never reached — PolicyBlockedError is raised first

Context manager

with guard.protect("database_write", content=query):
    db.execute(query)

Manual check

decision = guard.check("execute_trade", content="Buy 1000 AAPL at market")
if decision.allowed:
    execute_trade(...)

Async

@guard.intercept("send_notification")
async def send_notification(user_id, message):
    await notify(user_id, message)

# or
decision = await guard.check_async("send_notification", content=message)

# or
async with guard.protect_async("write_cache", content=key):
    await cache.set(key, value)

Backends

Backends decide what happens when an action is checked. Swap them out without changing application code.

StubBackend — local, no external calls

from agent_guard.backends import StubBackend

backend = (
    StubBackend(default="allow")           # allow everything by default
    .block(["delete_*", "drop_table"])     # block these patterns
    .escalate(["send_email", "wire_*"])    # escalate these patterns
    .allow(["read_*"])                     # explicitly allow these
)

Patterns support wildcards (*). Rules are evaluated in order — first match wins.

HttpBackend — any HTTP endpoint

from agent_guard.backends import HttpBackend

backend = HttpBackend(
    url="https://your-policy-server.com/evaluate",
    headers={"Authorization": "Bearer your-token"},
    timeout=5,
)

POST body: serialized Action. Expected response: {"outcome": "allow"|"block"|"escalate", "reason": "..."}.

XybernBackend — Sentinel enforcement API

from agent_guard.backends import XybernBackend

backend = XybernBackend(
    api_key="xb_live_...",
    workspace_id="ws_...",   # optional
)

Routes every action through the Xybern Sentinel control plane. Gives you audit logs, escalation workflows, policy management UI, and trust scoring out of the box.

Build your own

from agent_guard.backends import Backend
from agent_guard.types import Action, Decision

class MyBackend(Backend):
    def evaluate(self, action: Action) -> Decision:
        # your logic here
        if action.action_type.startswith("delete"):
            return Decision(outcome="block", reason="deletes are not permitted")
        return Decision(outcome="allow")

Framework adapters

LangChain

from agent_guard.adapters.langchain import guard_tools

tools = guard_tools([search_tool, calculator_tool, email_tool], guard=guard)
agent = create_react_agent(llm, tools, prompt)

Or wrap a single tool:

from agent_guard.adapters.langchain import GuardedTool

safe_tool = GuardedTool.wrap(email_tool, guard=guard, action_type="send_email")

OpenAI

from agent_guard.adapters.openai import dispatch_tool_calls

response = client.chat.completions.create(model="gpt-4o", messages=messages, tools=tools)

tool_results = dispatch_tool_calls(
    response.choices[0].message.tool_calls,
    handlers={"get_weather": get_weather, "send_email": send_email},
    guard=guard,
)

Anthropic

from agent_guard.adapters.anthropic import dispatch_tool_use

response = client.messages.create(model="claude-opus-4-7", messages=messages, tools=tools)

tool_results = dispatch_tool_use(
    response.content,
    handlers={"web_search": search, "send_email": send_email},
    guard=guard,
)

Configuration

Guard(
    backend=...,
    on_block="raise",     # "raise" (default) | "log" | "ignore"
    on_escalate="raise",  # "raise" (default) | "log" | "ignore"
    agent_id="my-agent",  # passed to the backend with every action
)
on_block / on_escalate behaviour
"raise" raises PolicyBlockedError / PolicyEscalatedError
"log" logs a warning, returns the Decision, execution continues
"ignore" silently returns the Decision, execution continues

Exceptions

from agent_guard import PolicyBlockedError, PolicyEscalatedError, BackendError

try:
    result = execute_trade(symbol="AAPL", qty=1000)
except PolicyBlockedError as e:
    print(e.action.action_type)   # "execute_trade"
    print(e.decision.reason)      # reason from the backend
except PolicyEscalatedError as e:
    notify_human_reviewer(e.action, e.decision)
except BackendError as e:
    # backend unreachable or returned unexpected response
    log_and_fail_safe(e)

Running tests

pip install -e ".[dev]"
pytest

Contributing

PRs welcome. Open an issue first for anything beyond small fixes.


License

MIT — see LICENSE.


Built by Xybern — regulated AI infrastructure.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

xybern_agent_guard-0.1.0.tar.gz (12.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

xybern_agent_guard-0.1.0-py3-none-any.whl (15.1 kB view details)

Uploaded Python 3

File details

Details for the file xybern_agent_guard-0.1.0.tar.gz.

File metadata

  • Download URL: xybern_agent_guard-0.1.0.tar.gz
  • Upload date:
  • Size: 12.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.2

File hashes

Hashes for xybern_agent_guard-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1f68ff994c257799e5bff071327e8163cb4001ba92f72174b099909197171bcf
MD5 008089551204898e4fcd4cb2ca108e45
BLAKE2b-256 851852846c0666d2219b0dafd5c9954a9012e9607e3ea35fa768fee0ecf8024e

See more details on using hashes here.

File details

Details for the file xybern_agent_guard-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for xybern_agent_guard-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a6cb125d1cbee9efe0ca46df9d52f7d673cd7683c0133ef4feffbf4720b2178c
MD5 6e63f9f15b186525e3fb5b5cb5df03b9
BLAKE2b-256 58420190860eeb935aed7a777b993035609e57a355a1c4f7374f82879ba1a679

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page