Wrap your client once.
Everything else plugs in.
Six small, composable libraries for the layer beneath your agent framework — context, cost, testing, and audit. Each works alone; together they ride one event bus with zero per-call wiring. In Python and TypeScript.
from cendor.core import instrument from cendor.tokenguard import budget client = instrument(OpenAI()) # ← the one line you change @budget(usd=0.50, on_exceed="block") def answer(q): # over-budget call never runs return client.responses.create(model="gpt-4o", input=q)
from cendor.core import instrument from cendor.acttrace import AuditLog client = instrument(Anthropic()) # same seam, any provider audit = AuditLog(system="loan_triage") # auto-subscribes to the bus resp = client.messages.create(model="claude-sonnet-4-6", ...) audit.export("evidence.jsonl", framework="eu_ai_act")
from cendor.core import instrument from cendor import cassette llm = ChatOpenAI(client=instrument(OpenAI()).chat.completions) @cassette.use("tests/agent_run.json") # record once… def test_agent(): # …replay forever, offline assert "refund" in my_chain.invoke(query)
One stack. Two doors.
Start beneath your framework with the libraries, or start governed with the SDK — same flat cendor.* / @cendor/* namespace, drop between them anytime.
Bring governance to your stack
Six composable primitives that plug in under LangChain, LlamaIndex, or any SDK — context, cost, testing, governance.
Or start governed
cendor-sdk: a governed agent in 10 lines — budgets, tamper-evident audit, PII redaction, and replay as the foundation. Built on the six libraries.
Frameworks decide what your agent does.
They don't handle what happens underneath.
The context window fills up, and naive truncation drops exactly the wrong things.
contextkit + squeezeA looping agent quietly burns real money — and you can't say which feature or user spent it.
tokenguardEvery run hits a paid, non-deterministic API. No fast tests, no CI, just vibes.
cassetteWhen something goes wrong — or a regulator asks — you can't show what the agent saw, did, or refused.
acttraceOne seam, many listeners.
Every tool that needs to see an LLM call usually monkey-patches your client — stack three and they fight. Cendor makes interception a single shared primitive.
OpenAI (Chat + Responses), Anthropic, Hugging Face, Bedrock, Gemini, Ollama — detected by shape, so new models work the day they ship. Sync, async, streaming.
Budgets, recording, and audit subscribe — none patches your client, none imports another. Adding a library is free at the call site.
Managed runtimes emit OpenTelemetry gen_ai spans — feed them to otel.ingest() and the same tools keep working.
The mark is the architecture — one hub, many listeners.
Your framework stays. Cendor works above and below it.
One call, start to finish — what's yours, what's Cendor, and the single seam where they meet. You wrap the client once; every step after is automatic, over the bus.
Your user, app, or system sends a request.
LangChain · OpenAI Agents SDK · LlamaIndex — or no framework at all.
Pack the prompt into the token budget; oversized blocks compressed, reversibly.
Wrapped with instrument_tool(), so tool calls join the same stream.
Blocks or downgrades an over-budget call before a token is spent.
guard()Detects secrets & PII and, per your policy, blocks the call or redacts them before send — recorded on the tamper-evident chain.
Every call is normalized and published to the event bus. One wrap, many listeners — no tool patches your client, none imports another.
Records spend by feature and user; costs labeled reported vs estimated.
Records the run — replay it in tests, offline and deterministic.
Appends to the tamper-evident log: calls, costs, context decisions, and what the policy flagged or refused.
Any OpenTelemetry backend via core.otel — or ingest a managed runtime's spans back onto the bus.
The response — budgeted, scrubbed, recorded, and audited, with your code unchanged.
The dependency graph is a star, not a web — adding a library is free at the call site. See the full architecture →
Six libraries. One problem each.
Install one, or the whole stack — every tool stands alone and pulls only cendor-core.
Pack prioritized blocks into a token budget, evict by rule — and get a receipt of what was kept, shrunk, or dropped.
Content-aware, deterministic compression for JSON, logs, code, and prose — byte-for-byte reversible. No LLM involved.
Block or downgrade an over-budget call before it runs; attribute every dollar per feature and per user, for free.
Record a whole run once — LLM and tool calls — then replay it offline, deterministically, forever. No API key.
Detect secrets & PII offline and block or redact them in one line — then prove every decision in a tamper-evident log, with evidence packs for EU AI Act, ISO 42001, GDPR, and NIST AI RMF.
Shared types, token counting, offline prices, the instrument() seam, and the event bus every tool rides.
Every number regenerates offline.
token-count error vs the real tokenizer (OpenAI, with tiktoken)
smaller logs — compressed reversibly, restored byte-for-byte
instrument() overhead per call — bus emit, usage, Decimal pricing
a single edited byte breaks the audit chain — verify() fails
Reproduce every figure — no network, no API keys: uv run python benchmarks/run_all.py
Token counts report which method produced them. Costs are labeled reported vs estimated, in exact Decimal — never float. And acttrace produces evidence to support compliance, never a guarantee. No marketing math, and the limits are documented next to the features.
Your framework stays. Add the plumbing.
or just one piece: pip install cendor-tokenguard · then the 5-minute quickstart →