Skip to main content

SDK API

This is the canonical reference for the Python SDK. For tutorial-style introductions see Quickstart; for framework-specific patterns see the Framework adapters.

proofrail.init()

Configure the SDK. Call once at application startup before opening any chains.
proofrail.init(
    api_key: str,
    *,
    environment: str = "production",
    backend_url: str = "https://api.proofrail.dev",
    backend_timeout_seconds: float = 5.0,
    fail_modes: dict[str, str] | None = None,
    fail_mode: str | None = None,
    financial_approval_threshold_usd: float = 5000.0,
    cumulative_financial_threshold_usd: float = 10000.0,
    external_domains_allowlist: list[str] | None = None,
    high_risk_agents: list[str] | None = None,
    default_approval_timeout_hours: float = 24,
    fallback_approvers: list[str] | None = None,
    sensitive_field_patterns: list[str] | None = None,
    sensitive_value_patterns: list[str] | None = None,
    max_payload_string_length: int = 1000,
    enable_local_fast_path: bool = True,
    offline_buffer_max_events: int = 100,
)
Required
ParameterTypeDescription
api_keystrYour ProofRail API key, prefixed prail_. Treated as a secret.
Common
ParameterTypeDefaultDescription
environmentstr"production"Tag attached to every chain. Common values: "production", "staging", "development".
backend_urlstr"https://api.proofrail.dev"Override for self-hosted or testing deployments.
backend_timeout_secondsfloat5.0Per-request timeout when calling the backend. Should be raised for high-latency networks (e.g., 15s for Supabase free-tier).
Failure handling
ParameterTypeDefaultDescription
fail_modesdict[str, str]See ConfigurationPer-action-class behavior when the backend is unreachable. Keys are action categories (financial, external_communication, etc.); values are "deny" or "allow". A default key sets the fallback for unmatched categories.
fail_modestrNoneLegacy single-string parameter. Treated as {"default": fail_mode}. Don’t pass both fail_modes and fail_mode.
offline_buffer_max_eventsint100Number of events buffered locally if the backend is unreachable. Oldest events drop when the buffer fills.
Policy thresholds
ParameterTypeDefaultDescription
financial_approval_threshold_usdfloat5000.0Single transactions above this require approval.
cumulative_financial_threshold_usdfloat10000.0Chain cumulative financial exposure above this requires approval on the next financial action.
external_domains_allowlistlist[str]NoneDomains agents may communicate with without triggering exfiltration alerts.
high_risk_agentslist[str]NoneAgent names treated as high-risk; every action by these agents requires approval.
default_approval_timeout_hoursfloat24How long approval requests stay valid before timing out.
fallback_approverslist[str]NoneEmail addresses that receive escalations if primary approvers don’t respond within half the timeout.
Privacy
ParameterTypeDefaultDescription
sensitive_field_patternslist[str]See Sanitization defaultsField-name substrings that get redacted in payloads sent to the backend. Match is case-insensitive substring against keys.
sensitive_value_patternslist[str]See Sanitization defaultsValue prefixes that get redacted. Match uses str.startswith() against string values.
max_payload_string_lengthint1000Strings longer than this are truncated before being sent.
Performance
ParameterTypeDefaultDescription
enable_local_fast_pathboolTrueAllow obviously-safe actions to be decided locally without a backend round-trip. Disable for strictest governance (every action goes to the backend).

Returns

A ChainConfig instance. Configuration is also stored globally for the process so subsequent proofrail.Chain(...) calls use it.

Sanitization defaults

The SDK uses two separate default lists for redacting sensitive data: sensitive_field_patterns (default — matches against dict keys by case-insensitive substring):
["api_key", "password", "secret", "token", "credit_card", "ssn", "private_key"]
sensitive_value_patterns (default — matches against string values using str.startswith()):
["sk_", "pk_", "ghp_", "hf_", "eyJ", "AKIA", "prail_"]
Custom patterns you pass via the corresponding kwarg are appended to the defaults.

proofrail.Chain

Context manager that opens a chain and records every action within it. Use as an async or sync context manager depending on your code.
class Chain:
    def __init__(
        self,
        name: str,
        *,
        external_chain_id: str | None = None,
        metadata: dict | None = None,
    ): ...

    async def __aenter__(self) -> "Chain": ...
    async def __aexit__(self, exc_type, exc_val, exc_tb) -> None: ...

    def __enter__(self) -> "Chain": ...
    def __exit__(self, exc_type, exc_val, exc_tb) -> None: ...

    async def record_agent_action(...) -> PolicyDecision: ...
    def record_agent_action_sync(...) -> PolicyDecision: ...

Constructor parameters

ParameterTypeDescription
namestrHuman-readable identifier shown in the dashboard. Conventional: hyphen-separated lowercase ("vendor-purchase", "customer-onboarding").
external_chain_idstrYour own ID for the chain, useful for cross-referencing with your internal systems. Stored unchanged.
metadatadictArbitrary JSON-serializable key/value pairs. Attached to the chain and visible in receipts. Stored as opaque data — the SDK does not interpret keys within it.

Lifecycle

On __aenter__ / __enter__: a chain record is created on the backend; the chain ID is available as chain.id after entry. On __aexit__ / __exit__: the SDK calls POST /v1/chains/{chain_id}/complete, which seals the chain and triggers receipt generation on the backend. If exit was triggered by an exception, the chain is marked accordingly and the receipt reflects the failure mode.

Methods

record_agent_action() (async)

async def record_agent_action(
    self,
    agent_name: str,
    action_type: str,
    action_name: str,
    payload: dict,
    *,
    parent_agent_name: str | None = None,
    metadata: dict | None = None,
) -> PolicyDecision
Record an action and receive a policy decision.
ParameterTypeDescription
agent_namestrIdentifier for the agent taking the action.
action_typestrCategory of action. Common values: tool_call, llm_call, state_update.
action_namestrSpecific name within the type. For tool_call, the tool name (e.g., search_web, send_email).
payloaddictThe action’s inputs. Sanitized before sending.
parent_agent_namestrAgent that delegated to this one, if any. Used for tracking hierarchical workflows.
metadatadictAction-level metadata. For LLM calls, include model, input_tokens, output_tokens for cost tracking.
Returns a PolicyDecision object on allow or allow_with_flag outcomes. Blocks until resolution on require_approval. Raises on deny.

record_agent_action_sync()

Synchronous form for non-async code. Same signature and behavior, but raises RuntimeError if called from inside a running event loop.

chain.id

The backend-assigned chain UUID. Available after __aenter__ / __enter__. Useful for logging or cross-system references:
async with proofrail.Chain("workflow") as chain:
    logger.info("Started chain", extra={"chain_id": chain.id})

proofrail.PolicyDecision

Returned by record_agent_action when the action is allowed (including after a human approval resolves).
@dataclass
class PolicyDecision:
    policy_decision: str                          # "allow" | "allow_with_flag"
    decision_reason: str = ""
    decision_source: str = "backend_evaluation"
    policy_name: str | None = None
    kill_switch_active: bool = False
    pause_reason: str | None = None
    remediation: str | None = None
    docs_url: str | None = None
    evaluation_mode: str | None = None
    shadow_decision: str | None = None
    estimated_cost_usd: float | None = None
    auto_paused: bool = False
AttributeTypeDescription
policy_decisionstrThe outcome — "allow" or "allow_with_flag". (Denials raise instead.)
decision_reasonstrHuman-readable explanation if a policy matched. Empty string when no reason applies.
decision_sourcestrWhere the decision came from: "backend_evaluation", "local_fast_path", "human_approval", or "offline_stub".
policy_namestrName of the matched policy, if any.
kill_switch_activeboolTrue if the org’s kill switch was found active during evaluation (in which case denials raise ProofRailKillSwitchError).
pause_reasonstrIf the org was paused, the reason supplied at activation.
remediationstrSuggested fix when a policy matched.
docs_urlstrLink to docs for this kind of decision.
evaluation_modestr"enforce" or "shadow" for the matching policy.
shadow_decisionstrWhen evaluation_mode is "shadow", the decision the policy would have made in enforce mode.
estimated_cost_usdfloatFor LLM call events, the computed cost.
auto_pausedboolTrue if the chain auto-paused at this action (event-count, duration, or token-budget limit).

Framework adapters

Each adapter exposes a govern() function that wraps an existing framework object. See the framework-specific pages for usage details.

proofrail.langgraph.govern()

def govern(
    compiled_graph,
    chain_name: str = "langgraph_workflow",
    metadata: dict | None = None,
) -> GovernedGraph
See LangGraph adapter.

proofrail.langchain.govern()

def govern(
    agent_executor_or_chain,
    chain_name: str = "langchain_workflow",
    metadata: dict | None = None,
) -> GovernedChain
The agent_name for recorded events is derived from type(executor).__name__ at wrap time — it isn’t a govern() parameter. See LangChain adapter.

proofrail.crewai.govern()

def govern(
    crew,
    chain_name: str = "crewai_workflow",
    metadata: dict | None = None,
) -> GovernedCrew
See CrewAI adapter.

proofrail.mcp.ProofRailMcpAdapter

class ProofRailMcpAdapter:
    def __init__(
        self,
        *,
        chain: proofrail.Chain,
        agent_name: str,
        parent_agent_name: str | None = None,
    ): ...

    def install(self, server) -> None: ...
    async def handle_tool_call(self, tool_name: str, arguments: dict, handler) -> Any: ...
    def tool(self, tool_name: str | None = None): ...  # decorator
See MCP adapter.

proofrail.client.verify_receipt()

Verify a receipt’s signature and return its contents.
async def verify_receipt(receipt_id: str) -> ReceiptVerifyResponse
class ReceiptVerifyResponse(BaseModel):
    valid: bool
    receipt_number: str
    chain_id: str
    generated_at: str
The valid field indicates whether the receipt’s HMAC signature checks out. If invalid, the receipt has been tampered with or modified after signing. This is a thin client over the public verification endpoint at GET /v1/receipts/{receipt_id}/verify. The endpoint requires no authentication — anyone with a receipt ID can verify. See Audit receipts for the signing and hash-chaining model.

Exceptions

All exceptions live in proofrail.exceptions. The base for policy-driven errors is ProofRailPolicyError.
ProofRailPolicyError                # base for policy denials
├── ActionDeniedError               # Policy or human reviewer denied
├── PolicyViolationError            # Policy condition violated outside main eval path
└── ProofRailKillSwitchError        # Org kill switch is active

Exception
├── BackendUnavailableError         # Backend unreachable, fail_mode=deny
├── ChainTimeoutError               # Chain exceeded configured timeout
└── ChainAutoPausedError            # Auto-pause rule fired (events, duration, tokens)
See Exceptions reference for attributes and handling patterns.

Version compatibility

The SDK requires Python 3.10 or later (enforced at install time by pip). Supported framework version ranges are pinned in sdk/pyproject.toml; install ProofRail with a compatible version of your framework already installed. See Limitations for the current compatibility matrix.

Where to go next

Configuration

Detailed walkthrough of every init() option.

Exceptions

All exception types and how to handle them.

Framework adapters

Per-framework usage and edge cases.

Limitations

What ProofRail does and doesn’t do at current version.