Governance in the SDK

Observe vs govern, trace evidence, and runtime policy enforcement.

Traccia SDKs support two levels of governance: trace evidence (works with any OTLP backend) and runtime policy enforcement (requires the Traccia platform).

observe vs govern

APIPurposeTraccia platform
observeObservability onlyNot required
governObservability + runtime policy checkRequired

Platform requirement

govern talks to the Traccia API. Get your API key from app.traccia.ai. Open-source or tracing-only setups should use observe.

This call vs the next wrap

Spend Cap, Model Boundary, Loop Cap, Refund Guard, Purchase Guard, High-Risk Tool, Dangerous Shell Commands, Freshness Guard, Retrieval Completeness, Unique Customer Cap, and Prompt Pin are Preventive: Block denies or reshapes this LLM or tool call under govern. Spend Cap and Model Boundary also apply when traffic uses the Gateway instead of the SDK. Tool guards, Freshness Guard, Retrieval Completeness, Unique Customer Cap, and Prompt Pin are SDK only. Observe and Warn still let the call through and record a match. Detective templates (Cost Spike, Tool Call Count, and similar) still arm the next wrap. Ingest never rejects a trace. Policy setup: Policies.

Runtime Policy: Govern

Wrap the agent entry point with govern. Auto-instrumented model calls and tool-typed observe wrappers are checked on this call. Spend Cap, Model Boundary, and Loop Cap need nothing else. Refund Guard, Purchase Guard, High-Risk Tool, and Dangerous Shell Commands are the same wrapper on a named tool. Their worked examples are Cap Refunds And Purchases and Stop A Dangerous Tool. Four policies need one extra field. Those snippets are in What The SDK Must Send. What each rule does is on Policies. Set the agent ID on init (or TRACCIA_AGENT_ID). Pass agent_id on govern only to override in a multi-agent process. Credentials are the same as tracing: TRACCIA_API_KEY, TRACCIA_ENDPOINT, TRACCIA_AGENT_ID. API key from app.traccia.ai only.

agent.py
python
from traccia import init, govern
from traccia.governance import AgentBlockedError
init(api_key="...", endpoint="https://api.traccia.ai/v2/traces", agent_id="support")
@govern(fail_open=False, name="run_agent")
def run_agent(prompt: str) -> str:
return call_llm(prompt)
try:
run_agent("hello")
except AgentBlockedError as exc:
print(exc.decision_id, exc.remaining_budget_usd, exc.reasons)

AgentBlockedError is a readable message (reason, remaining budget when relevant, decision id). Python fields: decision_id, remaining_budget_usd, reasons. TypeScript: decisionId, remainingBudgetUsd, reasons. fail_open=True (default) lets the agent continue if Traccia is unreachable. Optional explicit check_policy() / checkPolicy() exists for custom tools. It is not required on the default path.

Approval Pending

When Refund Guard or Purchase Guard holds a tool for a person, the SDK raises ApprovalPending. It is a different error from AgentBlockedError, because the call is not denied. It is waiting. It needs Python SDK 0.1.32 or TypeScript SDK 0.1.18 or later.

  • Catch it where your agent calls the tool.
  • Do not run the tool, and do not ask Traccia again.
  • Return the pending result so the model can tell the user the request is waiting.
  • Traccia does not resume the agent after someone approves.
  • Update to an SDK that has this error before you turn Ask For Approval on. An older SDK would let the tool run.
bash
from traccia.governance import ApprovalPending, pending_tool_result
try:
return issue_refund(amount=amount)
except ApprovalPending as exc:
return pending_tool_result(exc)

These snippets assume the money function is already instrumented as a tool inside a governed agent. For setup, exact band boundaries, signed delivery, and execution reports, see Approve A Refund Or Purchase. Current per-call policy checks allow execution on network or HTTP errors, even when the agent-status check uses fail_open=False or failOpen: false.

What The SDK Must Send

These four snippets sit inside the govern function above. Each one is the only extra field that policy reads. What each policy does, including the skip cases, is on its own page under Policies.

Freshness Guard

Return as_of or updated_at from the read tool you named on the policy. The write tool is checked after that. What Block does.

freshness.py
python
from traccia import observe
@observe(name="get_refund_policy", as_type="tool")
def get_refund_policy() -> dict:
return {"text": "Refunds within 30 days.", "as_of": "2026-09-24T08:00:00+00:00"}
@observe(name="issue_refund", as_type="tool")
def issue_refund(order_id: str, amount: float) -> dict:
return {"ok": True, "order_id": order_id, "amount": amount}

Retrieval Completeness

Set the retrieval attributes on the search span before the model call in the same trace. Leave the count off the span when you did not count chunks. What Block does.

retrieval.py
python
from traccia import observe
@observe(
name="search_docs",
as_type="tool",
attributes={
"traccia.retrieval.present": True,
"traccia.retrieval.chunk_count": 4,
},
)
def search_docs(query: str) -> dict:
return {"query": query}

Unique Customer Cap

Pass customer.id on the lookup arguments. The raw id is hashed before it is stored. What Block does.

customer.py
python
from traccia import observe
@observe(name="get_customer", as_type="tool")
def get_customer(customer: dict) -> dict:
return {"ok": True}
get_customer(customer={"id": "cust-alice"})

Prompt Pin

Compile the Traccia prompt inside govern, then make the model call. A string you wrote in code has no label, so Prompt Pin skips it. Prompt loading is documented on Prompts. What Block does.

prompt_pin.py
python
from traccia import govern, load_prompt
@govern(fail_open=False, name="answer")
def answer() -> str:
text = load_prompt("refund-policy", label="production").compile()
return call_llm(text)

Trace Evidence: Disclosure

Record EU AI Act Art. 50 transparency on the active span after your UI shows an AI notice. Works with observe. No platform policy API involved.

python
from traccia.governance import disclosure
disclosure(channel="ui", disclosed_to_user=True)

HIPAA-oriented init

Opt into HIPAA-oriented span attributes and prefer redaction when agents may touch ePHI. Soft warnings only. The SDK does not block PHI. Traccia does not currently offer a signed BAA. Platform workflow: HIPAA Controls for AI Agents.

python
from traccia import init, observe
init(
compliance={"frameworks": ["hipaa"]},
redact_pii=True,
)
@observe()
def clinical_assistant(user_message: str) -> str:
return f"Acknowledged: {user_message[:200]}"

Advanced: custom policy endpoints

Only needed for non-standard deployments. Defaults: {base}/api/v1/agents/{agent_id}/status and .../blocks.

traccia.toml
toml
[governance]
status_check_endpoint = "https://custom.example/agents/{agent_id}/status"
post_block_endpoint = "https://custom.example/agents/{agent_id}/blocks"
status_cache_ttl_seconds = 120

Next Steps

© 2026 Traccia.