Agent Framework
Integrations
Add API governance to AI agents. Primary path: @coderifts/agent-guard + TypeScript (OpenAI tools / LangGraph-JS). Python SDK examples stay available as a secondary section. Contract: Decision Spec v2 — preflight_mode required; act only on authorize + verified receipt.
Installation
Primary — TypeScript runtime guard + SDK
npm install @coderifts/agent-guard @coderifts/sdk
Secondary — Python SDK
pip3 install coderifts-sdk
Full mode contract (analyze vs authorize): /decision-spec/. MCP clients: /mcp/.
Framework Examples
Default tab is TypeScript. Every acting example uses preflight_mode: "authorize" with context.operation, branches on execution_action, and only then trusts a receipt for downstream gates. Analyze is risk-only — see the decision-spec page.
TypeScript — withCodeRifts (canonical)
Wrap the OpenAI (or any) tool table so mutating tools cannot run without a CodeRifts authorize preflight. The host must register only the returned tools array. Operation is required (receipts bind to it). See also agents quickstart.
Install
npm install @coderifts/agent-guard @coderifts/sdk
Guard the tool table (authorize path inside the package)
import { withCodeRifts } from '@coderifts/agent-guard';
import { CodeRifts } from '@coderifts/sdk';
const client = new CodeRifts({ apiKey: process.env.CODERIFTS_API_KEY });
// Register ONLY tools from the returned table — anything else bypasses the guard.
const { tools } = withCodeRifts({
tools: rawOpenAITools,
client,
operation: 'merge', // required: merge | deploy | publish | tool_call | …
environment: 'production',
});
// When you call preflight yourself (e.g. MCP or REST twin), use the authorize wrapper:
const result = await client.authorizeChangeSet({
context: { operation: 'merge' },
artifacts: [{ id: 'api', type: 'openapi', before: baseSpec, after: headSpec }],
});
// Branch on execution_action only (authorize). Unknown values fail closed.
if (result.execution_action !== 'CONTINUE') {
throw new Error(`halted: ${result.execution_action} (${result.decision})`);
}
// A valid signature is NOT authorization. currently_authorized lives on the
// verify-receipt response, not on the preflight result — check it before acting.
// Token-only verifyReceipt returns currently_authorized:null (not evaluated).
// Pass VerifyReceiptIntendedContext so the server can return true/false.
if (!result.chain_receipt) {
throw new Error('CodeRifts: authorize returned no chain_receipt to verify');
}
if (!result.decision_result) {
throw new Error('CodeRifts: missing decision_result');
}
const authz = await client.verifyReceipt(result.chain_receipt, {
operation: 'merge', // same operation the authorize preflight used
target_id: result.decision_result.artifact_digest ?? undefined,
fingerprint: result.verdict_fingerprint,
decision_result: result.decision_result, // DecisionResultEnvelope (JSON object; no to_dict)
});
if (authz.currently_authorized !== true) {
throw new Error(`not authorized: ${authz.status ?? 'unknown'}`);
}
// Downstream gates: verify chain_receipt conjunctively (receipt + currently_authorized
// + operation + fingerprint + execution_action) — see /decision-spec/
LangGraph.js sketch (same authorize rule)
// Same contract: preflight_mode "authorize", context.operation set, branch on execution_action.
// Prefer withCodeRifts so the model never holds raw mutating tools.
const { tools } = withCodeRifts({ tools: graphTools, client, operation: 'merge' });
// bind tools into your LangGraph.js agent / tool node
LangGraph (Python) — Preflight Node
Secondary path. Authorize mode + branch on execution_action. For strongest prevention use TypeScript withCodeRifts above.
Install dependencies
pip3 install coderifts-sdk langgraph
Full working example
from langgraph.graph import StateGraph
from coderifts import CodeRifts
coderifts = CodeRifts(api_key="cr_live_...")
def preflight_node(state):
result = coderifts.authorize_change_set(
artifacts=[{
"id": state["artifact_id"],
"type": "openapi",
"before": state["old_spec"],
"after": state["new_spec"],
}],
context={"operation": "merge", "environment": "staging"},
)
# Authorize only: branch on execution_action; decision explains why.
action = result.execution_action
# CONTINUE_WITH_MONITORING requires monitoringSinkWired; this example proceeds only on CONTINUE.
if action != "CONTINUE":
return {**state, "blocked": True, "reason": f"aborted: {action} (decision={result.decision})"}
# A valid signature is not authorization: currently_authorized comes from verify_receipt.
receipt = getattr(result, "chain_receipt", None)
authz = coderifts.verify_receipt(
receipt,
operation="merge",
environment=getattr(result, "environment", None),
target_id=getattr(result.decision_result, "artifact_digest", None),
fingerprint=getattr(result, "verdict_fingerprint", None),
decision_result=result.decision_result.to_dict(),
) if receipt else None
if getattr(authz, "currently_authorized", None) is not True:
return {**state, "blocked": True, "reason": "receipt not currently_authorized"}
return {**state, "blocked": False, "receipt": receipt}
def tool_node(state):
if state.get("blocked"):
return state
return state
builder = StateGraph(dict)
builder.add_node("preflight", preflight_node)
builder.add_node("execute", tool_node)
builder.add_edge("preflight", "execute")
graph = builder.compile()
AutoGen — Safe Tool Wrapper (Python)
Authorize preflight before the tool runs. Branch on execution_action only.
Install dependencies
pip3 install coderifts-sdk pyautogen
Full working example
import autogen
from coderifts import CodeRifts
coderifts = CodeRifts(api_key="cr_live_...")
def safe_tool_call(artifact_id, old_spec, new_spec, tool_fn, *args, **kwargs):
result = coderifts.authorize_change_set(
context={"operation": "tool_call"},
artifacts=[{
"id": artifact_id,
"type": "openapi",
"before": old_spec,
"after": new_spec,
}],
)
action = result.execution_action
if action != "CONTINUE":
return f"BLOCKED: aborted execution_action={action!r} (decision={result.decision})"
# A valid signature is not authorization: currently_authorized comes from verify_receipt.
receipt = getattr(result, "chain_receipt", None)
authz = coderifts.verify_receipt(
receipt,
operation="tool_call",
environment=getattr(result, "environment", None),
target_id=getattr(result.decision_result, "artifact_digest", None),
fingerprint=getattr(result, "verdict_fingerprint", None),
decision_result=result.decision_result.to_dict(),
) if receipt else None
if getattr(authz, "currently_authorized", None) is not True:
return "BLOCKED: receipt not currently_authorized"
return tool_fn(*args, **kwargs)
CrewAI — Safe API Tool (Python)
Authorize on init; on run, re-check execution_action before executing.
Install dependencies
pip3 install coderifts-sdk crewai
Full working example
from crewai import Agent, Task, Crew
from coderifts import CodeRifts
coderifts = CodeRifts(api_key="cr_live_...")
class SafeAPITool:
def __init__(self, artifact_id, old_spec, new_spec):
self.artifact_id = artifact_id
self.preflight = coderifts.authorize_change_set(
context={"operation": "tool_call"},
artifacts=[{
"id": artifact_id,
"type": "openapi",
"before": old_spec,
"after": new_spec,
}],
)
def run(self, *args, **kwargs):
action = self.preflight.execution_action
if action != "CONTINUE":
raise RuntimeError(f"CodeRifts aborted: execution_action={action!r} (decision={self.preflight.decision})")
# A valid signature is not authorization: currently_authorized comes from verify_receipt.
receipt = getattr(self.preflight, "chain_receipt", None)
authz = coderifts.verify_receipt(
receipt,
operation="tool_call",
environment=getattr(self.preflight, "environment", None),
target_id=getattr(self.preflight.decision_result, "artifact_digest", None),
fingerprint=getattr(self.preflight, "verdict_fingerprint", None),
decision_result=self.preflight.decision_result.to_dict(),
) if receipt else None
if getattr(authz, "currently_authorized", None) is not True:
raise RuntimeError("CodeRifts: receipt not currently_authorized")
# ... execute tool
LangChain (Python) — Preflight Tool
Authorize + branch on execution_action inside the tool.
Install dependencies
pip3 install coderifts-sdk langchain-core
Full working example
from langchain_core.tools import tool
from coderifts import CodeRifts
coderifts = CodeRifts(api_key="cr_live_...")
@tool
def get_order_status(order_id: str) -> str:
"""Look up an order status before calling the API."""
result = coderifts.authorize_change_set(
context={"operation": "tool_call"},
artifacts=[{
"id": "orders-api",
"type": "openapi",
"before": OLD_SPEC,
"after": NEW_SPEC,
}],
)
action = result.execution_action
if action != "CONTINUE":
raise RuntimeError(f"CodeRifts aborted: execution_action={action!r} (decision={result.decision})")
# A valid signature is not authorization: currently_authorized comes from verify_receipt.
receipt = getattr(result, "chain_receipt", None)
authz = coderifts.verify_receipt(
receipt,
operation="tool_call",
environment=getattr(result, "environment", None),
target_id=getattr(result.decision_result, "artifact_digest", None),
fingerprint=getattr(result, "verdict_fingerprint", None),
decision_result=result.decision_result.to_dict(),
) if receipt else None
if getattr(authz, "currently_authorized", None) is not True:
raise RuntimeError("CodeRifts: receipt not currently_authorized")
return status
SDK surface (summary)
Full field contract: Decision Spec v2. Below is a short map only.
| Method | Description | Returns |
|---|---|---|
| preflight_change_set(..., preflight_mode=) | preflight_mode required. authorize (with context.operation): branch on execution_action. analyze: risk only (analysis_outcome, may_execute:false) — not permission. |
mode-dependent (see /decision-spec/) |
| verify_receipt(token, ...) | Verify a signed chain-receipt you already hold. A valid signature is not authorization — check currently_authorized. |
valid, currently_authorized, status |
| get_decision_details(decision_id=..., fingerprint=...) | Look up a past decision by decision_id or fingerprint. Read-only — not for making new safety decisions. | execution_action, decision, safe_for_agent, risk_score |
Default Policy
CodeRifts provides a recommended default policy for all agent frameworks. Fetch it programmatically from the GET /api/v1/policy/default endpoint.
The default policy blocks every breaking change — field or endpoint removal, type changes, enum narrowing, and newly required fields — and flags everything else for review. Each endpoint returns the same decision shape, so one check works across every framework.
Copy-paste preflight decorator (secondary)
A framework-agnostic Python decorator can wrap a tool function for demos. Prefer the TypeScript @coderifts/agent-guard path above for production table wrapping. Any path that acts on a change set must use preflight_mode: "authorize" with context.operation and branch on execution_action — not mode-less public GET checks as a gate. Full contract: /decision-spec/.
Runtime prevention that wraps a whole tool table: @coderifts/agent-guard — agents quickstart.
Wrap any tool function
from coderifts_decorator import coderifts_guard
@coderifts_guard(old_spec, new_spec) # halts on BLOCK
def call_order_api(order_id):
# runs only if the change is safe for agents
return requests.get(f"https://your-api.com/orders/{order_id}").json()
Human-in-the-loop: also halt on REQUIRE_APPROVAL
@coderifts_guard(old_spec, new_spec, strict=True)
def call_order_api(order_id):
...
Runnable LangGraph and LangChain examples, verified end-to-end, live in the example-langgraph-guard repo.
MCP Integration
For agents that support the Model Context Protocol (Claude Desktop, Cursor, Windsurf), CodeRifts exposes governance tools directly via MCP — no SDK required.
View MCP Integration