openterms-py
Python SDK for the OpenTerms Protocol.
Two halves of the same agent-governance story, in one library:
- Permissions — before an agent acts, query
openterms.jsonto see what the site owner permits. - Receipts — after an agent acts, sign and emit an ORS v0.1 receipt so the action is auditable and verifiable later.
pip install openterms-py
Runtime dependencies: cryptography>=42, requests>=2.28. Python >=3.10.
Quickstart
Before you act: check permissions
import openterms
result = openterms.check("example.com", "scrape_data")
if result:
print("allowed")
else:
print(f"blocked: {result.decision}")
After you act: emit a signed receipt
from openterms import IngestClient, generate_keypair
sk, pk = generate_keypair()
private_seed = sk.private_bytes_raw()
client = IngestClient(
base_url="http://localhost:3000",
workspace_id="00000000-0000-4000-8000-0000000000aa",
key_id="my-key",
private_key=private_seed,
agent_id="my-agent",
)
response = client.emit_receipt(
action_type="tool_call",
action_context={"tool_id": "web.fetch", "url": "https://example.com"},
)
print(response.receipt_id, response.canonical_hash)
End-to-end loop: check, act, sign
import openterms
from openterms import IngestClient
result = openterms.check("example.com", "scrape_data")
if not result:
raise SystemExit(f"blocked: {result.decision}")
# ... agent does the work ...
client = IngestClient(...)
client.emit_receipt(
action_type="scrape_data",
action_context={
"domain": "example.com",
"openterms_hash": result.raw_value and "...",
},
)
Permissions API
Top-level convenience functions:
| Function | Purpose |
|---|---|
openterms.fetch(domain) |
Fetch and parse the domain's openterms.json |
openterms.check(domain, action) |
Decide allow/deny/not_specified |
openterms.discover(domain) |
Read the discovery block (MCP servers, API specs) |
openterms.permission_receipt(domain, action, decision) |
Local audit artifact (unsigned) |
openterms.configure(...) |
Tune TTL, timeout, user agent, registry URL |
openterms.clear_cache(domain=None) |
Evict cached entries |
Lookup order: https://{domain}/.well-known/openterms.json, then
https://{domain}/openterms.json, then the configured registry URL.
Lower-level: openterms.OpenTermsClient, openterms.TermsCache,
openterms.CheckResult, openterms.DiscoveryResult, openterms.PermissionReceipt.
Receipts API (ORS v0.1)
Top-level:
| Symbol | Purpose |
|---|---|
sign_receipt(payload, private_key, key_id) |
Ed25519-sign a canonical ORS payload |
verify_receipt(receipt, jwks) |
Verify; returns a VerifyResult (no raise) |
canonicalize(payload) / canonical_hash(payload) |
RFC 8785-ish JSON canonicalization |
build_payload(receipt) |
Strip signature/key fields, return signable payload |
generate_keypair() |
Ed25519 keypair |
public_key_to_jwk(pk, kid) / build_jwks(keys) |
JWKS helpers |
IngestClient |
Build, sign, POST receipts to an ingest service |
Policy engine
from openterms import evaluate, Policy, Rule
policy = Policy(rules=[Rule(rule_id="r1", type="max_amount", params={"amount_cents": 5000})])
decision = evaluate(policy, receipt={...})
Framework adapters
| Package | Install |
|---|---|
| LangChain callback | pip install langchain-openterms |
| CrewAI tool wrapper | pip install crewai-openterms |
Both depend on openterms-py>=1.0.0 and surface the same IngestClient.
Migrating from 0.4.x
See CHANGELOG.md for the full migration table. The short version:
Receipt→PermissionReceiptopenterms.receipt(...)→openterms.permission_receipt(...)openterms.check(..., receipt=True)removed — useIngestClient.emit_receiptopenterms.receipts.sign_receipt/verify_receiptnow usecryptography(not PyNaCl) and have different signatures- License changed: MIT → Apache-2.0
License
Apache-2.0 — see LICENSE.
Release files for openterms-py 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| openterms_py-1.0.1.tar.gz | 50.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openterms_py-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 85.9 kB
Release files / openterms_py-1.0.1.tar.gz
| Download URL | openterms_py-1.0.1.tar.gz |
|---|---|
| Size | 50.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
23366bf723b825bec2cac2cc873e5eb44a682e0bc0d87ecd7eff30a4ce8b9811
|
|
BLAKE2b-256 checksum How to use checksums |
e93ca089c16292dd5747f6ca5f1cf24ee27d6f8af8cb5d8e13e21d010b9ba973
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / openterms_py-1.0.1-py3-none-any.whl
| Download URL | openterms_py-1.0.1-py3-none-any.whl |
|---|---|
| Size | 36.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cb82afb8a90cbdc8ceb330e030d0c54a3e144991caeb1cd95e66e53251572f0d
|
|
BLAKE2b-256 checksum How to use checksums |
940cf2527a60b1841cd57d74684f48be3821a4a4b602629f858a780ad28f09f6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|