CAIN-42 · For developers
Framework integrations
Works with LangChain, CrewAI, AutoGen, OpenAI Agents, MCP, Claude Code and Cursor.
Last reviewed 2026-10-01
Live Core platform · Platform feature
What it is
Drop-in adapters for LangChain, LangGraph, CrewAI, AutoGen, OpenAI Agents, Pydantic AI, MCP and OpenTelemetry, plus Claude Code and Cursor hooks.
Where it fits
Part of For developers: SDKs, CLI, MCP server, APIs and offline verifiers. Every CAIN-42 product runs behind the same rule: an AI agent's action is checked before it runs (identity, authority, policy, risk), decided as allow, hold for a human, or block, and recorded as signed evidence. Unknown or error never becomes allow.
Use it
- Documentation
https://cainstudio.online/docs/integrations
Live now
Checked from your browser when this page opened, not from a cached list.
Fire a real decision
Send an action through the live CAIN-42 pipeline from this page, with no account, and watch every stage decide. This is the same pipeline every product here sits behind; it runs for a throwaway demo tenant and is rate limited.
For AI engineers
Every product sits behind one decision path: your agent proposes an action with the exact arguments, CAIN runs it through identity, authority, policy, risk, trust and quorum consensus, and answers ALLOW, REQUIRE_APPROVAL or DENY with an Ed25519-signed record. A timeout, outage or unknown verdict never becomes ALLOW. A brand-new agent has no trust history, so its first actions usually come back REQUIRE_APPROVAL.
Python (zero dependencies)
pip install https://cainstudio.online/cainstudio-0.3.0-py3-none-any.whl
export CAIN_API_KEY=... # free key: https://cainstudio.online/signup
import cainstudio
@cainstudio.guard()
def transfer(amount_usd: float, to: str) -> str:
... # runs only if CAIN allows this call, with these arguments
try:
transfer(5000, "acme")
except cainstudio.ApprovalRequired as e:
print("held for a human:", e.approval_id)
except cainstudio.ActionBlocked as e:
print("refused:", e.decision.reasons)
except cainstudio.CainUnavailable:
print("CAIN unreachable: not run") # fail-closedSee a real decision with no account
cainstudio try # live pipeline, stage by stage
cainstudio try --list # the other attack scenariosMCP clients (Claude Code, Cursor)
claude mcp add --transport http cain https://cainstudio.online/mcpMore: Python SDK · TypeScript SDK · framework integrations · AI quickstart · decision signing key
Tested guarantees in this area
Every rule in these niches has its own page with its recorded result.
- Tools, MCP, protocols & adapters: 684 tested invariants — How agents reach tools, APIs and each other, safely.
- Benchmarks, coverage & performance: 1269 tested invariants — How fast it runs and how much was tested.
Related
- CAIN MCP server — Plug CAIN into Claude, Cursor or any MCP client with one command.
- cainstudio CLI — Decide, explain and approve actions from your terminal.
- cainstudio Python SDK — Add one line to your Python agent and every risky action is checked first.
- Decision API — One HTTP call: send the action, get allow / hold / block and a signed record.
- Hosted service catalog — Every hosted service you can call with one key.
- TypeScript SDK — Guard agent actions from Node.js and TypeScript.
Full documentation
The complete reference, also at /docs/integrations.
Framework integrations#
Every example below uses the client you can install today:
pip install https://cainstudio.online/cainstudio-0.3.0-py3-none-any.whl pip install "cainstudio[langchain] @ https://cainstudio.online/cainstudio-0.3.0-py3-none-any.whl" # LangChain adapter export CAIN_API_KEY=agt_... # the agent's own key (see the quickstart)
(PyPI listing pending. Each snippet on this page is run against that wheel; see "How this page is checked" at the end.)
Honest status per framework. "Supported" means there is framework-specific code in the package. "Generic" means you guard the plain function the framework calls with @cainstudio.guard(), which works in any framework because every one of them ultimately calls a function to execute a tool.
| Framework | Status | How |
| Custom Python | Supported | @cainstudio.guard() on the function that acts |
| LangChain | Supported | cainstudio.langchain.protect(tools) |
| LangGraph | Generic | guard the tool functions your nodes call |
| LlamaIndex | Generic | guard the function behind your FunctionTool |
| CrewAI | Generic | guard the function behind your @tool |
| OpenAI agents | Generic | guard the function you dispatch to on a tool call |
| Microsoft (AutoGen) | Generic | guard the function you register as a tool |
| Google (Vertex / ADK) | Generic | guard your FunctionDeclaration handler |
| TypeScript / JavaScript | Generic | the ~20-line helper in TypeScript (no npm package yet) |
| MCP | Supported (self-hosted) | MCPGate in the call path, see MCP |
| Dedicated adapters for the rest | Planned | not built |
What a guard does#
import cainstudio
@cainstudio.guard()
def send_email(to: str, subject: str, body: str) -> str:
... # unchanged
Before the body runs, the call's name and arguments go to CAIN-42. If it is allowed, the function runs. Otherwise it raises instead of running: cainstudio.ActionBlocked (denied), cainstudio.ApprovalRequired (held for a human; it carries the approval id) or cainstudio.CainUnavailable (CAIN could not be asked, which is never treated as allowed). @cainstudio.guard(wait_for_approval=120) waits up to 120 seconds for a human instead of raising. Async functions work the same way.
LangChain#
For tools you did not write (third-party, built-in, already constructed), and to guard a whole list at once:
from cainstudio.langchain import protect tools = protect([search, send_email, transfer_funds], agent_id="support-agent") agent = create_agent(model, tools)
Names, descriptions and argument schemas are kept, so the model sees exactly the same tools. A refused or held call is not executed; by default the refusal is returned to the model as the tool's error, so the agent can explain or take another route. on_block="raise" raises instead. A missing or unknown key is not a refusal, it is misconfiguration: it always raises (ConfigurationError, AuthenticationError), in either mode, and the tool body does not run. For tools you write yourself, @cainstudio.guard() on the function is enough.
Forgetting one tool is the realistic failure mode, and it is silent. Pass the agent's whole tool list through protect() rather than picking tools one by one.
LangGraph#
Guard the tool functions rather than the nodes where you can: a node may do several things, and you want the decision attached to the consequential one.
@cainstudio.guard()
def issue_refund(order_id: str, amount: int) -> str:
...
OpenAI agents#
Guard the dispatch target, not the model call. The model producing a tool call is not the action; executing it is.
import json
@cainstudio.guard()
def delete_record(record_id: str): ...
def handle_tool_call(call):
if call.function.name == "delete_record":
return delete_record(**json.loads(call.function.arguments))
CrewAI#
from crewai.tools import tool
@tool("Refund an order")
@cainstudio.guard()
def issue_refund(order_id: str) -> str: ...
Order matters: @cainstudio.guard() goes closest to the function, so the decision is made around the real call with its real arguments.
How this page is checked#
The guard and LangChain snippets were run on 1 October 2026 against the published cainstudio-0.2.1 wheel in a clean virtual environment with langchain-core installed: the decorator, protect() with tool names and schemas preserved, and the error classes named above. A call with no key, or with an unknown key, raises before the tool body runs, and protect() keeps the tool's name, description and argument schema. Framework examples for CrewAI and OpenAI show only where the guard goes; those frameworks were not installed for the check.
The earlier version of this page used from cain import trust and cain.adapters.langchain. Those come from the cain-trust operator package, which is not installable on its own yet.
Try CAIN-42 on your own agents
Create a free account and every new account starts with a 7-day trial of the full platform. Or try the sandbox first, with no account at all.
Create a free account → · Try the sandbox · See the whole ecosystem