Skip to main content

safety-protocol

CI PyPI Python License: MIT

Enforceable governance for LLM agents. Instead of hoping the model behaves, every action passes through infrastructure that enforces binding, closed vocabulary, least-privilege scope, spend caps, approval gates, a hash-chained audit trail, and a kill switch. Deny-by-default: an action is permitted only if a rule explicitly allows it.

The agent proposes; the protocol decides. The agent cannot talk its way around it, because the check is not a prompt instruction.

Install

pip install safety-protocol

Zero runtime dependencies — the guard, scope linter, audit trail and reference deployment are stdlib. Optional integrations are extras:

Extra Adds
onchain requests — verify a settled payment against a JSON-RPC node
crypto eth-account — real EIP-3009 / USDC settlement signing
demo openai — the repo-root Nebius/Nemotron demo agent
pip install "safety-protocol[onchain,crypto]"

Quickstart (library)

from safety_protocol import SafetyProtocol, BoundAgent, ScopeRule

protocol = SafetyProtocol(
    agent_id="agent-001",
    user_id="alice",
    scope_rules=[
        ScopeRule(
            action_type="api_call",
            allowed_targets=["https://api.example.com/v1/search"],
            match="exact",
            methods=["POST"],
            param_schema={
                "required": ["query"],
                "properties": {"query": {"type": "string", "maximum": 200}},
                "additional_properties": False,
            },
            forbidden_targets=["admin", "billing"],
            max_cost=1.00,
        ),
    ],
    budget_limit=50.0,
    approval_threshold_cost=10.0,
    allowed_action_types=["api_call"],
)

agent = BoundAgent(agent_id="agent-001", user_id="alice", safety_protocol=protocol)

result = agent.propose_action(
    action_type="api_call",
    target="https://api.example.com/v1/search",
    params={"query": "test"},
    estimated_cost=2.50,
)
print(result.outcome)  # ActionOutcome.ALLOWED

The guard (CLI + HTTP)

Give the guard a user-controlled config; it lints the rules before going live and fails closed — a config that is too broad refuses to start. The agent only ever sends intents; it can never widen its own scope.

safety-guard init  --out guard_config.json          # write a default config
safety-guard lint  --config guard_config.json       # exit 1 if too broad
safety-guard check --config guard_config.json \
    --action api_call --target https://api.research.example/v1/search \
    --method POST --params '{"query":"hi"}'
safety-guard pay   --config guard_config.json \
    --recipient 0xMerchant1111111111111111111111111111111 --usd 0.10
safety-guard serve --config guard_config.json       # HTTP on 127.0.0.1:8080

The HTTP surface (any agent, any language):

Method Path Body
POST /guard {action_type, target, method?, params?, cost?}
POST /pay {recipient, usd, resource?}
POST /approve {token, approved, approver}
POST /killswitch {reason}
GET /audit — (immutable decision log)
GET /health — (status + lint summary)

Equivalent module entry point: python -m safety_protocol.guard_service --config guard_config.json.

Config reference

{
  "agent_id": "guard-agent",
  "user_id": "alice",
  "budget_limit": 20.0,              // global session cap (null = none)
  "approval_threshold_cost": 2.0,    // actions >= this need human sign-off
  "allowed_action_types": ["api_call", "payment"],   // closed verb vocabulary
  "scope_rules": [
    {
      "action_type": "api_call",
      "allowed_targets": ["https://api.research.example/v1/search"], // allowlist
      "match": "exact",              // exact | prefix | glob | regex
      "methods": ["POST"],           // transport verbs permitted
      "param_schema": {              // params MUST satisfy this
        "required": ["query"],
        "properties": {"query": {"type": "string", "maximum": 200}},
        "additional_properties": false
      },
      "forbidden_targets": ["admin", "billing"],
      "forbid_match": "token",       // token | substring
      "max_cost": 1.00,              // per-rule cap (tightest wins)
      "requires_approval": false
    }
  ]
}

Every dimension is enforced. Leaving any of them broad (a wildcard prefix, an unbound method, an unvalidated param) is what makes the other controls decorative — the safety-guard lint command exists to catch exactly that before deploy.

Architecture

Layer What it is Status
1. Enforcement binding, scope, budget, approval, monitor, audit, killswitch production-usable
2. On-chain anchors SBT-style binding + on-chain audit of key events simulated (in-memory, same interface as a real chain)
3. Insurance claims evidence, underwriter reports interface / reference

The on-chain layer is simulated. It is not third-party verifiable until a real contract is deployed. The library discloses this in every binding proof (on_chain_backend: "simulated_in_memory"). Use ERC-5192 SBT or ERC-8004 on a real chain in production.

ReferenceDeployment wires all three layers together; the layers are composable and each adds value on its own.

Development

pip install -e ".[dev]"
python -m pytest
ruff check

The repo-root files (sovereign_agent.py, agent_capabilities.py) are a standalone demo agent and are not part of the package:

pip install -e ".[demo]"
python sovereign_agent.py --offline     # no API key needed; same gate logic
python sovereign_agent.py               # live via NEBIUS_API_KEY

Origin

Originally built for the Nebius x NVIDIA Global AI Hackathon (Track: Personal AI), then hardened into a general enforcement library.

License

MIT. See LICENSE.

Metadata

Release files for safety-protocol 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for safety-protocol 0.3.0
File Size Uploaded
safety_protocol-0.3.0.tar.gz 83.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for safety-protocol 0.3.0
File Interpreter ABI Platform
safety_protocol-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 135.5 kB

Release files / safety_protocol-0.3.0.tar.gz

Download URL safety_protocol-0.3.0.tar.gz
Size 83.1 kB
Tags Source
SHA-256 checksum
How to use checksums
b609c08ebb64625a38d46b6f70d688ab647ad3fe8f677c23ce60ebde1196f226
BLAKE2b-256 checksum
How to use checksums
7ecedac26420a833da6e50cef47a958186039703140922e151ee22e9ae936b32
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / safety_protocol-0.3.0-py3-none-any.whl

Download URL safety_protocol-0.3.0-py3-none-any.whl
Size 52.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
096b204add3469cc120dcec12de2833f6aa7b423dbd6a341c145a3c227da784b
BLAKE2b-256 checksum
How to use checksums
70a5036bf0d6e2ddda3abb7768e194422deef8cc858e2388be2b8fd04a6e2d32
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

0.4.0

2 release files

This release

0.3.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page