Skip to main content

Nuggets

langchain-nuggets

CI PyPI Python versions License: MIT

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.

Why Nuggets Authority?

Most agent middleware shapes prompts or guardrails outputs. Nuggets Authority governs actions — "is this agent allowed to do this, right now, on whose authority?" — before a tool runs, and leaves cryptographic proof.

  • Pre-execution enforcement, not after-the-fact logging — unauthorized calls fail closed and never run.
  • Cryptographic accountability — every decision is a signed, independently verifiable proof artifact; verification on by default.
  • Scoped, revocable authority — delegations bound by capability, target, invocation cap, and expiry.
  • Intent binding — optional intent_resolver support adds an intent_hash to proofs, so reviewers can distinguish the same action taken for different business intents.
  • Trusted agent identity — each request signed (RS256) and bound to the agent's DID, ownership verified server-side.
  • Drop-in for both ToolNode and create_agent, with no changes to your tools.

Built on Nuggets, the universal trust infrastructure for autonomous AI. Nuggets governs at the point of execution.

Installation

pip install langchain-nuggets

For LangGraph Platform OIDC auth:

pip install langchain-nuggets[langgraph]

Authority Middleware

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
ESCALATE Human approval required; verified PENDING_APPROVAL returned, tool not executed, no proof artifact (see Payments & approvals)
ERROR Fail closed — tool not executed
Proof binding Proofs bind actor, controller, delegation, tool, parameters, result hash, constraints, and optional intent hash

To provision the agent identity, private key, and delegation referenced above, see the agent provisioning runbook.

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:

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).

Intent binding

Set intent_resolver when the agent can identify why a tool call is being made. The SDK hashes the intent with the request parameters and timestamp, sends the intent_hash to the authority, and includes it in the emitted proof artifact.

MiddlewareConfig(
    ...,
    intent_resolver=lambda tool, args: "KYC lookup for compliance review",
)

Payments & approvals

For monetary tools, supply an action-context resolver to attach the payment amount_minor (minor units, integer) and currency (ISO-4217, uppercase) to the signed action. The resolver is the only source of money fields — they are never inferred from tool args — and the tool name must exactly match the delegation capability (e.g. nuggets.payments.send).

MiddlewareConfig(
    ...,
    action_context_resolver=lambda tool, args: {
        "amount_minor": 500,           # £5.00
        "currency": "GBP",
        "target": "did:web:merchant",  # optional; overrides the args-derived target
    },
)

amount_minor and currency are validated as a pair — supply both or neither. Invalid money fields (negative/non-integer amount, non-^[A-Z]{3}$ currency, one without the other) fail closed with an ERROR ToolMessage before the tool runs.

ESCALATE (human approval). When the authority requires approval it returns ESCALATE. The middleware verifies the signed decision — exactly as it does for ALLOW — then returns a PENDING_APPROVAL ToolMessage. This is not an error, and the wrapped tool never runs:

{ "status": "PENDING_APPROVAL", "approval_id": 500, "reason_code": "APPROVAL_REQUIRED", "proof_id": "...", "signature": "..." }

Operational boundary:

  • No payment handler runs on PENDING_APPROVAL — nothing is executed or charged.
  • The application owns polling/redeem of the approval, out-of-band, using approval_id.
  • approval_id is a server-issued handle, not part of the signed receipt — treat it as an opaque identifier, not a cryptographically verified field. (The ESCALATE decision signature is verified.)

With create_agent

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

pip install langchain-nuggets[agent]
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.

Keep the private JWKS in a secret store or mounted secret — never in source control, logs, or Downloads; treat any previously downloaded key as stale. For demos and smoke runs, use a disposable, scoped delegation and a freshly downloaded key, and revoke both afterwards.

Test mode

test_mode=True short-circuits the live auth flow during local development — no HTTP is made and each check returns a synthetic ALLOW with a proof artifact flagged as test-mode-unverifiable. Action-context resolution still runs first: a configured action_context_resolver that returns invalid money fields (or raises) fails closed with an ERROR ToolMessage before the short-circuit, so validation behaves identically in and out of test mode.

LangGraph Platform OIDC auth

from langchain_nuggets.langgraph import NuggetsAuth

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

JWTs are verified with a fixed RS256 allowlist (never the token header's alg), and JWKS keys are filtered by kty/use/alg. If you pass audience=, it is enforced per RFC 9068.

Audience enforcement is not yet mandatory. Making a configured audience required (failing closed when unset) is deferred until the Nuggets issuer defines a LangGraph resource-server aud — there is no concrete audience= value to set today (tracked in #63). When it lands, set audience= to your deployment's resource URI; do not use the authority API resource (…/api/authority), which is a different resource.

Pre-built authorization helpers:

from langchain_nuggets.langgraph import require_scopes, ownership_filter

# Owner-scope every operation. ownership_filter stamps value["metadata"]["owner"]
# on writes and returns an {"owner": identity} filter for reads/searches; it
# fails closed (403) when there is no authenticated identity.
owned = ownership_filter()
for op in (
    auth.on.threads.create, auth.on.threads.read, auth.on.threads.update,
    auth.on.threads.delete, auth.on.threads.search,
):
    op(owned)

Register it for every operation you want scoped — a create handler alone stamps the owner but leaves reads/updates/deletes unfiltered.

Self-hosted / private CA

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

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 is the universal trust infrastructure for autonomous AI. Nuggets governs at the point of execution. Learn more at nuggets.life.

License

MIT

Trademarks

langchain-nuggets is an independent, community-maintained integration and is not affiliated with, sponsored by, or endorsed by LangChain, Inc. "LangChain" and "LangGraph" are trademarks of LangChain, Inc. All other trademarks are the property of their respective owners.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

langchain_nuggets-1.1.2.tar.gz (41.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

langchain_nuggets-1.1.2-py3-none-any.whl (32.2 kB view details)

Uploaded Python 3

File details

Details for the file langchain_nuggets-1.1.2.tar.gz.

File metadata

  • Download URL: langchain_nuggets-1.1.2.tar.gz
  • Upload date:
  • Size: 41.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for langchain_nuggets-1.1.2.tar.gz
Algorithm Hash digest
SHA256 1837171c51865d0c4effc8dac2f903fae2aee5ed779cc9235dd37ee4f20517c5
MD5 36c26bdc50bb41e19f43efb3ffc576d7
BLAKE2b-256 2af6d290c4e8b02b55b7812f460f8f90fb2e1b284cabbb3dc31154bc45e72996

See more details on using hashes here.

Provenance

The following attestation bundles were made for langchain_nuggets-1.1.2.tar.gz:

Publisher: release-pypi.yml on NuggetsLtd/langchain-nuggets

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file langchain_nuggets-1.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for langchain_nuggets-1.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 efabf7a4290178f79aa38149b6743c51806fc317edf094d1fef15d178bd42a53
MD5 c69367da46aa4928f005670f4813947a
BLAKE2b-256 6bf7e16bec10914fbd2b09e8a4e097fb0503e2b9fe179c1732a3cd456652947d

See more details on using hashes here.

Provenance

The following attestation bundles were made for langchain_nuggets-1.1.2-py3-none-any.whl:

Publisher: release-pypi.yml on NuggetsLtd/langchain-nuggets

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

1.3.0

2 files

This release

1.1.2 This release

2 files

1.1.1

2 files

1.1.0

2 files

1.0.0

2 files

0.6.0

2 files

0.4.1

2 files

0.3.0

2 files

0.2.0

2 files

0.1.0

2 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