Getting started

Install the SDK, run one governed agent, and learn where each concept lives. Ten minutes, one API key (or none — the ungoverned example works offline with a recorded cassette).

1. Install

pip install "cendor-sdk[openai,anthropic]"

Provider SDKs are optional extras — [openai], [anthropic], [google], [bedrock], [ollama], [huggingface], [azure], [foundry-local], plus [mcp], [otel], and [all]. The install bundles the whole Cendor stack by dependency; import only from cendor.sdk.

npm i @cendor/sdk openai

Provider SDKs are peer dependencies — add openai and/or @anthropic-ai/sdk for the providers you call. ESM-only; Node LTS first, edge runtimes supported. Everything imports from @cendor/sdk.

2. A governed agent in 10 lines

One agent, one tool, and all four governance layers — budget cap, PII guard, audit chain, and a cost/usage receipt:

from cendor.sdk import Agent, tool, run, budget, guard, Policy, AuditLog

@tool
def get_weather(city: str) -> str:
    """Current weather for a city."""      # schema derived from type hints + docstring
    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)                        # the final answer
print(result.cost, result.usage)            # Decimal money, real token usage
print([s.name for s in result.tool_steps])  # ["get_weather"]
import { Agent, tool, run, withBudget, guard, Policy, AuditLog } from '@cendor/sdk';
import { z } from 'zod';

const getWeather = tool(({ city }) => `Sunny in ${city}`, {
  name: 'get_weather',
  description: 'Current weather for a city',
  parameters: z.object({ city: z.string() }),   // TS has no runtime type hints — zod is the schema
});

const agent = new Agent({ name: 'assistant', model: 'gpt-4o', tools: [getWeather],
                          instructions: 'Answer using tools when helpful.' });

const audit = new AuditLog('support', { riskTier: 'limited', path: 'audit.jsonl' });
const result = await withBudget({ usd: 0.25, onExceed: 'block' }, () =>
  guard({ policy: Policy.default(), audit }, () =>
    run(agent, "What's the weather in Paris?", { audit })));

console.log(result.output);                          // the final answer
console.log(result.cost?.toString(), result.usage);  // decimal money, real token usage
console.log(result.toolSteps.map((s) => s.name));    // ["get_weather"]

What each line buys you:

  • @tool / tool(...) — the JSON Schema comes from type hints + docstring (Python) or a zod schema (TS); it’s formatted per provider automatically.
  • budget(usd=0.25, on_exceed="block") — a pre-flight cap: the over-budget call never runs.
  • guard(Policy.default(), ...) — PII is redacted before the provider sees it.
  • AuditLog(...) — every model and tool call lands in a tamper-evident hash chain (verify("audit.jsonl") checks it offline).
  • result.cost — decimal money, never a float, aggregated across the whole run.

3. Run it ungoverned — core only

Every governance layer is optional. Drop the wrappers and it’s a bare loop on cendor-core:

from cendor.sdk import Agent, run

agent = Agent(name="a", model="gpt-4o", instructions="Be brief.")
result = run(agent, "Hello")               # sync
result = await run.aio(agent, "Hello")     # async — same signature
import { Agent, run } from '@cendor/sdk';

const agent = new Agent({ name: 'a', model: 'gpt-4o', instructions: 'Be brief.' });
const result = await run(agent, 'Hello');   // TS is async throughout

4. Make it testable

Record the run once; replay it offline forever — deterministic, no network, no keys. Cost and tokens are real on replay, so tests can assert spend too:

from cendor import cassette

with cassette.using("tests/fixtures/run.json"):   # records on first run, replays after
    result = run(agent, "What's the weather in Paris?")
import { using } from '@cendor/cassette';

const result = await using('tests/fixtures/run.json', () =>   // records once, replays after
  run(agent, "What's the weather in Paris?"));

This is the foundation of the eval harness, which turns recorded trajectories into CI regression tests.

5. Where each concept lives

I want to…Go to
Understand Agent, tool, run, ResultAgents & the loop
Cap spend, attribute cost, audit, redactGovernance
Make the agent remember across turns/processesMemory & sessions
Give the agent my documentsRetrieval (RAG)
Use more than one agentMulti-agent
Connect Gemini / Bedrock / Ollama / Hugging Face / AzureProviders
Consume MCP tools, serve A2A, emit OTel spansEcosystem & interop
Survive crashes, retries, long runsProduction hardening
Gate regressions in CIEval & regression testing

Coming from the libraries? Everything you already use — budget, track, guard, Policy, AuditLog, trace — is the same object here, re-exported for one-import convenience. Nothing to relearn. The reverse also holds: see FAQ → libraries or SDK.