Machine-Readable Permissions for AI Agents: OpenTerms SDK Now Available
Autonomous agents need a way to know what they're allowed to do before they do it.
Today we're releasing three Python packages that let AI agents and automated tools read machine-readable permission signals from websites before taking action. All three enforce a fail-closed security model: explicit allow required, ambiguous states block by default.
The Problem
When you deploy an agent into production, it might:
- Scrape a website for data
- Post content to a platform
- Call an API programmatically
- Create accounts or complete transactions
The agent doesn't know if it's allowed. It just tries.
This happens because websites do not expose machine-readable permission signals. Terms of service are written for human readers, not machines. There is no standard way for a site to declare what tools can do. Agents have no mechanism to ask permission before acting.
The Solution: Machine-Readable Permissions
We've published the OpenTerms Protocol, a standard for websites to declare their permission rules in a machine-readable JSON file (openterms.json). The three packages we're releasing today are the agent-side SDKs that read these files and enforce deterministic permission gates before your agent acts.
What You Can Do Now
Check Permissions Before Acting
Plain Python example — permission gate before an HTTP call:
import openterms
import requests
def fetch_if_permitted(domain: str, url: str) -> dict | None:
result = openterms.check(domain, "api_access")
if not result: # False when decision is "deny" or "not_specified"
print(f"Blocked: api_access is '{result.decision}' for {domain}")
return None
return requests.get(url, timeout=10).json()
The Fail-Closed Default
All three SDKs block by default on ambiguous results:
| Result | Meaning | Default Behavior |
|---|---|---|
allow | Explicitly permitted | Proceed |
deny | Explicitly forbidden | Block |
not_specified | Key absent, null, or unclear | Block (fail-closed) |
noopentermsjson | Site hasn't published permissions | Block (fail-closed) |
The fail-closed model keeps your agent predictable: if you don't know you're allowed, you don't proceed. No surprises. No silent violations.
If you explicitly want to proceed in the absence of permission rules, you can opt-in:
result = openterms.check(domain, "api_access", fail_closed=False)
# now proceeds even when permission is not_specified or no_openterms_json
But that choice is explicit. It's not a silent default.
Guarded Tool Execution
The CrewAI and LangChain wrappers both provide a guarded-wrapper pattern: a drop-in class that wraps any downstream tool and runs the OpenTerms check as a gate before the tool executes. The wrapped tool never runs unless the check returns allow.
This is minimal integration overhead — wrap your existing tool, get deterministic gating.
CrewAI example:
from crewai_openterms import OpenTermsGuardedTool
fetch_page = SomeFetchTool()
# Wrapped tool: executes only when OpenTerms returns allow
guarded_fetch = OpenTermsGuardedTool(
wrapped_tool=fetch_page,
action="read_content",
fail_closed=True, # default — block on not_specified / no_openterms_json
)
result = guarded_fetch._run(url="https://example.com/page")
LangChain example:
from langchain_openterms import OpenTermsGuard
# Replace search with any LangChain tool
guarded_search = OpenTermsGuard(
tool=search,
action="read_content",
fail_closed=True, # default
)
result = guarded_search.invoke("https://example.com/pricing")
The guarded wrapper is a drop-in. Your existing tool doesn't change. The permission check gates execution before the tool is called.
The Seven Canonical Permission Keys
All packages check against the same standardized keys:
read_content— Reading or displaying publicly accessible contentscrape_data— Automated bulk scraping or crawlingapi_access— Programmatic API accesscreate_account— Creating user accounts programmaticallymake_purchases— Completing automated purchases or transactionspost_content— Publishing or submitting contentallow_training— Using site content to train ML models
Installation
openterms-py (Plain Python)
For plain Python without a framework dependency:
pip install openterms-py
# Optional async support:
pip install "openterms-py[async]"
crewai-openterms (CrewAI Integration)
For CrewAI agents. Includes OpenTermsCheckTool, OpenTermsGuardTool, and OpenTermsGuardedTool:
pip install crewai-openterms
# With improved accuracy (includes openterms-py SDK):
pip install "crewai-openterms[sdk]"
langchain-openterms (LangChain Integration)
For LangChain agents. Includes OpenTermsGuard, OpenTermsChecker, and OpenTermsCallbackHandler:
pip install langchain-openterms
# With improved accuracy (requires openterms-py>=0.3.1):
pip install "langchain-openterms[sdk]"
Examples & Documentation
Live SDK documentation: openterms.com/sdk — complete API reference, code examples for all three packages, and integration patterns.
Examples repository: github.com/jstibal/openterms-examples — complete working examples with pytest test coverage. Start here if you're building a new agent.
OpenTerms protocol docs: openterms.com/docs
Why This Matters
Predictable Agent Behavior
When your agent enforces machine-readable permission signals, it:
- Gates tool execution deterministically — allow signals proceed, everything else blocks
- Escalates gracefully when a signal is absent or ambiguous
- Behaves consistently across environments — the same permission gate in dev, staging, and production
Minimal Integration Overhead
The guarded-wrapper pattern means you don't restructure your agent. Wrap the tool, pass the action key, set fail_closed. Done. The permission check is invisible to the rest of your pipeline.
Explicit Allow Semantics
Fail-closed defaults mean no implicit permissions. Your agent cannot accidentally act without an explicit allow signal — it must opt-in to permissive behavior, and that opt-in is visible in the code.
What Happens During Public Alpha
Most sites don't publish an openterms.json yet. When your agent encounters a site without one, the SDK returns noopentermsjson and blocks by default.
This is not an error — it's expected alpha behavior. You have three options:
- Block and escalate (default) — Flag the action for review
- Use explicit opt-in — Set
fail_closed=Falsewhen you've verified the site permits the action - Wait for adoption — As more sites publish
openterms.json, the SDK works out of the box
What's Next
Additional framework integrations are planned. If you're building with a Python agent framework and want to suggest an integration, open an issue on GitHub.
Get Started
- Install the right package for your framework
- Read the SDK documentation
- Check out working examples
- Gate your agent's tools with permission checks
- Deploy with confidence
The full protocol specification is at openterms.com/docs.