A governed, provider-agnostic agent SDK — cost budgets, tamper-evident audit, PII redaction, context governance, and record/replay testing as the foundation, not plugins. The second door to the Cendor stack.
Project description
cendor-sdk
A governed agent in 10 lines — cost budgets, tamper-evident audit, and PII redaction built in.
provider-agnostic · local-first · offline by default · sync and async
The only agent SDK where cost budgets, tamper-evident audit, PII redaction, context governance, and record/replay testing are the foundation, not plugins.
cendor-sdk owns the agent loop, so every governance concern that is best-effort beneath a
framework becomes first-class here: usage is never lost, budgets enforce before the model call,
PII is redacted before send, and the whole run correlates under one trace_id. It's the simple,
batteries-included door into the Cendor stack — you don't need
to pick a framework or wire the libraries. (Already have a framework? Compose the libraries beneath
it: pip install cendor-libs.)
Install
pip install "cendor-sdk[openai,anthropic]" # provider SDKs are optional extras
pip install "cendor-sdk[all]" # every provider + interop, batteries included
The install bundles the whole Cendor stack (cendor-core, tokenguard, acttrace, contextkit,
squeeze, cassette) by dependency — you install once and import only from cendor.sdk. Provider
SDKs stay optional extras: [openai], [anthropic], [google], [bedrock], [ollama],
[huggingface], [azure], [foundry-local], plus [mcp] and [otel].
A governed agent in 10 lines
from cendor.sdk import Agent, tool, run, budget, guard, Policy, AuditLog
@tool
def get_weather(city: str) -> str:
"""Current weather for a city."""
return f"Sunny in {city}"
agent = Agent(name="assistant", model="gpt-4o", tools=[get_weather],
instructions="Answer using tools when helpful.")
log = AuditLog(system="support", risk_tier="limited", path="audit.jsonl")
with budget(usd=0.25, on_exceed="block"), guard(Policy.default(), audit=log):
result = run(agent, "What's the weather in Paris?", audit=log)
print(result.output) # -> "It's sunny in Paris."
print(result.cost, result.usage) # priced in Decimal, budgeted
print([s.name for s in result.tool_steps]) # -> ["get_weather"]
# audit.jsonl: audit_open -> decision -> llm_call -> tool_call -> llm_call, hash-chained &
# verify()-able, all correlated by one trace_id. Wrap in cassette.using("run.json") to replay it.
Ungoverned still works — on cendor-core alone. Every governance layer is optional and
removable; drop the with block and run(agent, ...) runs bare:
from cendor.sdk import Agent, run
result = run(Agent(name="a", model="gpt-4o", instructions="Be brief."), "Hi")
result = await run.aio(agent, "Hi") # same call, async
Why it's different
| Provider lock | Cost budgets | Tamper-evident audit | PII redaction | Record/replay tests | Local-first | |
|---|---|---|---|---|---|---|
| OpenAI Agents SDK | OpenAI-centric | ✗ | ✗ | ✗ | ✗ | lib |
| LangGraph | agnostic | DIY | DIY | DIY | DIY | lib |
| Anthropic Agent SDK | Anthropic-centric | ✗ | ✗ | ✗ | ✗ | lib |
| CrewAI / Pydantic AI / ADK | varies | ✗/DIY | ✗ | ✗ | ✗ | lib |
| cendor-sdk | agnostic | built-in | built-in | built-in | built-in | yes |
Governance is composed through Cendor's existing bus / interceptor / Sink / Compressor
seams, correlated by trace() — zero SDK-specific glue. Budgets, audit, redaction, and
record/replay all ride the agent loop through those seams, so removing any one is just not entering
its context.
Multi-agent, one correlated tree
Handoff, supervisor/router, and sequential/parallel pipelines — with the correlation that was
impossible beneath frameworks. A whole multi-agent run is one governed, trace_id-correlated
tree, on one verifiable audit chain. Handoff even works across providers:
from cendor.sdk import Agent, run
writer = Agent(name="writer", model="claude-opus-4-8", instructions="Write the brief.")
planner = Agent(name="planner", model="gpt-4o", instructions="Plan, then hand off.",
handoffs=["writer"])
result = run([planner, writer], "Research X and write a brief") # OpenAI -> Anthropic handoff
print(result.agents) # ["planner", "writer"]
Every major provider — one canonical loop
The provider is inferred from the model id (override with provider=). History is held in one
canonical shape, so a run can hand off between providers without rewriting it.
| Provider | Models | Extra |
|---|---|---|
| OpenAI | Chat Completions + Responses API | [openai] |
| Anthropic | Messages API | [anthropic] |
| Google Gemini | google-genai |
[google] |
| AWS Bedrock | Converse API | [bedrock] |
| Ollama | local models | [ollama] |
| Hugging Face | Inference / endpoints | [huggingface] |
| Azure AI Foundry | deployments via the OpenAI v1 endpoint (Chat + Responses) | [azure] |
| Foundry Local | on-device, OpenAI-compatible | [foundry-local] |
More in the box
Everything a real agent needs — all governed through the same seams:
- Streaming —
run.stream/run.astreamyield text deltas + tool events (native for the OpenAI family + Ollama). - Structured output — a dataclass / Pydantic / JSON-schema
output_typeuses each provider's native schema mode. - Reasoning & control —
Agent.extrapassestool_choice,reasoning_effort,top_p,stop, …; o-seriestemperatureis handled for you. - RAG —
VectorIndex+Agent(retriever=…)inject governed retrieval, or expose your store as a@tool. - Memory —
Session(conversation),SummarizingSession(rolling summary),SQLiteSessionStore(durable),context_budget(fit the window). - Embeddings —
embed()/aembed()capture RAG calls on the same cost/audit tree. - Cost governance for any model —
register_model_price(...)so budgets bind on custom / deployment-named ids.
Docs
- Quickstart & reference
- Multi-agent orchestration
- Interop — MCP, A2A, Foundry, OTel, HITL
- Production hardening · Governed eval
- Runnable, network-free examples
- Changelog
License
Apache-2.0.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cendor_sdk-1.1.0.tar.gz.
File metadata
- Download URL: cendor_sdk-1.1.0.tar.gz
- Upload date:
- Size: 106.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b7efa54583795061e354048698a43b6f2854859483f8a26aef8ff3ff65dd6449
|
|
| MD5 |
1bfa2dfe000742d4f29d6f1b9a5911bb
|
|
| BLAKE2b-256 |
be582ad6c2a0d4fb1fc379a8f7523061bffaa62fdc522c5fb030230a998620e4
|
Provenance
The following attestation bundles were made for cendor_sdk-1.1.0.tar.gz:
Publisher:
release.yml on cendorhq/cendor-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cendor_sdk-1.1.0.tar.gz -
Subject digest:
b7efa54583795061e354048698a43b6f2854859483f8a26aef8ff3ff65dd6449 - Sigstore transparency entry: 2083059166
- Sigstore integration time:
-
Permalink:
cendorhq/cendor-sdk@ff49e3365d7ab9796b66b46694ea393c813532e9 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/cendorhq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ff49e3365d7ab9796b66b46694ea393c813532e9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cendor_sdk-1.1.0-py3-none-any.whl.
File metadata
- Download URL: cendor_sdk-1.1.0-py3-none-any.whl
- Upload date:
- Size: 64.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bf61a2ef429c29d3fd126b1bbf4d1b6aecb403eb72e6e6d15a8b38253e41290b
|
|
| MD5 |
dca63adc08267bf38ed6d10aea03f670
|
|
| BLAKE2b-256 |
7a5231700a424d03d87585c4e33b4a6b76b5c933db17351932411838a989904e
|
Provenance
The following attestation bundles were made for cendor_sdk-1.1.0-py3-none-any.whl:
Publisher:
release.yml on cendorhq/cendor-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cendor_sdk-1.1.0-py3-none-any.whl -
Subject digest:
bf61a2ef429c29d3fd126b1bbf4d1b6aecb403eb72e6e6d15a8b38253e41290b - Sigstore transparency entry: 2083059172
- Sigstore integration time:
-
Permalink:
cendorhq/cendor-sdk@ff49e3365d7ab9796b66b46694ea393c813532e9 -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/cendorhq
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ff49e3365d7ab9796b66b46694ea393c813532e9 -
Trigger Event:
push
-
Statement type: