obex
Deterministic, config-driven guardrails for LLM agent tool calls. Zero-LLM enforcement. Compliance audit trail built in.
Named after the Latin word for bolt or barrier. The bolt on the gate that no LLM can argue past.
Why
LLM agents can now call tools autonomously — execute SQL, send emails, make API calls. Existing guardrail frameworks either use LLM calls in the enforcement path (non-deterministic, slow, expensive) or require writing Python code that compliance teams can't review.
Obex is different:
- YAML config — rules live in config files that compliance teams can review, version, and audit without reading Python
- Zero-LLM enforcement — every decision is deterministic and reproducible. No AI in the guardrail path.
- Compliance-first — OPA-inspired audit trail as a first-class feature, not an afterthought
- Framework-agnostic — works standalone or with LangGraph, CrewAI, or any agent framework
| Feature | Obex | NeMo Guardrails | LangChain Middleware | OpenAI Agents SDK |
|---|---|---|---|---|
| Config-driven (YAML) | Yes | Colang DSL | Python code | Python decorators |
| Zero-LLM enforcement | Yes | No (LLM in loop) | Yes | Yes |
| Audit trail | Built-in | Logging only | No | No |
| Framework-agnostic | Yes | LangChain | LangChain only | OpenAI only |
| Dependencies | Zero (stdlib) | Heavy | LangChain | OpenAI SDK |
Quick Start
pip install obex[yaml]
from obex import Engine, ToolCall
engine = Engine.from_yaml("rules.yaml")
# Evaluate a tool call
result = engine.evaluate(
ToolCall(name="execute_sql", args={"query": "DROP TABLE users"})
)
print(result.decision) # Decision.BLOCK
print(result.reason) # "Pattern matched in field 'query': DROP TABLE"
YAML Config
version: "1.0"
policy_version: "1.0.0"
rules:
# Block dangerous SQL patterns
- name: block_sql_injection
type: regex_block
applies_to: ["execute_sql", "run_query"]
params:
fields: ["query"]
patterns:
- "(?i)(DROP|DELETE|TRUNCATE)\\s+TABLE"
# Require confirmation IDs on sensitive operations
- name: require_confirmation
type: regex_require
applies_to: ["send_email", "transfer_funds"]
params:
fields: ["confirmation_id"]
pattern: "^CONF-[A-Z0-9]{8}$"
# Scan all tool calls for PII leakage
- name: detect_pii
type: pii_detect
applies_to: ["*"]
params:
detectors: [email, phone_intl, hk_id, credit_card]
action: block
# Role-based tool access
- name: tool_entitlement
type: entitlement
applies_to: ["*"]
params:
roles:
analyst: ["search", "get_data", "summarize"]
admin: ["*"]
default: block
Rule Types
| Type | Purpose | Key Params |
|---|---|---|
regex_block |
Block if field matches pattern | fields, patterns |
regex_require |
Block if required field is missing/invalid | fields, pattern |
pii_detect |
Scan args for PII (email, phone, HKID, etc.) | detectors, action |
entitlement |
Role-based tool access control | roles, default |
Audit Trail
Every evaluation produces a structured JSON record (JSONL format, OPA-inspired):
from obex import AuditLogger, Engine
logger = AuditLogger("audit.jsonl")
engine = Engine.from_yaml("rules.yaml", audit_logger=logger.log)
Each record includes: decision_id, timestamp, policy_version, tool_name, tool_args (redacted), decision, rules_evaluated, blocking_rule, human_override, trace_id.
Audit Reports
Generate compliance-ready summaries from audit logs:
from obex import AuditReporter
reporter = AuditReporter("audit.jsonl")
report = reporter.generate()
print(report.to_text())
========================================
OBEX AUDIT REPORT
========================================
Period: 2026-02-28 10:00 to 2026-02-28 16:00
Policy versions: 1.0.0
Total evaluations: 500
Allow: 450 (90.0%)
Block: 50 (10.0%)
Top blocked tools:
1. execute_sql — 25 blocks
2. send_email — 15 blocks
Top triggered rules:
1. block_sql_injection — 20 triggers
2. detect_pii — 18 triggers
Human override rate: 4.0% (2 of 50 blocks overridden)
========================================
LangGraph Integration
pip install obex[langgraph]
from langgraph.prebuilt import ToolNode
from obex import Engine
from obex.adapters.langgraph import guarded_tool_node
tools = [search, calculator]
engine = Engine.from_yaml("rules.yaml")
safe_tools = guarded_tool_node(ToolNode(tools), engine)
builder.add_node("tools", safe_tools)
Blocked tool calls return a ToolMessage with the block reason — the LLM sees why its call was rejected and can adjust.
Programmatic Use (No YAML)
from obex import Engine, ToolCall
from obex._types import RuleConfig, RuleType
engine = Engine(rules=[
RuleConfig(
name="block_drops",
rule_type=RuleType.REGEX_BLOCK,
params={"fields": ["query"], "patterns": [r"(?i)DROP\s+TABLE"]},
applies_to=["execute_sql"],
),
])
result = engine.evaluate(ToolCall(name="execute_sql", args={"query": "SELECT 1"}))
assert result.decision.value == "allow"
Zero dependencies — the core engine runs on stdlib alone.
Design Philosophy
- Hooks > prompts for mechanical rules. If a rule is regex-matchable, enforce it in code, not in the system prompt.
- Fail closed. If a rule errors, the tool call is blocked.
- No LLM in the enforcement path. Every decision is deterministic and reproducible.
- Config is reviewable. Compliance teams review YAML, not Python.
- Audit schema inspired by OPA. Decision logs follow established policy-engine conventions.
License
MIT
Metadata
Release files for obex 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| obex-0.1.0.tar.gz | 88.5 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| obex-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 102.7 kB
Release files / obex-0.1.0.tar.gz
| Download URL | obex-0.1.0.tar.gz |
|---|---|
| Size | 88.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
434ba063e976c7d70a8d1564f5a5c86e18eb5becb2e87aa6f2ca007709cf55dd
|
|
BLAKE2b-256 checksum How to use checksums |
7f7311d64e3a5f409897d222ea4202aa061e33c121df212b151956009990305c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Release files / obex-0.1.0-py3-none-any.whl
| Download URL | obex-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8450c4f45aaee357eae986a1178f0d8c8aa43caf2b3330bccfa120f4340ff0cb
|
|
BLAKE2b-256 checksum How to use checksums |
cb24e8922c0ad8ee087d8133c8ca18d626eeddfdecfc20bb3eb84916483dad88
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.5
|
Security for obex 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.