safe-agent-l
safe-agent-l is a Python runtime enforcement library for autonomous AI agent systems. It sits between your agent's decision-making — an LLM, a reinforcement-learning policy, a rules engine — and the actions that reach production, and applies four independent controls at the point of action:
- Constraint enforcement — machine-readable policy rules (price floors, allowlisted tools, quantity ceilings) reject or clip impermissible actions before they execute, instead of trusting the agent to follow the rules.
- Auditable decision traces — every decision, allowed or denied, is recorded as a complete, reconstructable trace; incomplete audit records are rejected at log time, not discovered during an investigation.
- Defense-in-depth safety controls — independent safety layers (anomaly detection, custom checks) all evaluate every action, and a circuit breaker halts the agent after repeated failures.
- Fail-closed resilience — guardrail checks that time out default to deny, and last-known-good policy stays enforced through network degradation and partitions, resynchronizing on recovery.
The library is pure Python with zero runtime dependencies, is fully
typed (py.typed), and wraps any agent that can express an action as a
dictionary — it is not itself an LLM agent and does not call any model API.
What problem does this solve?
Agents that set prices, issue refunds, call tools, or drive workflows act faster than human review cycles. Prompt-level instructions ("never price below $19.99") are suggestions, not controls: the model can ignore them, and you cannot prove to an auditor that it didn't. safe-agent-l moves those rules out of the prompt and into an enforcement layer the agent's output must pass through, with an audit trail for every outcome.
Who it's for: teams deploying autonomous or semi-autonomous agents that take consequential actions, and platform/safety engineers who need guardrails and decision evidence that survive an incident review.
How it works
input state ──► propose_fn (your agent) ──► TimeoutToSafeDefault (timeout → deny)
│
▼
ConstraintEngine (violation → deny or clip)
│
▼
SafetyStack (any layer fails → deny;
│ repeated failures trip breaker)
▼
allowed action
every outcome (allowed or denied) ────────► DecisionLogger (complete, reconstructable trace)
SafeAgent.decide() runs this pipeline for one action. Each pillar is also
usable standalone — you can adopt just the ConstraintEngine in front of an
existing agent, or just the DecisionLogger for audit trails.
What this does not guarantee
Be clear-eyed about what a library can and cannot do:
- It does not guarantee legal or regulatory compliance. It enforces the constraints you configure and produces evidence they were applied. Whether those constraints are legally correct and complete is your responsibility, with your legal and compliance teams.
- It is not a complete safety system. It is one enforcement layer. Deployment controls, monitoring, human escalation paths, and incident response still belong to you.
- Enforcement is in-process. Code that calls your tools or APIs directly,
without going through
SafeAgent.decide(), bypasses every control here. Place enforcement at a boundary the agent cannot route around (see docs/security.md). - The anomaly detector is a statistical baseline, not a substitute for domain-specific safety checks.
- This is not legal advice and carries no certification against any standard or regulation.
Installation
pip install safe-agent-l
Or from source:
pip install git+https://github.com/VasanthRajendran/safe-agent-l.git
Or for development:
git clone https://github.com/VasanthRajendran/safe-agent-l.git
cd safe-agent-l
pip install -e ".[dev]"
Requires Python 3.9+. No runtime dependencies.
Quickstart
from safeagentl import Constraint, ConstraintEngine, DecisionLogger, SafeAgent, SafetyStack
# Constraint enforcement: prices below the contractual floor cannot execute.
constraints = ConstraintEngine([
Constraint(field="price", op="gte", bound=19.99, reason="contractual MAP floor"),
])
# Auditability: every decision is logged with a reconstructable trace.
logger = DecisionLogger()
# Defense in depth: independent safety layers must all pass.
safety = SafetyStack(layers=[lambda action: action["price"] > 0])
agent = SafeAgent(
agent_id="pricing-agent-1",
constraint_engine=constraints,
logger=logger,
safety_stack=safety,
)
decision = agent.decide(
{"sku": "ABC123"},
propose_fn=lambda state: {"price": 9.99}, # below the floor
)
print(decision.allowed) # False
print(decision.reason) # "constraint_violation"
print(decision.trace.reasoning) # full audit trail for this decision
Integrating with an existing agent
Your agent stays whatever it already is; safe-agent-l only needs a
propose_fn that maps input state to a proposed action dictionary:
def propose_fn(state: dict) -> dict:
# call your LLM / policy / planner here
tool_call = my_llm_agent.plan(state)
return {"tool": tool_call.name, **tool_call.arguments}
decision = agent.decide(state, propose_fn=propose_fn)
if decision.allowed:
execute_tool(decision.action) # only ever execute the governed action
else:
escalate_to_human(decision) # trace explains exactly why it was denied
The key integration rule: execute decision.action, never the raw
proposal. See docs/integrations.md for
tool-calling gates, workflow guardrails, and audit-log export, and
examples/ for runnable end-to-end scripts:
examples/pricing_agent.py— pricing agent with all four pillars, including timeout and partition handlingexamples/tool_approval_gate.py— approval gate for a tool-calling agent, with audit-log exportexamples/generic_agent_guard.py— generic tool-calling agent example with allowed and denied operations
API overview
| Concern | Module | Key classes |
|---|---|---|
| Constraint enforcement | safeagentl.constraints |
Constraint, ConstraintEngine |
| Auditable decision traces | safeagentl.explainability |
DecisionTrace, DecisionLogger |
| Defense-in-depth safety | safeagentl.safety |
AnomalyDetector, CircuitBreaker, SafetyStack |
| Fail-closed resilience | safeagentl.network |
PriorityRouter, TimeoutToSafeDefault, PartitionTolerantCache |
| Orchestration | safeagentl.agent |
SafeAgent, Decision, ConformanceLevel |
Full reference: docs/api.md. Concepts and design rationale: docs/concepts.md.
API stability
Pre-1.0: minor versions (0.x) may contain breaking changes, always listed in
CHANGELOG.md. The public API is exactly the set of names
exported from the top-level safeagentl package; anything imported from
submodules with a leading underscore is internal. From 1.0 onward the
project will follow semantic versioning.
Development
pip install -e ".[dev]"
pytest # test suite
pytest --cov=safeagentl # with coverage
ruff check . # lint
mypy # type check
Reporting security issues
Please do not open public issues for vulnerabilities — including bugs that allow constraint, safety-layer, or audit-log bypass, which we treat as security-relevant. See SECURITY.md for private reporting instructions.
Relationship to the SAFE-AGENT-L standardization effort
The SAFE-AGENT-L governance framework was presented to the IEEE Future Networks AI/ML Working Group in February 2026 and is in PAR (Project Authorization Request) review within IEEE ComSoc COM/NetSoft SC toward a proposed IEEE Recommended Practice. This library is an independent, permissively licensed implementation of the framework's four pillars. It is not part of the IEEE standardization process and makes no claim of conformance to a not-yet-published standard.
Project
- CONTRIBUTING.md — how to contribute
- CHANGELOG.md — release history
- ROADMAP.md — where the project is going
- SECURITY.md — vulnerability reporting
- MAINTAINERS.md — governance and support expectations
- CODE_OF_CONDUCT.md
- docs/ — concepts, API reference, integration guides
Citation
If you use this software in academic work, please cite it — see
CITATION.cff and the software paper in
paper/paper.md.
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file safe_agent_l-0.2.0.tar.gz.
File metadata
- Download URL: safe_agent_l-0.2.0.tar.gz
- Upload date:
- Size: 19.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8282164933e5d8a277670e80656798cc859efa96bd786d1e4521b643e7406000
|
|
| MD5 |
25b831d09863f600307bb4c887602434
|
|
| BLAKE2b-256 |
51e99a07fec9f2f019865cff81db750a2cc8d4f9d7f57f4747e92a5c55570679
|
Provenance
The following attestation bundles were made for safe_agent_l-0.2.0.tar.gz:
Publisher:
publish.yml on VasanthRajendran/safe-agent-l
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_agent_l-0.2.0.tar.gz -
Subject digest:
8282164933e5d8a277670e80656798cc859efa96bd786d1e4521b643e7406000 - Sigstore transparency entry: 2495032816
- Sigstore integration time:
-
Permalink:
VasanthRajendran/safe-agent-l@04d736d36bbcdaeb0754206f48a642102066e8f4 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VasanthRajendran
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@04d736d36bbcdaeb0754206f48a642102066e8f4 -
Trigger Event:
release
-
Statement type:
File details
Details for the file safe_agent_l-0.2.0-py3-none-any.whl.
File metadata
- Download URL: safe_agent_l-0.2.0-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5afb9ea3994d03f930460fee8b79912a745eebf6a17f209ec87d35f4efd029c
|
|
| MD5 |
1843fdeda06290210e4c91a1e3855822
|
|
| BLAKE2b-256 |
f46c7bbff32e740ccfe074097f5f438ada15958e4ac89b72664dd8c9c04890ba
|
Provenance
The following attestation bundles were made for safe_agent_l-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on VasanthRajendran/safe-agent-l
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
safe_agent_l-0.2.0-py3-none-any.whl -
Subject digest:
d5afb9ea3994d03f930460fee8b79912a745eebf6a17f209ec87d35f4efd029c - Sigstore transparency entry: 2495032831
- Sigstore integration time:
-
Permalink:
VasanthRajendran/safe-agent-l@04d736d36bbcdaeb0754206f48a642102066e8f4 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/VasanthRajendran
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@04d736d36bbcdaeb0754206f48a642102066e8f4 -
Trigger Event:
release
-
Statement type: