Trust enforcement adapter for LangChain and LangGraph — powered by CapiscIO
Project description
CapiscIO LangChain Guard
Trust enforcement for LangChain and LangGraph agents.
LangChain Guard is the CapiscIO trust enforcement adapter for LangChain and LangGraph. It verifies caller trust badges, enforces security policies, and emits audit events — all composable via LangChain's LCEL pipe (|) operator with zero configuration.
Installation
pip install langchain-capiscio
Quick Start
Turn any LangChain agent into a trust-verified agent in 2 lines:
from langchain_capiscio import CapiscioGuard
# Reads CAPISCIO_API_KEY from env, connects to registry
secured = CapiscioGuard.connect() | my_chain
result = secured.invoke({"input": "Summarize this ticket"})
CapiscioGuard.connect() reads your environment, connects to the CapiscIO registry, and returns a guard that verifies caller trust badges before every invocation — consistent with CapiscIO.connect() and CapiscioMCPServer.connect() across the ecosystem.
Why LangChain Guard?
LangChain agents orchestrate powerful tools — search, databases, code execution. But LangChain itself doesn't define how to:
- Authenticate which agent is calling your chain
- Authorize whether that agent meets your trust requirements
- Audit what happened for post-incident review
LangChain Guard solves this with:
| Feature | Description |
|---|---|
CapiscioGuard |
Runnable[dict, dict] — verifies trust badges before downstream execution. Composable with |. |
CapiscioTool |
Wraps a LangChain Tool with trust enforcement at the tool-call boundary. |
CapiscioCallbackHandler |
Audit trail — emits chain/tool lifecycle events to the CapiscIO EventEmitter. |
@capiscio_guard |
Decorator for LangGraph function-based nodes. |
verify_badge / resolve_agent_card |
Convenience @tool-decorated functions for agent-driven trust checks. |
Enforcement Modes
Control enforcement behavior per guard instance:
guard = CapiscioGuard.connect(mode="block") # Fail closed (production default)
guard = CapiscioGuard.connect(mode="monitor") # Warn but continue
guard = CapiscioGuard.connect(mode="log") # Log only
LCEL Pipe Composition
CapiscioGuard is a LangChain Runnable — compose it with any chain or agent via the | operator:
Note: The example below uses LangGraph. Install it separately:
pip install langgraph
from langchain_capiscio import CapiscioGuard
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(llm, tools)
secured = CapiscioGuard.connect(mode="log") | agent
result = secured.invoke({"input": "What's 42 * 17?"})
Callback Handler
Emit structured audit events (task lifecycle, tool calls) to the CapiscIO dashboard:
from langchain_capiscio import CapiscioCallbackHandler
handler = CapiscioCallbackHandler(emitter=my_event_emitter)
result = chain.invoke(
{"input": "..."},
config={"callbacks": [handler]},
)
Events emitted: task_started, task_completed, task_failed, tool_call, tool_result.
LangGraph Integration
from langchain_capiscio import CapiscioGuard, capiscio_guard
# Option 1: Runnable as graph node
graph.add_node("verify", CapiscioGuard.connect())
# Option 2: Decorator
@capiscio_guard(mode="block")
def call_agent(state: dict) -> dict:
...
"Let's Encrypt" Style Setup
Zero-config (recommended)
Set environment variables and connect with no arguments:
export CAPISCIO_API_KEY="cap_..."
export CAPISCIO_SERVER_URL="https://dev.registry.capisc.io" # optional
export CAPISCIO_AGENT_NAME="my-agent" # optional
export CAPISCIO_DEV_MODE="true" # optional
guard = CapiscioGuard.connect() # reads env vars, connects eagerly
Explicit configuration
guard = CapiscioGuard.connect(
api_key="cap_...",
mode="block",
name="my-agent",
server_url="https://dev.registry.capisc.io",
)
Extra connect kwargs
Pass additional keyword arguments through to CapiscIO.connect():
guard = CapiscioGuard.connect(
mode="log",
dev_mode=True,
keys_dir="capiscio_keys/",
agent_card=my_card_dict,
)
Using Environment Variables
CapiscioGuard.connect() reads environment variables automatically. from_env() is kept as a convenience alias:
guard = CapiscioGuard.connect(mode="log")
| Variable | Required | Description | Default |
|---|---|---|---|
CAPISCIO_API_KEY |
Yes* | Registry API key | — |
CAPISCIO_SERVER_URL |
No | Registry URL override | https://registry.capisc.io |
CAPISCIO_AGENT_NAME |
No | Agent name for registration | — |
CAPISCIO_DEV_MODE |
No | Enable dev mode (true/1/yes) |
false |
CAPISCIO_AGENT_PRIVATE_KEY_JWK |
No | JSON-encoded Ed25519 private JWK for ephemeral environments | — |
*Required if not passed explicitly via constructor.
Priority: explicit constructor args > connect_kwargs > env vars > SDK defaults.
Deploying to Containers / Serverless
In ephemeral environments (Docker, Lambda, Cloud Run) the local ~/.capiscio/keys/ directory doesn't survive restarts. Without a persisted key, the SDK generates a new keypair on every start, which means a new DID and invalidated badges.
Key Persistence via Environment Variable
On first run the SDK generates a keypair and logs a capture hint:
╔══════════════════════════════════════════════════════════════════╗
║ New agent identity generated — save key for persistence ║
╚══════════════════════════════════════════════════════════════════╝
Add to your secrets manager / .env:
CAPISCIO_AGENT_PRIVATE_KEY_JWK='{"kty":"OKP","crv":"Ed25519","d":"...","x":"...","kid":"did:key:z6Mk..."}'
Copy that value into your secrets manager and set it as an environment variable. On subsequent starts the SDK recovers the same DID without generating a new identity.
Key resolution priority: env var → local file → generate new.
# docker-compose.yml
services:
langchain-agent:
image: my-langchain-agent
environment:
CAPISCIO_API_KEY: ${CAPISCIO_API_KEY}
CAPISCIO_AGENT_PRIVATE_KEY_JWK: ${AGENT_KEY_JWK} # from secrets manager
CAPISCIO_DEV_MODE: "false"
# No code changes needed — CapiscioGuard.connect() reads env vars automatically
secured = CapiscioGuard.connect(mode="block") | my_agent
Warning: Never bake private keys into container images. Inject them at runtime via environment variables or mounted secrets.
See the Ephemeral Deployment Guide for secrets manager examples and volume-mount alternatives.
Badge Token Extraction
CapiscioGuard extracts the caller's badge token from (in priority order):
- Context variable — set by A2A server middleware via
set_capiscio_context() - RunnableConfig —
config={"configurable": {"capiscio_badge": token}} - Input dict —
{"capiscio_badge": token, ...}
For A2A server integrations, set the context at the HTTP perimeter:
from langchain_capiscio import CapiscioRequestContext, set_capiscio_context
set_capiscio_context(CapiscioRequestContext(
badge_token=badge_jwt,
caller_did="did:web:caller.example.com",
))
Trust Levels
| Level | Name | Description |
|---|---|---|
| 0 | Self-Signed (SS) | No external validation, did:key issuer |
| 1 | Registered (REG) | Account registration with CapiscIO Registry |
| 2 | Domain Validated (DV) | Domain ownership verified via DNS/HTTP challenge |
| 3 | Organization Validated (OV) | Organization existence verified (DUNS, legal entity) |
| 4 | Extended Validated (EV) | Manual review + legal agreement with CapiscIO |
API Reference
Guard
CapiscioGuard.connect(api_key, *, mode, name, server_url, dev_mode, **kwargs)— Connect to registry and return a ready-to-use guard (recommended)CapiscioGuard.from_env(mode, **kwargs)— Alias forconnect()(reads env vars)CapiscioGuard(*, identity, config, mode, api_key, name, server_url, connect_kwargs)— Low-level constructor (keyword-only, lazy init on first invoke)CapiscioGuard.invoke(input, config)— Verify badge and pass through to downstreamCapiscioGuard.ainvoke(input, config)— Async version
Callbacks
CapiscioCallbackHandler(emitter, identity)— Emit chain/tool lifecycle events to CapiscIO
Tool Enforcement
CapiscioTool(tool, *, identity=None, config=None, mode="block", api_key=None)— Wrap a LangChainToolwith trust enforcementverify_badge—@tool-decorated function for agent-driven badge verificationresolve_agent_card—@tool-decorated function for agent card resolution
LangGraph
@capiscio_guard(mode, identity, config, api_key)— Decorator for LangGraph function-based nodes
Context
set_capiscio_context(ctx)— Set request context (badge token, caller DID) for the current invocationget_capiscio_context()— Retrieve current request contextCapiscioRequestContext— Dataclass holding badge token and caller DID
Documentation
Development
# Clone repository
git clone https://github.com/capiscio/langchain-capiscio.git
cd langchain-capiscio
# Install development dependencies
pip install -e ".[dev]"
# Run tests
pytest -v
# Run tests with coverage
pytest --cov=langchain_capiscio --cov-report=html
License
Apache License 2.0
Contributing
Contributions welcome! Please open an issue or pull request on GitHub.
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 langchain_capiscio-0.2.0.tar.gz.
File metadata
- Download URL: langchain_capiscio-0.2.0.tar.gz
- Upload date:
- Size: 17.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
10e85f226f5e79ea6fca7048224c6cbddb8889788db8cb7b6ab1201c2c6985ec
|
|
| MD5 |
6473c603b4e8b7eb96315d139dfd5412
|
|
| BLAKE2b-256 |
12e15037f1dcbf1d88fdd8d1b4ab14b1c915f981320271405fed5d85d9a18edd
|
Provenance
The following attestation bundles were made for langchain_capiscio-0.2.0.tar.gz:
Publisher:
publish.yml on capiscio/langchain-capiscio
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_capiscio-0.2.0.tar.gz -
Subject digest:
10e85f226f5e79ea6fca7048224c6cbddb8889788db8cb7b6ab1201c2c6985ec - Sigstore transparency entry: 1530348630
- Sigstore integration time:
-
Permalink:
capiscio/langchain-capiscio@86887359cae8e43140fabc7b384b586baf7cc8d8 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/capiscio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@86887359cae8e43140fabc7b384b586baf7cc8d8 -
Trigger Event:
push
-
Statement type:
File details
Details for the file langchain_capiscio-0.2.0-py3-none-any.whl.
File metadata
- Download URL: langchain_capiscio-0.2.0-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
423910fd317586ffec0ff9645b7d9508e3a9beb79c3d567660e463a6d9c3d958
|
|
| MD5 |
2b610300168814308d5faf8283abea08
|
|
| BLAKE2b-256 |
32db3a64221c1ab8f8df33f13369f07a55e209ba76c0a15de6d1385972663d92
|
Provenance
The following attestation bundles were made for langchain_capiscio-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on capiscio/langchain-capiscio
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
langchain_capiscio-0.2.0-py3-none-any.whl -
Subject digest:
423910fd317586ffec0ff9645b7d9508e3a9beb79c3d567660e463a6d9c3d958 - Sigstore transparency entry: 1530348732
- Sigstore integration time:
-
Permalink:
capiscio/langchain-capiscio@86887359cae8e43140fabc7b384b586baf7cc8d8 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/capiscio
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@86887359cae8e43140fabc7b384b586baf7cc8d8 -
Trigger Event:
push
-
Statement type: