Skip to content

capiscio/langchain-capiscio

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CapiscIO LangChain Guard

Trust enforcement for LangChain and LangGraph agents.

PyPI version Python 3.10+ License

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

# Zero-config — reads CAPISCIO_API_KEY from env, connects to registry
secured = CapiscioGuard() | my_chain
result = secured.invoke({"input": "Summarize this ticket"})

CapiscioGuard reads your environment, connects to the CapiscIO registry on first use, and verifies caller trust badges before every invocation.

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(mode="block")    # Fail closed (production default)
guard = CapiscioGuard(mode="monitor")  # Warn but continue
guard = CapiscioGuard(mode="log")      # Log only

LCEL Pipe Composition

CapiscioGuard is a LangChain Runnable — compose it with any chain or agent via the | operator:

from langchain_capiscio import CapiscioGuard
from langgraph.prebuilt import create_react_agent

agent = create_react_agent(llm, tools)
secured = CapiscioGuard(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())

# 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 create a guard 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()  # reads env vars, connects on first invoke()

Explicit configuration

guard = CapiscioGuard(
    mode="block",
    api_key="cap_...",
    name="my-agent",
    server_url="https://dev.registry.capisc.io",
)

connect_kwargs

Pass extra keyword arguments through to CapiscIO.connect():

guard = CapiscioGuard(
    mode="log",
    connect_kwargs={
        "dev_mode": True,
        "keys_dir": "capiscio_keys/",
        "agent_card": my_card_dict,
    },
)

Using Environment Variables

CapiscioGuard.from_env() mirrors the CapiscIO.from_env() / MCPServerIdentity.from_env() pattern used across CapiscIO packages:

guard = CapiscioGuard.from_env(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 reads env vars automatically
secured = CapiscioGuard(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):

  1. Context variable — set by A2A server middleware via set_capiscio_context()
  2. RunnableConfigconfig={"configurable": {"capiscio_badge": token}}
  3. 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(mode, api_key, name, server_url, connect_kwargs, identity, config) — LCEL-composable trust enforcement Runnable
  • CapiscioGuard.invoke(input, config) — Verify badge and pass through to downstream
  • CapiscioGuard.ainvoke(input, config) — Async version
  • CapiscioGuard.from_env(mode, **kwargs) — Create guard from environment variables

Callbacks

  • CapiscioCallbackHandler(emitter, identity) — Emit chain/tool lifecycle events to CapiscIO

Tool Enforcement

  • CapiscioTool(tool, mode, identity, api_key) — Wrap a LangChain Tool with trust enforcement
  • verify_badge@tool-decorated function for agent-driven badge verification
  • resolve_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 invocation
  • get_capiscio_context() — Retrieve current request context
  • CapiscioRequestContext — 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

See CONTRIBUTING.md for guidelines.

About

Trust enforcement for LangChain and LangGraph agents — verify caller badges, enforce security policies, and emit audit events via LCEL composable guards. Powered by CapiscIO.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages