Skip to content

SDK Guide

CRP ships a progressive-disclosure SDK (SPEC-032). Start with one line of code and unlock deeper control only when you need it. No rewrites. No architecture changes.

Who this is for

  • Developers who want governance without learning a new API
  • Compliance teams who need audit trails and risk scores
  • Engineers who want full control over routing, safety, and provenance

Installation

pip install crprotocol

Verify the install:

python -m crp --version
Need a specific provider?

CRP works with OpenAI, Anthropic, Google Gemini, Mistral, Cohere, Ollama, LM Studio, vLLM, and any OpenAI-compatible endpoint. Install the provider SDK you already use -- CRP does not replace it.


Level 0 -- Governance (Zero New Concepts)

Change one line and every call is governed, risk-scored, and audited.

from openai import OpenAI

client = OpenAI(
    api_key="your-provider-key",
    base_url="https://gateway.crprotocol.io/v1",
)

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[{"role": "user", "content": "Hello"}],
)

# Governance signals are attached automatically
print(response.crp.risk)       # LOW | MEDIUM | HIGH | CRITICAL
print(response.crp.grounded)   # True | False
print(response.crp.compliant)  # True | False
import crp

client = crp.Client()
response = client.complete("Summarise the EU AI Act")

print(response.crp.risk)       # LOW | MEDIUM | HIGH | CRITICAL
print(response.crp.grounded)   # True | False
print(response.crp.compliant)  # True | False

That's it

No new imports. No new concepts. Your existing code stays the same.

Understanding the .crp object

Every response carries a governance summary. Here is what each field means:

Field Type Meaning
risk str Overall risk level: LOW, MEDIUM, HIGH, CRITICAL
grounded bool Whether the response is anchored to provided context
compliant bool Whether the response passes configured safety policies
fabrications int Number of unsupported claims detected
chain_valid bool Whether the audit chain is intact
injection_detected bool Whether prompt-injection patterns were found
pii_detected bool Whether personal data was detected in output
safety_budget_remaining float Remaining safety budget (0.0--1.0)
Handle high-risk responses
response = client.complete("Generate a medical diagnosis")

if response.crp.risk == "CRITICAL":
    raise ValueError("Critical risk detected -- human review required")

if not response.crp.grounded:
    print("Warning: response is not grounded in provided documents")

Level 1 -- Quality (One New Concept: "knowledge")

Give CRP your documents, then ask questions with grounded, coherent answers.

import crp

client = crp.Client()

# Ingest documents, directories, URLs, or raw strings
client.ingest("./docs/")
client.ingest("https://example.com/spec.pdf")

# Ask questions -- CRP retrieves, reasons, and cites sources
answer = client.ask("Write a deployment guide")

print(answer.text)                     # The generated response
print(answer.quality)                  # S | A | B | C | D
print(answer.complete)                 # Did it cover the whole task?
print(answer.sources)                  # [{title, doc_id, used_facts, relevance_score}]

Source attribution

Each source tells you exactly where the information came from:

for src in answer.sources:
    print(f"{src.title} (relevance: {src.relevance_score:.2f})")
    print(f"  Used {src.used_facts} facts from doc {src.doc_id}")

What happens behind the scenes

ask() runs the full CRP quality pipeline invisibly: 1. CDR -- Contextual Document Retrieval finds relevant chunks 2. CDGR -- Cross-Document Graph Reasoning connects facts across sources 3. STL -- Semantic Topic Labelling positions the query in knowledge space 4. Continuation -- Multi-turn coherence maintenance 5. Verification -- Grounding check against source documents


Level 2 -- Control

Depth control

Control how thorough the response should be:

# quick | standard | thorough | exhaustive
answer = client.ask("Explain transformers", depth="thorough")
Depth Use when Typical latency
quick Simple FAQs, low stakes Fast
standard General tasks (default) Normal
thorough Complex analysis, research Slower
exhaustive Critical decisions, compliance Slowest

Tool registration

Register Python functions as tools. CRP can call them automatically when needed.

@client.tool
def search_docs(query: str) -> str:
    """Search internal documentation."""
    return vector_db.search(query)

@client.tool
def get_metrics(service: str) -> dict:
    """Get service health metrics."""
    return monitoring.get(service)

# CRP may call search_docs("auth service") automatically
answer = client.ask("What does our auth service do?")

Reasoning transparency

Inspect how the answer was built:

answer = client.ask("Should we use microservices?")

print(answer.how_it_was_built)   # STL operation sequence
print(answer.open_questions)     # Gaps identified
print(answer.decisions)          # Trade-offs made by the CSO
Use this for compliance documentation

how_it_was_built and decisions give you an audit-ready explanation of why the model produced a specific output. Save these for regulatory evidence packs.


Configuration

CRP loads crp.config.yaml automatically if it exists in the working directory.

# crp.config.yaml
provider:
  name: openai
  api_key: ${OPENAI_API_KEY}

safety:
  profile: balanced
  halt_on_critical: true
  grounding_threshold: 0.8

audit:
  destination: comply.crprotocol.io
  webhook_secret: ${WEBHOOK_SECRET}

context:
  mode: full
  max_sources: 10

Environment variable substitution

Values prefixed with ${} are resolved from environment variables at load time.

Safety profiles

Profile Description Best for
permissive Minimal intervention Internal tools, low-risk domains
balanced Default protection Most production workloads
strict Halt on MEDIUM+ risk Financial, legal, high-stakes
medical HIPAA-aligned Healthcare applications
financial SOX-aligned Banking, trading, accounting

Override per-request:

client = crp.Client(safety="strict")
# or
response = client.complete("...", safety="medical")

Session Persistence

CRP sessions survive restarts. Pass a session handle to resume context:

import crp

client = crp.Client()

# Start a session
response = client.complete("My name is Alice")
session_id = client.session.id  # Save this

# Later -- or in another process
client2 = crp.Client(session=session_id)
response2 = client2.complete("What is my name?")
# "Alice" -- context is preserved

Session storage

By default sessions are in-memory. For production, configure Redis or PostgreSQL in crp.config.yaml.


Streaming

Stream responses for real-time UIs:

import crp

client = crp.Client()

for chunk in client.complete("Tell me a story", stream=True):
    print(chunk.text, end="", flush=True)
    if chunk.crp.risk == "CRITICAL":
        print("\n[HALTED -- critical risk detected]")
        break

Each chunk carries partial governance signals, so you can interrupt mid-generation if risk escalates.


Multi-turn Conversations

Build conversational agents with persistent context:

import crp

client = crp.Client()

# Turn 1
r1 = client.ask("What is the EU AI Act?")
print(r1.text)

# Turn 2 -- context is automatic
r2 = client.ask("What are the penalties for non-compliance?")
print(r2.text)

# Turn 3 -- references earlier turns
r3 = client.ask("How does that compare to GDPR fines?")
print(r3.text)

CLI

The crp CLI provides governance tools without writing code:

# Scan a codebase for ungoverned AI calls
python -m crp scan --paths ./src --format sarif

# Validate a configuration file
python -m crp validate crp.config.yaml

# Run benchmarks
python -m crp benchmark --suite conformance

# Export audit trail
python -m crp audit --session <id> --format json

See the CLI Guide for full reference.


Error Handling

CRP uses graceful degradation. If a safety check fails, you get a governed response instead of a raw exception:

import crp

client = crp.Client()

response = client.complete("Generate a medical diagnosis")

if response.finish_reason == "error":
    print("Dispatch failed -- check logs")
    print(f"Risk level: {response.crp.risk}")
else:
    print(response.text)

Always check .crp.risk

Even when finish_reason is stop, the response may be HIGH or CRITICAL risk. Your application logic should decide whether to show, flag, or block the output.


Next Steps


API Reference

crp.Client

class CRPClient:
    def __init__(
        self,
        provider: LLMProvider | None = None,
        config: CRPConfig = CRPConfig(),
        safety: str | dict = "balanced",
        depth: str = "auto",
    )

Methods

Method Level Description
complete(prompt, ...) 0 Single-turn completion with governance
ask(question, ...) 1 Multi-turn quality-aware query
ingest(path) 1 Ingest documents into CKF
tool(fn) 2 Decorator to register a callable tool
call_tool(name, ...) 2 Execute a registered tool

Response Types

CRPCompletionResponse (Level 0) - text: str -- Generated text - crp: CRPResponseMeta -- Governance summary - finish_reason: str -- stop | error | halted - usage: dict -- Token counts

CRPAskResponse (Level 1--2) - All fields from CRPCompletionResponse, plus: - quality: str -- S | A | B | C | D - sources: list[SourceAttribution] -- Cited documents - complete: bool -- Whether the whole task was covered - how_it_was_built: str -- Reasoning trace - open_questions: list[str] -- Identified gaps - decisions: list[dict] -- Trade-off log

For the full progressive-disclosure specification, see SPECS_5_06_2026_CRP_v4/specs/CRP-SPEC-032-developer-experience.md.