Metadata-Version: 2.4
Name: langchain-nuggets
Version: 1.0.0
Summary: Nuggets authority middleware for LangChain / LangGraph
Project-URL: Homepage, https://nuggets.life
Project-URL: Repository, https://github.com/NuggetsLtd/langchain-nuggets
Project-URL: Changelog, https://github.com/NuggetsLtd/langchain-nuggets/blob/main/CHANGELOG.md
License-Expression: MIT
Keywords: agents,ai,authority,langchain,langgraph,middleware,nuggets,trust
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27.0
Requires-Dist: langchain-core>=0.3.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: pyjwt[crypto]>=2.8.0
Provides-Extra: agent
Requires-Dist: langchain>=1.0; (python_version >= '3.10') and extra == 'agent'
Provides-Extra: dev
Requires-Dist: langgraph-sdk>=0.1.0; extra == 'dev'
Requires-Dist: mypy>=1.13.0; extra == 'dev'
Requires-Dist: pyjwt[crypto]>=2.8.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: respx>=0.22.0; extra == 'dev'
Requires-Dist: ruff>=0.8.0; extra == 'dev'
Provides-Extra: langgraph
Requires-Dist: langgraph-sdk>=0.1.0; extra == 'langgraph'
Description-Content-Type: text/markdown

<p align="center">
  <a href="https://nuggets.life"><img src="https://mintcdn.com/nuggets-b89005a2/jRQbw6WveDYPxE-G/assets/logo-light-bg.svg?fit=max&auto=format&n=jRQbw6WveDYPxE-G&q=85&s=1d4b5047b72eae8cc80de51d2ed68ada" alt="Nuggets" height="56"></a>
</p>

# langchain-nuggets

[![CI](https://github.com/NuggetsLtd/langchain-nuggets/actions/workflows/ci.yml/badge.svg)](https://github.com/NuggetsLtd/langchain-nuggets/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/langchain-nuggets.svg)](https://pypi.org/project/langchain-nuggets/)
[![Python versions](https://img.shields.io/pypi/pyversions/langchain-nuggets.svg)](https://pypi.org/project/langchain-nuggets/)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://github.com/NuggetsLtd/langchain-nuggets/blob/main/LICENSE)

Authority middleware for LangChain / LangGraph — pre-execution trust enforcement on every tool call.

Wrap any `ToolNode` and the middleware calls the Nuggets authority endpoint before each tool executes. The backend evaluates a scoped delegation, returns an `ALLOW` or `DENY` decision, and signs an audit proof. Tools that aren't allowed never run.

## Installation

```bash
pip install langchain-nuggets
```

For LangGraph Platform OIDC auth:

```bash
pip install langchain-nuggets[langgraph]
```

## Authority Middleware

```python
from langchain_nuggets.middleware import NuggetsAuthorityMiddleware, MiddlewareConfig
from langgraph.prebuilt import ToolNode

config = MiddlewareConfig(
    api_url="https://accounts.nuggets.life",
    oidc_issuer_url="https://auth.nuggets.life",
    agent_id="did:web:auth.nuggets.life:your-agent-id",
    controller_id="did:web:auth.nuggets.life:your-controller-id",
    delegation_id="42",
    agent_private_key="/secrets/agent-jwks.json",
)

middleware = NuggetsAuthorityMiddleware(config)

tool_node = ToolNode(
    tools=your_tools,
    wrap_tool_call=middleware.wrap_tool_call,
)
```

**Execution model:** `Agent → Tool Call → Nuggets Authority Check → Allow/Deny → Emit Proof`

**Trust primitives enforced:** Actor Identity, Authority (delegation), Policy, Intent, Consent, Accountability (provenance).

| Behaviour | Detail |
|-----------|--------|
| **ALLOW** | Tool executes; cryptographic proof artifact emitted |
| **DENY** | Tool blocked; structured error returned with `reason_code` |
| **ERROR** | Fail closed — tool not executed |

To provision the agent identity, private key, and delegation referenced above, see [the agent provisioning runbook](https://github.com/NuggetsLtd/langchain-nuggets/blob/main/docs/agent-provisioning.md).

### Proof verification (on by default)

Every `ALLOW` carries a proof signed by the authority, and the SDK **verifies it before the tool runs** — discovering the authority's signing identity from `{api_url}/.well-known/authority-configuration`, pinning the proof's issuer to that authority, verifying the signature against the published JWKS, and binding the proof to the request. Any failure fails **closed**: `DENY` with `reason_code = PROOF_VERIFICATION_FAILED`, tool not run. On by default — no config.

Every decision is therefore **independently verifiable**. A third party can validate an emitted proof out-of-band:

```python
from langchain_nuggets.middleware import verify_authority_proof, discover_authority

issuer, jwks_uri = discover_authority("https://accounts.nuggets.life")
verify_authority_proof(proof_jws, expected={...}, issuer=issuer, jwks_uri=jwks_uri)
```

Opt out only deliberately (e.g. an offline harness verifying proofs separately): `MiddlewareConfig(..., verify_proofs=False)`.

### With `create_agent`

For the LangChain `create_agent` API, install the `agent` extra and use the `AgentMiddleware` adapter (same config, same enforcement):

```bash
pip install langchain-nuggets[agent]
```

```python
from langchain.agents import create_agent
from langchain_nuggets.middleware import NuggetsAuthorityAgentMiddleware, MiddlewareConfig

agent = create_agent(
    model="...",
    tools=your_tools,
    middleware=[NuggetsAuthorityAgentMiddleware(MiddlewareConfig(...))],
)
```

### Agent private key

The accounts portal generates an RS256 keypair at agent creation and lets you download the private key as a JWKS file. `MiddlewareConfig.agent_private_key` accepts:

- A filesystem path to a PEM, JWK JSON, or JWKS JSON file
- A raw PEM string
- A JWK or JWKS dict

The key is never transmitted; only the signed `agent_proof` JWS is sent.

### Test mode

`test_mode=True` short-circuits the live auth flow during local development — every check returns `ALLOW`, no HTTP is made, and the emitted proof artifact is flagged as test-mode-unverifiable.

## LangGraph Platform OIDC auth

```python
from langchain_nuggets.langgraph import NuggetsAuth

nuggets = NuggetsAuth(issuer_url="https://auth.nuggets.life")
auth = nuggets.auth  # pass to langgraph.json
```

Pre-built authorization helpers:

```python
from langchain_nuggets.langgraph import require_scopes, ownership_filter
```

## Self-hosted / private CA

Point the URLs at your own deployment and pass `ca_cert` to either constructor:

```python
MiddlewareConfig(
    api_url="https://nuggets.internal.example.com",
    oidc_issuer_url="https://oidc.internal.example.com",
    # ...
    ca_cert="/etc/ssl/private-ca/nuggets-ca.pem",
)
```

Set `verify_ssl=False` to disable TLS verification (development only).

## About Nuggets

Nuggets provides decentralized identity and verifiable trust infrastructure for people and AI agents. Learn more at [nuggets.life](https://nuggets.life).

## License

MIT
