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:

ResultMeaningDefault Behavior
allowExplicitly permittedProceed
denyExplicitly forbiddenBlock
not_specifiedKey absent, null, or unclearBlock (fail-closed)
noopentermsjsonSite hasn't published permissionsBlock (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 content
  • scrape_data — Automated bulk scraping or crawling
  • api_access — Programmatic API access
  • create_account — Creating user accounts programmatically
  • make_purchases — Completing automated purchases or transactions
  • post_content — Publishing or submitting content
  • allow_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]"

PyPI · GitHub

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]"

PyPI · GitHub

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]"

PyPI · GitHub

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:

  1. Block and escalate (default) — Flag the action for review
  2. Use explicit opt-in — Set fail_closed=False when you've verified the site permits the action
  3. 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

  1. Install the right package for your framework
  2. Read the SDK documentation
  3. Check out working examples
  4. Gate your agent's tools with permission checks
  5. Deploy with confidence

The full protocol specification is at openterms.com/docs.