Current collected state Current
Observed since 20 Oct, 21:25 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
agendex
Governance SDK for AI Agents - Runtime policy enforcement, activity capture, and approval workflows
Resource-Level Governance for AI Agents - Dynamic task-scoped access control, parameter inspection, and tamper-evident audit trails.
| Traditional IAM | Agendex |
|---|---|
| "Agent can use payment tool" | "Agent doing vendor_payment task can call payments API if amount < $1000" |
| Static permissions | Dynamic, task-scoped |
| No parameter inspection | Full body/query inspection |
| Tool-level control | Resource-level control |
pip install agendex
With framework extras:
pip install agendex[langchain] # LangChain integration
pip install agendex[crewai] # CrewAI integration
pip install agendex[all] # All integrations
from agendex import AgendexClient, GovernedDBClient, GovernedS3Client, GovernedHTTPSession
from agendex.errors import DeniedError, PendingApprovalError
# 1. Create client (reads config from env vars)
client = AgendexClient()
# 2. Create governed resource clients
db = GovernedDBClient(client, task="monthly_report")
s3 = GovernedS3Client(client, task="monthly_report")
http = GovernedHTTPSession(client, task="monthly_report")
# 3. Use in your tools - governance happens automatically
def fetch_revenue(month: str) -> str:
try:
result = db.query("monthly_revenue", {"month": month})
return json.dumps(result.get("rows", []))
except DeniedError as e:
return f"[DENIED] {e.reason}"
except PendingApprovalError as e:
return f"[APPROVAL REQUIRED] ID: {e.approval_id}"
def initiate_payment(amount: float, vendor: str) -> str:
try:
result = http.post(
"https://payments.api/v1/pay",
json={"amount": amount, "vendor": vendor}
)
return json.dumps(result)
except DeniedError as e:
return f"[DENIED] {e.reason}" # e.g., "amount > 5000"
| Variable | Description | Default |
|---|---|---|
AGENDEX_URL | Proxy URL | http://localhost:8000 |
AGENDEX_AGENT_ID | Agent identifier | required |
AGENDEX_TOKEN | Bearer token | required |
+-----------------------------------------------------------------+
| Agent Process |
| |
| Tool: fetch_revenue("2025-01") |
| | |
| v |
| GovernedDBClient.query("monthly_revenue", {month: "2025-01"}) |
| | |
+---------+--------------------------------------------------------+
|
v
+-----------------------------------------------------------------+
| Agendex Proxy |
| |
| /evaluate: { |
| action: "db.query.run", |
| params: {query_id: "monthly_revenue"}, |
| task: "monthly_report" |
| } |
| | |
| v |
| Policy: Allow db.query.run IF query_id=monthly_revenue |
| AND task IN [monthly_report, demo] |
| | |
| v |
| /invoke -> DBQueryAdapter -> SQLite -> rows |
| |
+-----------------------------------------------------------------+
agents:
finance_bot:
allow:
# DB: Only specific queries, scoped by task
- action: "db.query.run"
resources:
- type: db_query
query_id: "monthly_revenue"
tasks: ["monthly_report", "demo"]
# S3: Only specific buckets/prefixes
- action: "s3.reports.fetch"
resources:
- type: s3
bucket: "reports-bucket"
key_prefix: "monthly/"
# HTTP: Parameter-aware decisions
- action: "http.service.call"
condition: "body.amount < 1000"
- action: "http.service.call"
condition: "1000 <= body.amount <= 5000"
require_approval: true
# CRM: Scoped to lookup only
- action: "crm.lookup"
tasks: ["support"]
deny:
- action: "http.service.call"
condition: "body.amount > 5000"
| Client | Action | What It Governs |
|---|---|---|
GovernedDBClient | db.query.run | Query ID, parameters |
GovernedS3Client | s3.reports.fetch | Bucket, key prefix |
GovernedHTTPSession | http.service.call | Domain, path, method, body |
GovernedCRMClient | crm.lookup, crm.update | Account ID, status changes |
GovernedTool | any custom action | Arbitrary params |
For actions that don't fit a built-in client, use GovernedTool:
from agendex import GovernedTool
# Wrap any action
slack = GovernedTool(client, action="slack.post", task="alerts")
slack.invoke(channel="#ops", message="System alert!")
# Or call it directly
email = GovernedTool(client, action="email.send", task="notifications")
email(to="admin@co.com", subject="Report ready")
Override default action names globally:
from agendex import configure_actions
configure_actions(
db_query="database.execute", # db.query -> database.execute
http_request="api.call", # http.request -> api.call
crm_lookup="salesforce.lookup", # crm.lookup -> salesforce.lookup
)
~31 lines to add Agendex to an existing agent:
MIT
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
requestsEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | requests>=2.28.0 | runtime |
langchainEnvironment{
"extras": "",
"marker": "extra == \"langchain\"",
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | langchain>=0.2.0; extra == "langchain" | runtime |
langchain-coreEnvironment{
"extras": "",
"marker": "extra == \"langchain\"",
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | langchain-core>=0.2.0; extra == "langchain" | runtime |
crewaiEnvironment{
"extras": "",
"marker": "extra == \"crewai\"",
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | crewai>=0.30.0; extra == "crewai" | runtime |
langchainEnvironment{
"extras": "",
"marker": "extra == \"all\"",
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | langchain>=0.2.0; extra == "all" | runtime |
langchain-coreEnvironment{
"extras": "",
"marker": "extra == \"all\"",
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | langchain-core>=0.2.0; extra == "all" | runtime |
crewaiEnvironment{
"extras": "",
"marker": "extra == \"all\"",
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | crewai>=0.30.0; extra == "all" | runtime |
pytestEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | pytest>=8.0.0; extra == "dev" | runtime |
pytest-asyncioEnvironment{
"extras": "",
"marker": "extra == \"dev\"",
"requires_python": ">=3.9",
"evaluation": "NOT_EVALUATED"
} | pytest-asyncio>=0.23.0; extra == "dev" | runtime |
bdist_wheel · 52.6 KB · Python py3
sdist · 54.92 KB · Python source
Observed since 20 Oct, 21:25 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:45f7e7697442277f2e2b7f4b7ff220c794fec8646d81839227f481406fe538c8