The published package remains agentcert-sdk-python for compatibility. New
code should use the Witnora class names; existing AgentCert imports remain
supported.
import os
from agentcert_sdk import WitnoraClient
witnora = WitnoraClient(
base_url=os.environ.get(
"WITNORA_BASE_URL", os.environ.get("AGENTCERT_BASE_URL", "https://witnora.com")
),
project_id=os.environ.get("WITNORA_PROJECT_ID") or os.environ["AGENTCERT_PROJECT_ID"],
api_key=os.environ.get("WITNORA_API_KEY") or os.environ["AGENTCERT_API_KEY"],
)
decision = witnora.assess_action(
externalId="purchase-order-4850",
principal={"id": "procurement-agent", "type": "agent"},
actionType="SUBMIT",
targetSystem="MockERP",
requestedPermissions=["MockERP:SUBMIT"],
amount=4850,
currency="USD",
expectedState={"status": "SUBMITTED"},
)The client uses only the Python standard library at runtime. It cannot register identities, grant permissions, or approve runtime actions. An owner or admin configures those controls in the Witnora workspace first.
Adapters emit agentcert.envelope.v0.1 without adding framework dependencies
to this package:
from agentcert_sdk.adapters import WitnoraTracingProcessor, BrowserUseAdapter, LangGraphAdapter
# LangGraph: inside `async for event in graph.astream_events(..., version="v2")`
LangGraphAdapter(witnora, agent_id="research-agent", run_id="run-42").record(event)
# OpenAI Agents SDK
processor = WitnoraTracingProcessor(witnora, agent_id="support-agent", run_id="run-43")
# add_trace_processor(processor)
# browser-use
on_step_start, on_step_end = BrowserUseAdapter(
witnora, agent_id="browser-agent", run_id="run-44"
).hooks()
# Agent(..., register_new_step_callback=on_step_end)See docs/universal-envelope.md for the
field contract and trust boundaries.
Use RunRecorder when a framework adapter is unnecessary:
from agentcert_sdk import WitnoraRunRecorder
recorder = WitnoraRunRecorder.start(
witnora,
{
"externalId": "release-42",
"kind": "release_gate",
},
)
recorder.record_event(
"onegent.outcome.verification",
payload={"expected": "SUBMITTED", "observed": "SUBMITTED", "success": True},
)
recorder.complete(status="passed")The recorder allocates an ordered sequence and trace-linked spans, sends bounded batches, and keeps a failed batch pending for an explicit retry. It is a thin assurance collector, not a general OpenTelemetry backend.
from agentcert_sdk import instrument_async_tool
query = instrument_async_tool(
recorder,
{"schemaVersion": "agentcert.capability_manifest.v0.1", "id": "data.query"},
database_sandbox.query,
tool_name="sql_query",
)The wrapper links started/completed/failed phases with one invocation ID and
uploads only redacted descriptors. See
docs/universal-agent-semantics.md.