Agent framework integrations
Installation#
Primary — TypeScript runtime guard + SDK:
npm install @coderifts/agent-guard @coderifts/sdkSecondary — Python SDK:
pip3 install coderifts-sdkFull mode contract (analyze vs authorize): Decision Spec v2. MCP clients: MCP Integration.
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).
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.
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',
target_id: result.decision_result.artifact_digest ?? undefined,
fingerprint: result.verdict_fingerprint,
decision_result: result.decision_result,
});
if (authz.currently_authorized !== true) {
throw new Error(`not authorized: ${authz.status ?? 'unknown'}`);
}See also Agent Quickstart.
LangGraph (Python) — preflight node#
Secondary path. Authorize mode + branch on execution_action. For strongest prevention use TypeScript withCodeRifts above.
pip3 install coderifts-sdk langgraphfrom 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"},
)
action = result.execution_action
if action != "CONTINUE":
return {**state, "blocked": True, "reason": f"aborted: {action} (decision={result.decision})"}
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}
builder = StateGraph(dict)
builder.add_node("preflight", preflight_node)
graph = builder.compile()AutoGen — safe tool wrapper (Python)#
pip3 install coderifts-sdk pyautogenfrom 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}],
)
if result.execution_action != "CONTINUE":
return f"BLOCKED: aborted execution_action={result.execution_action!r} (decision={result.decision})"
receipt = getattr(result, "chain_receipt", None)
authz = coderifts.verify_receipt(receipt, operation="tool_call",
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 and LangChain (Python)#
CrewAI wraps a SafeAPITool class that authorizes on init and re-checks execution_action before every run; LangChain wraps the same authorize + verify sequence inside an @tool-decorated function. Both follow the identical pattern above: authorize_change_set → branch on execution_action → verify_receipt → check currently_authorized is True before executing.
pip3 install coderifts-sdk crewai # CrewAI
pip3 install coderifts-sdk langchain-core # LangChainSDK surface (summary)#
Full field contract: Decision Spec v2.
| 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 |
verify_receipt(token, ...) |
Verify a signed chain-receipt you already hold. A valid signature is not authorization by itself. | currently_authorized, status, payload |