SDK Guide¶
Complete SDK reference
For the canonical interface map covering every public method and return field, see the SDK Reference. This guide is task-oriented; the reference is the authoritative surface documentation.
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¶
Verify the install:
Need a specific provider?
CRP works with OpenAI, Anthropic, Google Gemini, Mistral, Cohere, Ollama, LM Studio, vLLM, TGI, 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://your-gateway.example/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
Gateway availability
Managed cloud at gateway.crprotocol.io is on the waitlist. You can also self-host the Gateway runtime.
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) |
session_id | str | Stable session identifier |
window_id | str | Turn-scoped window identifier |
Handle high-risk responses
Level 1 -- Quality (One New Concept: "knowledge")¶
Give CRP your documents, then ask questions with grounded, coherent answers.
import crp
client = crp.SDKClient()
# 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 | Behaviour |
|---|---|---|
quick | Simple FAQs, low stakes | Short answer, low token cap |
standard | General tasks | Balanced coverage |
thorough | Complex analysis, research | Higher token cap, deeper envelope |
exhaustive | Critical decisions, compliance | Continuation loop with gap analysis and stitching |
Tool registration¶
Register Python functions as tools. They are invoked automatically during complete() and ask() when the provider supports tool calling.
@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)
# Call directly
print(client.call_tool("get_metrics", "auth-service"))
# CRP invokes the tool automatically when the model asks for it
answer = client.ask("What does our auth service do?")
Tool outputs become context
Tool outputs are fed back to the model and also extracted into the warm store/CKF, so later questions in the same session can build on them.
Reasoning transparency¶
Inspect how the answer was built:
answer = client.ask("Should we use microservices?")
print(answer.how_it_was_built) # simple construction summary
print(answer.open_questions) # Gaps identified
print(answer.decisions) # Trade-offs if available
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.
Application manifest¶
Most applications already have their own provider, tool registry, RAG pipeline, or context-management strategy before CRP is introduced. Rather than discarding that work, you can hand CRP an ApplicationProfile so it discovers or is told what the application already does. CRP then:
- selects a compatible relay strategy (
push,reflexive,progressive,stream_augmented,agentic) from the profile'sContextStrategy; - resolves the right provider adapter from the profile's
ProviderKind; - emits a
CRP-Application-Context-Manifestattestation on every dispatch; - avoids duplicating existing retrieval or tool registries where possible.
Declared profile¶
from crp.core.app_profile import ApplicationProfile, ProviderKind, ContextStrategy
profile = ApplicationProfile(
framework="custom",
provider=ProviderKind.OPENAI,
provider_model="gpt-4o-mini",
context_window=128_000,
context_strategy=ContextStrategy.RAG,
)
client = crp.CRPClient(app_profile=profile)
Derived profile¶
from crp.core.app_profile import build_profile_from_messages
profile = build_profile_from_messages(
messages=[{"role": "user", "content": "Hello"}],
tools=[{"type": "function", "function": {"name": "search_docs"}}],
provider=ProviderKind.OPENAI,
context_window=128_000,
)
client = crp.CRPClient(app_profile=profile)
Strategy mapping¶
ContextStrategy | CRP dispatch path | Best for |
|---|---|---|
rag | push | Apps that already retrieve relevant chunks |
summarization | reflexive | Apps that condense old turns |
sliding_window | progressive | Apps that keep last N turns |
long_context | stream_augmented | Apps relying on a huge native window |
hybrid | agentic | Mixed strategies |
full_history / unknown | push | Default safe path |
The manifest attestation is included automatically in dispatch_router when a profile is present, so downstream evidence packs can record which application context was active for each call.
Configuration¶
CRP loads crp.config.yaml automatically if it exists in the working directory.
# crp.config.yaml
version: "4"
model:
default: gpt-4o-mini
providers:
openai:
api_key: ${OPENAI_API_KEY}
safety:
profile: balanced
context:
mode: auto
depth: auto
retrieval:
min_relevance: 0.55
audit:
enabled: true
retention_days: 90
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 | Require approval, halt on injection/PII | Financial, legal, high-stakes |
research | Informative logging, no halts | Experimentation, non-production |
Configure at init or runtime:
Session Persistence¶
The SDK maintains one session per client instance. Sequential calls share CKF state automatically.
client = crp.SDKClient()
r1 = client.complete("What is the EU AI Act?")
print(r1.crp.session_id)
s = client.session()
print(s.id, s.fact_count, s.window_count)
Cross-process persistence
Explicit crp.SDKClient(session=session_id) resurrection and durable session persistence are not implemented. Use the Gateway or orchestrator persistence APIs for cross-process state.
Streaming¶
Synchronous streaming is available via client.stream(). It yields StreamEvent objects for tokens, continuation windows, and the final summary:
for event in client.stream("Explain the CAP theorem"):
if event.event_type == "token":
print(event.data, end="", flush=True)
See the Streaming guide for full event types and examples. Async streaming (aask_stream) is not yet implemented.
Multi-turn Conversations¶
Build conversational agents with persistent context:
import crp
client = crp.SDKClient()
# 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)
No explicit chat object
Multi-turn context is shared through the client instance. Use client.session() for a live view.
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
# Start the HTTP sidecar
python -m crp serve
# Create a session, dispatch, ingest, preview envelope, status
python -m crp init
python -m crp dispatch --task "..."
python -m crp ingest --session <id>
python -m crp status --session <id>
python -m crp preview --session <id>
Commands not implemented
validate, benchmark, and audit CLI commands do not exist.
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.SDKClient()
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¶
- Quickstart -- Get running in 5 minutes
- CLI Reference -- Command-line tools
- Configuration --
crp.config.yamlreference - Error Reference -- Exceptions and remediation
API Reference¶
crp.SDKClient (alias crp.CRPClient)¶
class CRPClient:
def __init__(
self,
provider: LLMProvider | None = None,
config: CRPConfig = CRPConfig(),
safety: str | dict = "balanced",
depth: str = "auto",
model: str | None = None,
api_key: str | None = None,
)
Methods¶
| Method | Level | Description |
|---|---|---|
complete(prompt, system="...", **kwargs) | 0 | Single-turn completion with governance |
ask(question, system="...", depth=None, **kwargs) | 1 | Multi-turn quality-aware query |
ingest(path) | 1 | Ingest documents into CKF; returns None |
tool(fn) | 2 | Decorator to register a callable tool |
call_tool(name, ...) | 2 | Execute a registered tool |
session() | 2 | Live session view |
configure(**kwargs) | 2 | Runtime configuration overrides |
knowledge.* | 2 | CKF search/query/health |
storage.* | 2 | Warm-store visibility |
audit.* | 3 | Tamper-evident audit trail |
compliance.* | 3 | EU AI Act / ISO 42001 helpers |
Response Types¶
CRPCompletionResponse (Level 0) - text: str -- Generated text - crp: CRPResponseMeta -- Governance summary - finish_reason: str -- stop | error | halted - usage: dict -- Token counts - raw_headers: dict -- Raw response headers
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 -- Simple construction summary - open_questions: list[str] -- Identified gaps - decisions: list[dict] -- Trade-off log if available
For the full progressive-disclosure specification, see SPECS_5_06_2026_CRP_v4/specs/CRP-SPEC-032-developer-experience.md.