Metadata-Version: 2.5
Name: axiomatics-ai-sdk
Version: 0.1.0
Summary: Externalized ABAC for AI applications: enforce PDP policies (XACML 3.0 JSON or OpenID AuthZEN) across agents, tools, MCP servers, A2A agents, and RAG
Project-URL: Homepage, https://github.com/axiomatics/axiomatics-ai-sdk-python
Project-URL: Repository, https://github.com/axiomatics/axiomatics-ai-sdk-python
Project-URL: Documentation, https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/README.md
Project-URL: Changelog, https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/CHANGELOG.md
Author: Axiomatics
License: Apache-2.0
License-File: LICENSE
Keywords: a2a,abac,ads,agents,attribute-based access control,authorization,authzen,langchain,mcp,pbac,pdp,pep,policy decision point,policy enforcement point,policy-based access control,xacml
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security
Requires-Python: >=3.11
Requires-Dist: cachetools>=5.0.0
Requires-Dist: httpx>=0.28.1
Requires-Dist: pydantic>=2.12.5
Provides-Extra: a2a
Requires-Dist: pyjwt[crypto]>=2.15.1; extra == 'a2a'
Provides-Extra: all
Requires-Dist: claude-agent-sdk>=0.2.0; extra == 'all'
Requires-Dist: deepagents<0.8,>=0.5; extra == 'all'
Requires-Dist: fastmcp<4,>=3.2.4; extra == 'all'
Requires-Dist: langchain-community; extra == 'all'
Requires-Dist: langchain-mcp-adapters; extra == 'all'
Requires-Dist: langchain>=1.2.15; extra == 'all'
Requires-Dist: litellm>=1.103.0; extra == 'all'
Requires-Dist: pyjwt[crypto]>=2.15.1; extra == 'all'
Requires-Dist: starlette>=0.37.0; extra == 'all'
Requires-Dist: strands-agents>=1.43.0; extra == 'all'
Provides-Extra: claude-agent-sdk
Requires-Dist: claude-agent-sdk>=0.2.0; extra == 'claude-agent-sdk'
Provides-Extra: deepagents
Requires-Dist: deepagents<0.8,>=0.5; extra == 'deepagents'
Requires-Dist: langchain>=1.2.15; extra == 'deepagents'
Provides-Extra: fastmcp
Requires-Dist: fastmcp<4,>=3.2.4; extra == 'fastmcp'
Requires-Dist: pyjwt[crypto]>=2.15.1; extra == 'fastmcp'
Provides-Extra: gateway
Requires-Dist: fastmcp<4,>=3.2.4; extra == 'gateway'
Requires-Dist: pyjwt[crypto]>=2.15.1; extra == 'gateway'
Requires-Dist: starlette>=0.37.0; extra == 'gateway'
Provides-Extra: jwt
Requires-Dist: pyjwt[crypto]>=2.15.1; extra == 'jwt'
Provides-Extra: langchain-agents
Requires-Dist: langchain>=1.2.15; extra == 'langchain-agents'
Provides-Extra: langchain-mcp
Requires-Dist: langchain-mcp-adapters; extra == 'langchain-mcp'
Requires-Dist: langchain>=1.2.15; extra == 'langchain-mcp'
Provides-Extra: llm-enrichment
Requires-Dist: litellm>=1.103.0; extra == 'llm-enrichment'
Provides-Extra: rag
Requires-Dist: langchain-community; extra == 'rag'
Requires-Dist: langchain>=1.2.15; extra == 'rag'
Provides-Extra: strands
Requires-Dist: strands-agents>=1.43.0; extra == 'strands'
Provides-Extra: tool-decorator
Requires-Dist: fastmcp<4,>=3.2.4; extra == 'tool-decorator'
Requires-Dist: pyjwt[crypto]>=2.15.1; extra == 'tool-decorator'
Description-Content-Type: text/markdown

# axiomatics-ai-sdk-python

**Externalized attribute-based access control (ABAC) for AI applications.**

Agents decide what to do; this SDK decides what they are *allowed* to do, by asking a Policy
Decision Point (PDP) at every point where an agent turn touches something that matters: the
prompt, the tool list, each tool call, each tool result, the final answer, agent-to-agent
messages, and document retrieval. Policies live in the PDP, written once in a standard policy
language, and apply the same way across LangChain, Google ADK, Strands, OpenAI Agents, the
Claude Agent SDK, MCP servers, A2A agents, and your own code. No authorization logic in the
application.

The SDK speaks **XACML 3.0 JSON** and **OpenID AuthZEN**, so it works with any PDP that
implements either. It is developed and tested against [Axiomatics ADS](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/running-ads.md).

## Where it fits

Every block below talks to the PDP through the SDK, which plays the Policy Enforcement Point
(PEP): it builds the authorization request from the caller's identity and the thing being
attempted, asks the PDP, and applies the answer.

![The SDK acts as the PEP for AI applications, gateways, and resources to reach a PDP](https://raw.githubusercontent.com/axiomatics/axiomatics-ai-sdk-python/main/assets/how-it-fits.png)

## When it intercepts

Along one agent turn the SDK can intercept at seven points. Each is a *transformation* of what
flows through it; a Deny is the simplest case (block, hide, or filter).

![The seven moments in an agent's workflow when the SDK can enforce access control](https://raw.githubusercontent.com/axiomatics/axiomatics-ai-sdk-python/main/assets/interception-points.png)


| # | Point | Fires | On Deny | Decided by |
|---|---|---|---|---|
| ① | Input guard (`BEFORE_MODEL`) | before the model sees the prompt | prompt blocked, refusal returned | policy over LLM-classified attributes |
| ② | Tool visibility (`TOOL_VISIBILITY`) | before the model sees the tool list | tool hidden; the model never knows it exists | policy |
| ③ | Tool invocation (`BEFORE_TOOL`) | before a tool call runs | call blocked; arguments are part of the decision; or paused for a [human's approval](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/human-approval.md) | policy, optionally against the user's [classified intent](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/intent-based-access.md) |
| ④ | Tool-output filter (`AFTER_TOOL`) | after a tool returns | denied records dropped, or fields masked | policy, per record |
| ⑤ | Output guard (`AFTER_MODEL`) | before the answer reaches the user | answer blocked, refusal returned | policy over LLM-classified attributes |
| ⑥ | A2A invocation (`A2A_INVOCATION`) | on an agent-to-agent message | message blocked | policy |
| ⑦ | Retrieval filter (`retrieval`) | on a vector-store search | only permitted documents returned; the filter is pushed into the store | policy, as a condition |

## Quick start

```bash
pip install "axiomatics-ai-sdk[langchain-agents]" langchain-litellm   # or: uv add ...
```

`langchain-litellm` is only the model this example uses; bring any LangChain chat model.

Wrap a LangChain agent. The context dict is the user's identity; the PDP decides which tools
alice sees, which calls run, and which records come back.

```python
from langchain.tools import tool
from langchain_litellm import ChatLiteLLM
from axiomatics_ai import AuthZConfig, PDPConnection, create_authorized_agent, standard_tool_enforcement

@tool
def search_docs(query: str) -> str:
    """Search internal documentation."""
    return "..."

config = AuthZConfig(
    connection=PDPConnection(base_url="http://localhost:8080"),
    enforcement=standard_tool_enforcement(),   # tool visibility + invocation + output filter
)

agent = create_authorized_agent(
    model=ChatLiteLLM(model="openai/gpt-5.6-luna"),
    tools=[search_docs],
    config=config,
)

agent.invoke({"messages": [{"role": "user", "content": "Find docs on deployment"}]},
             context={"username": "alice"})
```

No framework? Ask the PDP directly and enforce yourself (same `config`):

```python
from axiomatics_ai import Authorizer

authz = Authorizer(config)
if not authz.is_permitted(action="read_document", resource="doc-42", context={"username": "alice"}):
    raise PermissionError
```

Every other framework has a one-call equivalent; see [Integrations](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/README.md#integrations).
Full walkthrough, including running a PDP and writing the first policy:
[Getting started](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/getting-started.md).

## What it covers

Not every framework exposes a hook at every point. ✅ supported · — not expressible there.

| Integration | Input guard | Tool visibility | Tool invocation | Output filter | Output guard | Retrieval | A2A | Side |
|---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|---|
| [langchain_agents](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/langchain_agents.md) | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | client |
| [google_adk](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/google_adk.md) | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | client |
| [strands](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/strands.md) | ✅ | ✅ | ✅ | ✅ | ✅ | — | — | client |
| [openai_agents](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/openai_agents.md) | ✅ | ✅ | ✅ | ✅ | ✅ ¹ | — | — | client |
| [claude_agent](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/claude_agent.md) | ✅ ² | — | ✅ | ✅ | — ² | — | — | client |
| [langchain_mcp](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/langchain_mcp.md) | — | ✅ | — | — | — | — | — | client |
| [rag](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/rag.md) | — | — | — | — | — | ✅ | — | client |
| [fastmcp](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/fastmcp.md) | — | ✅ | ✅ | ✅ | — | — | — | server |
| [tool_decorator](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/tool_decorator.md) | — | — | — | ✅ | — | — | — | server |
| [a2a](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/a2a.md) | — | — | — | — | — | — | ✅ | both |
| [gateway](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/gateway.md) ³ | — | ✅ | ✅ | ✅ | — | — | ✅ | proxy |
| [direct](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/integrations/direct.md) | any point you choose, as single or batch decisions | | | | | | | any |

¹ OpenAI's guards are SDK guardrails: a block raises a tripwire the caller catches.
² The Claude Agent SDK has no tool-list filter and no hook that sees the final answer; its input
guard is a hard block.
³ Experimental: not production grade yet; the gateway will move to its own package.

## PDP compatibility

| Feature | Needs | Works with |
|---|---|---|
| Single decisions (①③⑤⑥, masking, `Authorizer.is_permitted`) | XACML 3.0 JSON, or AuthZEN evaluation | any PDP speaking either |
| Batch decisions (②, record filtering, `Authorizer.is_permitted_batch`) | XACML Multiple Decision Profile, or AuthZEN evaluations | PDPs implementing the profile or the batch endpoint |
| Retrieval filter (⑦) | partial evaluation (reverse query) | Axiomatics ADS only; no standard equivalent |

Endpoint paths are configurable, so a PDP that mounts the same protocols elsewhere needs only a
`PdpEndpoints` override. Developed and tested against Axiomatics ADS 26.1.x over both protocols;
single and batch decisions have also been exercised against other open-source PDPs over AuthZEN
and XACML JSON. Details: [Configuration](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/configuration.md#pdp-compatibility).

## Documentation

- [Getting started](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/getting-started.md) → [Configuration](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/configuration.md) →
  [Identity](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/identity.md) → [Agent identity](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/agent-identity.md) →
  [Enforcement points](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/enforcement-points.md) → [Content guards](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/content-guards.md) →
  [Intent-based access control](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/intent-based-access.md) →
  [Obligations and human approval](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/human-approval.md) → [Post-invocation](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/post-invocation.md) →
  [Hooks](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/hooks.md) → [Security](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/security.md) → [Troubleshooting](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/troubleshooting.md) →
  [Performance](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/performance.md)
- [Integrations](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/README.md#integrations), one page per framework
- [Architecture](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/architecture.md), [Running Axiomatics ADS](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/docs/running-ads.md), [Changelog](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/CHANGELOG.md)

## Examples and tests

Runnable examples for every integration are under [`examples/`](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/examples/), each folder with a
README naming the policy it needs; the policies are in [`examples/policies/`](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/examples/policies/).

```bash
uv sync --extra all
uv run pytest tests/          # unit tests need no PDP; integration tests start ADS from examples/policies/
```

## License

Apache 2.0. See [LICENSE](https://github.com/axiomatics/axiomatics-ai-sdk-python/blob/main/LICENSE).
