AI agent data access control — control what agents can see
Project description
aegis-trust
The trust layer for AI agents. One decorator declares the purpose; the SDK enforces what data the agent is allowed to see. Local-first AI agent data access control — no infrastructure, no telemetry.
pip install aegis-trust
You declare what each purpose is allowed to see. Everything else is filtered out before the agent gets it.
30-Second Quickstart
from aegis import shield
@shield(purpose="customer_support", scope=["name", "issue"])
def get_customer(id):
return {
"name": "Tanaka Taro",
"email": "tanaka@example.com", # hidden
"card": "4242-****-****-1234", # hidden
"issue": "Login problem",
}
get_customer(1)
# → {"name": "Tanaka Taro", "issue": "Login problem"}
The agent never sees email or card. No config files. No middleware. One line.
5-Minute Verification
pip install aegis-trust
python -c "from aegis import shield
f = shield(purpose='support', scope=['name'])(lambda: {'name': 'Aria', 'ssn': '123-45-6789'})
print(f())"
# → {'name': 'Aria'}
If you see {'name': 'Aria'} (no ssn), the install works and field-level filtering is active.
Why this exists
LLM-driven agents see whatever a tool returns. A "look up customer" tool that returns 30 fields hands all 30 to the model on every call. PII, payment data, internal notes — all of it ends up in the prompt window, the logs, and (often) the model provider's training pipeline.
@shield collapses the answer down to the fields the declared purpose actually needs, before the agent sees the result. The purpose is a contract: the function says what it is for, and the SDK enforces what it is allowed to return.
- Whitelist (
scope): the agent sees only the listed fields. - Blacklist (
deny_fields): the agent sees everything except the listed fields. - Fail-closed: on any error, return empty. The decorator never leaks unfiltered data, exceptions, or tracebacks.
Use Cases
Quickstart (lite mode, no infrastructure)
from aegis import shield
@shield(purpose="support", scope=["name", "issue"])
def get_customer(customer_id: str) -> dict:
return db.get_customer(customer_id)
FastAPI
@shield stacks with any framework decorator. Put @shield directly above the function (closest to it):
from fastapi import FastAPI
from aegis import shield
app = FastAPI()
@app.get("/customer/{customer_id}")
@shield(purpose="support", scope=["name", "issue"])
def get_customer(customer_id: str) -> dict:
return db.get_customer(customer_id)
The HTTP response now contains only name and issue, regardless of what db.get_customer returns.
FastMCP / MCP server tools
from fastmcp import FastMCP
from aegis import shield
mcp = FastMCP("customer-service")
@mcp.tool()
@shield(purpose="customer_support", scope=["name", "issue"])
def get_customer(customer_id: str) -> dict:
"""Look up a customer by ID."""
return db.get(customer_id)
Every MCP tool call now respects purpose-based access control.
aegis.yaml (centralized policies)
For multi-purpose deployments, define policies once in aegis.yaml:
# aegis.yaml
purposes:
support:
scope: ["name", "issue", "profile.age"]
billing:
deny_fields: ["card", "ssn", "profile.ssn"]
from aegis import shield
# scope/deny_fields pulled from aegis.yaml
@shield(purpose="support")
def get_customer(id: int) -> dict:
return db.get(id)
Requires the optional YAML extra:
pip install aegis-trust[yaml]
async functions
@shield works transparently with async def:
from aegis import shield
@shield(purpose="support", scope=["name", "issue"])
async def get_customer(customer_id: str) -> dict:
return await db.get(customer_id)
deny_fields (blacklist with dot-notation)
When the safe set is large and the unsafe set is small, blacklist is clearer:
from aegis import shield
@shield(purpose="billing", deny_fields=["ssn", "profile.ssn", "profile.internal_notes"])
def get_customer(id: int) -> dict:
return db.get(id)
scope and deny_fields are mutually exclusive. Specifying both raises ValueError.
API Summary
@shield(purpose, scope=None, *, deny_fields=None)
Decorator that controls data access based on declared purpose.
purpose(str): why the agent needs this data (e.g."customer_support")scope(list[str]): whitelist — fields the agent is allowed to seedeny_fields(list[str]): blacklist — fields to hide; everything else passes
Either scope or deny_fields is required (not both). Both accept dot-notation: ["profile.age"].
On any internal error, the decorated function returns an empty value rather than leaking unfiltered data, exceptions, or tracebacks.
Testing helpers
from aegis.pytest_plugin import assert_shield_blocked, assert_shield_passed
def test_support_agent_cannot_see_ssn(shield_history):
get_customer("id-1")
records = shield_history()
assert_shield_blocked(records, "ssn")
assert_shield_passed(records, "name")
The shield_history fixture is auto-registered via the pytest11 entry point.
Local history (optional)
Set AEGIS_HISTORY=1 to record every @shield call to a local SQLite store at ~/.aegis/history.db:
AEGIS_HISTORY=1 python my_app.py
aegis history # show recent calls
aegis stats # aggregate by purpose / blocked field
Migration from aegis-shield
If you were using the TestPyPI distribution aegis-shield (versions through 0.6.5.1), migrate to aegis-trust:
pip uninstall aegis-shield
pip install aegis-trust
The import path is unchanged (from aegis import shield). No source-code changes are required.
The package was renamed to aegis-trust because aegis-shield was already registered on PyPI by an unrelated party.
Security and cryptographic posture
aegis-trust is fail-closed by design. On any error inside @shield (filtering exception, scope mismatch, internal failure), the decorator returns an empty value rather than leaking unfiltered data, exceptions, or tracebacks.
Release evidence is anchored to the Bitcoin blockchain via OpenTimestamps (OTS) for tamper-evident chronology. As of v0.6.4, attestation hashes use SHA-3-512 (NIST FIPS 202) as a pre-PQC bridging measure. OTS is not a post-quantum cryptography substitute; full PQC migration is on the roadmap.
Vulnerability reports: contact@aegisagentcontrol.com. See SECURITY.md for the full policy.
Beyond local filtering
aegis-trust is the open-source entry point to a broader trust platform. For production deployments with enterprise controls and platform-managed policy orchestration, contact contact@aegisagentcontrol.com.
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
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 aegis_trust-0.6.5.5.tar.gz.
File metadata
- Download URL: aegis_trust-0.6.5.5.tar.gz
- Upload date:
- Size: 48.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
724c14c81835562a41dde05d22225d9872117e566e2151484a3e6679479ac832
|
|
| MD5 |
b66722b1f73a12034d3c2a776d92e20a
|
|
| BLAKE2b-256 |
0d59a9ec064759d30fe09a01a76d4a4cb8bc84a497a82fe567ecc394a986a947
|
File details
Details for the file aegis_trust-0.6.5.5-py3-none-any.whl.
File metadata
- Download URL: aegis_trust-0.6.5.5-py3-none-any.whl
- Upload date:
- Size: 96.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
712ae6ff0969cbab82de32262271d14706ad6df8a1854607f6a5206d446467cf
|
|
| MD5 |
17d80f5ddc4c2574b2e27218366c81b8
|
|
| BLAKE2b-256 |
f86ee07f0d3dcedbb3554b91ae4073f581a6106e46bb42734f57d5bee6f1f793
|