For teams adopting Microsoft Agent Governance Toolkit

Microsoft AGT decides inside your agent. Provedit re-decides outside it, and signs the record.

Point AGT's built-in OTelLogsBackend at a Provedit OTLP endpoint and every AuditEntry lands in a hash-linked chain that an auditor can verify without trusting your agent host. AGT decides and runs in-process; Provedit re-judges and signs the record from a different trust domain. No Provedit SDK to install.

AGT v3.5.0+ · OTelLogsBackend OTLP/HTTP docs →
What AGT writes AGT: allow
// AuditLogger.log({ ... })
{
  "agentId":    "refund-bot",
  "action":     "shell.exec",
  "decision":   "allow",
  "context": {
    "cmd":      "./refund.sh 4821",
    "actor":    "alice@acme.com",
    "session":  "sess_8e2a…"
  },
  "timestamp":  "2026-05-25T14:09:42Z",
  "hash":       "3a7f…"
}
Where it ran: inside the agent
What Provedit records Provedit: needs review
seq
#128443
action
act_019e5a9e…1061e
tool
shell.exec
params
cmd="./refund.sh 4821"
agent
refund-bot
actor
alice@acme.com
agt said
allow
verdict
NEEDS REVIEW   (refund over the approved limit)
entry 0x9f3a…c81e ✓ verified prev 0x82b1…4d77

Same call, two verdicts. AGT's decision is kept on the record as a note. The final verdict comes from a separate system that the agent cannot edit.

Why a second authoritytrust-boundary

AGT is excellent at policy in-process: it sees every tool call, runs your governance rules, and writes an audit entry. The risk it cannot reduce on its own is the agent host. If that host is compromised, every audit entry it writes is suspect, including the one that says the audit passed.

Provedit is the second authority. It receives the AGT entry over the network, evaluates its own policy against it, and writes both verdicts to an append-only, hash-linked chain that lives in a different trust domain. AGT decides and runs in-process; Provedit re-judges and records after the fact. The pair on the chain, signed by a system the agent host cannot rewrite, is the evidence. Disagreements are the alert.

01

Tool call

Agent invokes shell.exec or any governed tool.

Auth: agent

02

AGT decides

In-process policy returns allow, deny, or require_approval.

Auth: agent host

03

AGT emits OTel logs

OTelLogsBackend writes one LogRecord per entry. Your Collector ships them.

Auth: collector

04

Provedit re-decides

Server-side policy stamps the authoritative verdict.

Auth: Provedit

05

Chain & verify

Hash-linked, Merkle-anchored, verifiable offline.

Auth: auditor

Wire it inno Provedit SDK

AGT v3.5.0 shipped OTelLogsBackend: a built-in audit backend that emits every AuditEntry as an OpenTelemetry LogRecord. Register it once, point your Collector at Provedit's OTLP endpoint, and you're done. The integration surface is OTel, not us.

01 · Attach the OTel backend to AGT python
from agent_os.audit_logger import GovernanceAuditLogger
from agent_os.audit_logger.otel import OTelLogsBackend

audit = GovernanceAuditLogger()
audit.add_backend(OTelLogsBackend())  # reads OTEL_* env
02 · Point your OTel Collector at Provedit otel-collector-config.yaml
exporters:
  otlphttp/provedit:
    endpoint: https://api.provedit.ai/otlp
    encoding: json          # v1 is JSON-only; protobuf on request
    headers:
      Authorization: "Bearer ${PROVEDIT_API_KEY}"

service:
  pipelines:
    logs:
      exporters: [otlphttp/provedit]

No Provedit code in your agent. AGT does the sending (PR #1747); we receive. If you prefer not to run a Collector, AGT's OTLP exporter can post directly to https://api.provedit.ai/otlp/v1/logs. When you create the agent key, pick agt.observe if you only want a tamper-evident record, or provedit.mcp.default if you want the second opinion shown in the example above. Full integration reference →

What gets senton the wire

AGT's OTelLogsBackend emits one OpenTelemetry LogRecord per audit entry. Provedit decodes the agt.* attribute namespace and the JSON-encoded AuditEntry body. Nothing is silently dropped. Unknown attributes are preserved verbatim under params._agt.meta.

tool, toolVersion, params AGT → Provedit
From attribute governance.action and the AuditEntry body's context. Become first-class fields on the chain entry, queryable in the timeline.
actor, sessionId, requestedAt AGT → Provedit
From agent.id, agt.audit.meta.session_id, and the LogRecord's observedTimeUnixNano. Power the eight identity-rooted views in the console.
params._agt.decision AGT hint
AGT's verdict (allow, deny, require_approval) from attribute governance.decision. Recorded under _agt as a hint. Never elevated to the top-level verdict. Provedit re-evaluates server-side and stamps the authoritative result.
params._agt.meta.* unknown fields
Every agt.audit.meta.* attribute AGT emitted, prefix stripped, preserved verbatim. Forward-compatible with future AGT versions.
Authorization: Bearer pvk_… transport
Standard agent key issued from the Provedit console. Set as a header on your OTel Collector's otlphttp exporter. Scoped per tenant, revocable, rotatable.

Questions worth askingfaq

Does this duplicate AGT? Why not just use one?

No, it pairs with it. AGT runs policy in-process where it has the richest context. Provedit runs policy out-of-process where the agent host cannot reach it. The pair gives you defence in depth and a record that survives the agent host being wrong, compromised, or just gone.

Do I have to run a second policy? What if I just want the chain?

Bind the agent key to the built-in agt.observe policy when you mint it. Every AGT record then commits to the chain with policyDecision: allow, AGT's own verdict preserved under params._agt.decision. No re-evaluation, no disagreement signal, just the tamper-evident system of record. Pick provedit.mcp.default (or your own policy) when you do want Provedit's second opinion stamped alongside AGT's. More on the policy choice →

What happens if Provedit is unreachable?

Your OTel Collector queues and retries with exponential backoff (a built-in capability of otlphttp; configure sending_queue and retry_on_failure). AGT keeps running. We do not gate tool calls on the network, because AGT already gated them; we're the system of record, not the gate.

Can the verdict mismatch be reconciled?

Yes. Both verdicts are on the chain (policyDecision is Provedit's; params._agt.decision is AGT's), so disagreements are queryable in the timeline and the audit export. Mismatches are usually one of three things: a policy you changed in Provedit but not in AGT, an attribute Provedit knows about that AGT does not (rate ceilings, customer tier, recent incident state), or genuine drift you want to know about. The OTLP receiver never opens an approval workflow on mismatch, because the action already ran inside AGT; the mismatch is a finding, not a ticket.

How is the chain verified?

A separate open-source verifier (@provedit/verifier) replays the chain from public bundle endpoints and recomputes every hash. Anyone with the bundle URL can run it; you do not need Provedit to be online. See Verify the chain.

Where does this map to regulation?

EU AI Act Articles 12 (record-keeping) and 19 (post-market monitoring), ISO/IEC 42001 controls on operational logging and incident traceability, and NIST AI RMF's Govern / Manage functions. Provedit is one defensible implementation path, not a mandated control.

Add the second authority.

Free up to 5 agents. No card. Live in ten minutes, including the AGT wiring.