OpenAI Agents SDK
Wire Checkrd into the OpenAI Agents SDK via TracingProcessor and Guardrail.
OpenAI Agents SDK (Python)
The OpenAI Agents SDK splits its extension surface into two layers, and Checkrd targets both:
- Tracing processors — receive
on_trace_*andon_span_*events for observability. Cannot abort a run. - Guardrails — run before / after the model invocation and can
tripwirethe agent to abort.
CheckrdTracingProcessor handles observability. CheckrdInputGuardrail and CheckrdOutputGuardrail handle enforcement.
Install
pip install 'checkrd[openai-agents]'Quickstart
from agents import Agent, Runner, add_trace_processor
from checkrd import Checkrd
from checkrd.integrations.openai_agents import (
CheckrdInputGuardrail,
CheckrdTracingProcessor,
)
with Checkrd(policy="policy.yaml") as client:
# 1. Wire telemetry. Does NOT enforce — observation only.
add_trace_processor(CheckrdTracingProcessor.from_checkrd(client))
# 2. Wire enforcement on each agent.
agent = Agent(
name="research-agent",
instructions="Summarize tomorrow's calendar.",
input_guardrails=[CheckrdInputGuardrail.from_checkrd(client).as_guardrail()],
)
result = Runner.run_sync(agent, "Tomorrow's calendar")
print(result.final_output)Why two adapters
The Agents SDK's tracing processor is observation-only by design — it cannot abort a run. Trying to enforce from a tracing processor would break in the next minor version. Guardrails are the explicit enforcement seam.
The split lets you wire telemetry once globally (so the OpenAI traces dashboard keeps working) and add enforcement per-agent based on each agent's threat model.
Output guardrails
Use CheckrdOutputGuardrail when the agent's output (not just input) needs policy filtering — for example, blocking refusal-bypass attempts or schema-validating tool outputs:
agent = Agent(
name="bot",
output_guardrails=[CheckrdOutputGuardrail.from_checkrd(client).as_guardrail()],
)Both guardrails share the same options interface (engine, agent_id, sink, enforce, dashboard_url).
What gets enforced
Each guardrail produces a synthetic URL the policy engine matches against:
| Guardrail | Synthetic URL | Body |
|---|---|---|
CheckrdInputGuardrail | https://openai-agents.local/input/{agent_name} | {"input": ...} |
CheckrdOutputGuardrail | https://openai-agents.local/output/{agent_name} | {"output": ...} |
Example policy:
agent: research-agent
default: allow
rules:
- name: deny-pii-extraction
deny:
url: "openai-agents.local/input/*"
body:
input: "*ssn*|*social security*|*credit card*"Tracing event shapes
The processor emits one telemetry event per span. The kind field comes from the span's span_data type:
| Span kind | Source | Extra fields |
|---|---|---|
generation | GenerationSpanData | target (model), input_tokens, output_tokens |
function | FunctionSpanData | target (function name) |
agent | AgentSpanData | target (agent name) |
handoff | HandoffSpanData | target (target agent) |
guardrail | GuardrailSpanData | target (tripwire flag) |
mcplisttools | MCPListToolsSpanData | target (server) |
Trace correlation: request_id is the span's trace_id, span_id is span.span_id, parent_span_id is span.parent_id.
Observation-only mode
For a deny-but-don't-block rollout, set enforce=False:
guard = CheckrdInputGuardrail(
engine=engine,
agent_id="research",
sink=sink,
enforce=False,
)The guardrail returns tripwire_triggered=False even on policy deny. The deny is logged and emitted as a *_denied telemetry event, so dashboards show what would have been blocked.
Caveats
- Package name confusion. PyPI:
openai-agents. Import:agents. (Notopenai_agents.) shutdown()andforce_flush()are mandatory on aTracingProcessor. We implement them — you do not need to.- Guardrail functions are async even when the agent is sync. The SDK runs them on the agent's loop.
- The Agents SDK ships its own OpenAI traces dashboard. Use
add_trace_processor()(additive) instead ofset_trace_processors()(replaces) so you keep both.