Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/microsoft/agent-governance-toolkit/llms.txt

Use this file to discover all available pages before exploring further.

Every action an AI agent takes — tool calls, policy decisions, trust handshakes — must be recorded in a tamper-proof log. Without it, you cannot answer the question every auditor asks: “What exactly did this agent do, and who authorized it?” AGT records every governance decision with full context: what policy was active, what the agent requested, the rule that matched, and the outcome. Each entry is hash-chained to its predecessor, making retroactive modification immediately detectable. This page covers the audit entry structure, the Merkle chain integrity mechanism, the Decision BOM, the pluggable GovernanceEventSink, export formats, and compliance framework mapping.

Audit Entry Structure

Agent OS Audit Entry

The base audit entry captures a single governance decision:
FieldTypeRequiredDescription
timestampstring (ISO 8601 UTC)RequiredWhen the event occurred
event_typestringRequiredCategory of the audit event (e.g., governance_decision)
agent_idstringRequiredIdentifier of the agent that triggered the event
actionstringRequiredThe action being audited
decisionstringRequiredGovernance decision outcome: allow, deny, escalate, warn
reasonstringOptionalHuman-readable explanation of the decision
latency_msfloatOptionalTime in milliseconds to reach the decision
metadatadictOptionalArbitrary key-value pairs for extension data

Agent Mesh Audit Entry

The full mesh-level entry adds chain integrity fields and cross-component correlation:
FieldTypeDescription
entry_idstringUnique identifier — format: audit_{uuid4_hex[:16]}
timestampdatetime (UTC)Entry creation time
event_typestringCategory of the audit event
agent_didstringDID of the acting agent
actionstringThe action being audited
resourcestringTarget resource of the action
datadictAdditional structured data
outcomestringResult: success, failure, denied, error
policy_decisionstringPolicy engine decision
matched_rulestringRule that matched
policy_versionstringVersion of the policy bundle that produced this decision
previous_hashstringHash of the previous entry in the chain
entry_hashstringSHA-256 hash of this entry’s canonical form
trace_idstringOTel trace ID for distributed correlation
session_idstringSession scope identifier
arguments_hashstringSHA-256 hash of the action arguments (tamper defense)
approver_didstringDID of the principal whose approval authorized this action
from agentmesh.governance.audit import AuditLog

audit = AuditLog()

entry = audit.log(
    event_type="tool_invocation",
    agent_did="did:web:sales-assistant.example.com",
    action="allow",
    resource="/crm/contacts",
    data={"tool": "crm_lookup", "query": "acme corp"},
    outcome="success",
    trace_id="trace-7f3a",
)

print(entry.entry_id)     # unique UUID-based ID
print(entry.entry_hash)   # SHA-256 hash of the entry
print(entry.timestamp)    # UTC datetime
Event types:
Event TypeWhen
tool_invocationAgent successfully called a tool
tool_blockedPolicy denied a tool call
policy_evaluationPolicy engine evaluated a request
policy_violationAgent violated a governance policy
rogue_detectionAnomaly detection flagged an agent
agent_invocationAgent-to-agent delegation occurred
trust_handshakeIATP handshake performed

Entry Hash Computation

The entry hash is computed deterministically so any modification is detectable:
  1. Construct a dictionary with exactly: entry_id, timestamp (ISO format), event_type, agent_did, action, resource, data, outcome, previous_hash.
  2. Serialize to JSON with keys sorted alphabetically and no extra whitespace.
  3. Compute SHA-256 of the UTF-8 encoded JSON bytes.
  4. Encode as lowercase hexadecimal string.
All hash comparisons use timing-safe hmac.compare_digest to prevent timing side-channel attacks.

Decision BOM (Bill of Materials)

The Decision BOM enables post-hoc reconstruction of all inputs, context, and outputs that contributed to a governance decision. This supports regulatory audits, incident investigation, and reproducible compliance evidence. Every Decision BOM is assembled in four phases:
1

Phase 1 — Audit Query

Query the AuditSource for events within a ±5-second window around the decision timestamp, filtered by trace ID or agent ID.
2

Phase 2 — Trust Enrichment

Query the TrustSource for the agent’s trust score at decision time and recent score history.
3

Phase 3 — Policy Enrichment

Query the PolicySource for policy evaluations associated with the trace, and active policies at the time of decision.
4

Phase 4 — Trace Enrichment

Query the TraceSource for OpenTelemetry spans associated with the trace ID.

BOM Field Categories

CategoryDescription
IDENTITYAgent identity and authentication information
TRUSTTrust scores, reputation, and vouching data
POLICYPolicy rules, evaluations, and configurations
ACTIONThe requested action and its parameters
CONTEXTEnvironmental context (session, trace, resources)
OUTCOMEDecision result and enforcement actions
LINEAGECausal chain and delegation history

Required BOM Fields

Every Decision BOM must include:
Field NameCategoryDescription
agent_identityIDENTITYThe verified identity of the acting agent
trust_score_at_decisionTRUSTThe agent’s trust score at decision time
policy_rules_evaluatedPOLICYList of policy rules that were evaluated
action_typeACTIONThe type of action requested
decision_outcomeOUTCOMEThe final governance decision
The completeness_score (0.0–1.0) indicates the fraction of required fields that were successfully populated.

Decision BOM Schema

FieldTypeDescription
decision_idstringUnique identifier for this BOM
timestampdatetime (UTC)When the decision was made
agent_idstringAgent that requested the action
action_requestedstringWhat action was requested
outcomestringDecision outcome (allow/deny/escalate/warn)
fieldslist[BOMField]All collected BOM fields with source and confidence
reconstructed_atdatetime (UTC)When this BOM was reconstructed
sources_queriedlist[string]Data sources that were consulted
completeness_scorefloatScore (0.0–1.0) indicating data completeness

Merkle Chain

Every entry in AuditLog is added to an internal MerkleAuditChain. The chain builds a Merkle tree over all entries:
        Root Hash
       /         \
    H(AB)       H(CD)
   /    \      /    \
  H(A)  H(B) H(C)  H(D)   ← leaf = SHA-256 of entry
Key properties:
  • Append-only: entries cannot be removed or reordered.
  • Tamper-evident: changing any entry changes the root hash, and all subsequent hashes become invalid.
  • Efficient proofs: proving an entry exists requires O(log n) hashes, not the full log.

Verifying the Chain

# Full integrity check — recomputes all hashes
is_valid, error = audit.verify_integrity()
print(f"Chain valid: {is_valid}")

# Get the Merkle root (publish this for external auditors)
root = audit._chain.get_root_hash()
print(f"Merkle root: {root}")

# Prove a specific entry is in the log
proof = audit.get_proof(entry.entry_id)
print(proof["entry"])          # the AuditEntry
print(proof["merkle_root"])    # current Merkle root hash
print(proof["merkle_proof"])   # list of (hash, position) tuples
print(proof["verified"])       # True if the proof checks out

External Proof Verification

A third party who only has the root hash can verify inclusion without the full log:
from agentmesh.governance.audit import MerkleAuditChain

verified = MerkleAuditChain.verify_proof(
    entry_hash="abc123...",
    proof=[("def456...", "left"), ("789aaa...", "right")],
    root_hash="expected-root...",
)
print(f"Entry in log: {verified}")
To verify a proof:
  1. Start with the entry’s hash.
  2. For each (sibling_hash, position): if left, compute SHA-256(sibling || current); if right, compute SHA-256(current || sibling).
  3. Compare the final hash against the known root hash.

Commitment Anchoring

The Commitment Engine produces summary records that anchor a session’s delta chain, enabling third-party verification without requiring access to the full delta history.
from hypervisor.audit.commitment_engine import CommitmentEngine

engine = CommitmentEngine()

# Commit the current chain state
record = engine.commit(session_id="session-001", delta_engine=delta_engine)
print(record.hash_chain_root)     # root hash of the session's delta chain
print(record.delta_count)         # number of deltas committed
print(record.committed_at)        # UTC timestamp

# Later: verify the session hasn't been tampered with
is_valid = engine.verify(session_id="session-001", delta_engine=delta_engine)
print(is_valid)  # True if root hashes match

# Queue for batch external anchoring
engine.queue_for_batch()
engine.flush_batch()    # publishes hashes to configured external store
The CommitmentRecord schema:
FieldTypeDescription
session_idstringThe session being committed
hash_chain_rootstringRoot hash of the session’s delta chain
participant_didslist[string]DIDs of all agents in the session
delta_countintNumber of deltas in the committed chain
committed_atdatetime (UTC)Timestamp of commitment creation
blockchain_tx_idstring or NoneExternal blockchain transaction ID
committed_tostringWhere the commitment was anchored (default: "local")

GovernanceEventSink

GovernanceEventSink is the pluggable interface for routing governance events to external systems. Any object implementing emit(), shutdown(), and force_flush() can serve as a sink — no inheritance required (structural typing).
from agent_os.event_sink import GovernanceEventSink

class GovernanceEventSink(Protocol):
    def emit(self, events: Sequence[GovernanceEvent]) -> SinkExportResult:
        """Export a batch of governance events. MUST NOT raise exceptions."""
        ...

    def shutdown(self, timeout_ms: int = 5000) -> bool:
        """Gracefully shut down. Returns True if completed within timeout."""
        ...

    def force_flush(self, timeout_ms: int = 30000) -> bool:
        """Force immediate flush. Returns True if completed within timeout."""
        ...
Export result codes:
CodeValueDescription
SUCCESS0Events were successfully exported
FAILURE1Export failed; events may be retried
DROPPED2Events were intentionally dropped (e.g., circuit breaker open)

Built-in Sinks

JSONL File Sink

Writes one JSON object per line to a .jsonl file with 0o600 permissions (owner read/write only). Thread-safe with a lock on writes.

OTel Logs Backend

Emits audit entries as OTel LogRecords with the agt.* attribute namespace. No-op if the OpenTelemetry SDK is not installed.

In-Memory Backend

Stores entries in a Python list. For testing and development only — not for production.

REST API Sink

Submits entries to the Audit Collector REST API (POST /api/v1/audit/log). For centralized multi-agent deployments.

The Event Processor

The GovernanceEventProcessor runs a background daemon thread that batches events and exports them to all registered sinks. It implements circuit-breaker semantics: after 5 consecutive export failures, the breaker opens and skips export for 60 seconds before attempting again.
from agent_os.event_sink import GovernanceEventProcessor

processor = GovernanceEventProcessor(
    max_queue_size=1024,         # AGT_GSP_MAX_QUEUE_SIZE
    schedule_delay_ms=2000,      # AGT_GSP_SCHEDULE_DELAY_MS
    max_batch_size=100,          # AGT_GSP_MAX_BATCH_SIZE
    export_timeout_ms=10000,     # AGT_GSP_EXPORT_TIMEOUT_MS
)

processor.start()
processor.emit(event)
processor.force_flush()
processor.shutdown(timeout_ms=5000)
When the queue is full, the DROP_OLDEST policy applies: the oldest event is removed to make room for the new one, and the drop count is incremented.

Custom Sink Example

import os
from agentmesh.governance.audit import AuditEntry, AuditLog

class PostgresSink:
    """Push audit entries to a PostgreSQL table.

    Implements the AuditSink protocol from agentmesh.governance.audit_backends.
    """

    def __init__(self, dsn: str):
        import psycopg2
        self._conn = psycopg2.connect(dsn)

    def write(self, entry: AuditEntry) -> None:
        with self._conn.cursor() as cur:
            cur.execute(
                """
                INSERT INTO audit_log
                    (entry_id, timestamp, event_type, agent_did,
                     action, resource, outcome, entry_hash, trace_id)
                VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
                """,
                (
                    entry.entry_id,
                    entry.timestamp.isoformat(),
                    entry.event_type,
                    entry.agent_did,
                    entry.action,
                    entry.resource,
                    entry.outcome,
                    entry.entry_hash,
                    entry.trace_id,
                ),
            )
            self._conn.commit()

    def write_batch(self, entries: list[AuditEntry]) -> None:
        for entry in entries:
            self.write(entry)

    def verify_integrity(self) -> tuple[bool, str | None]:
        return True, None  # delegate to AuditLog.verify_integrity()

    def close(self) -> None:
        self._conn.close()

# Use it
sink = PostgresSink(dsn=os.environ["DATABASE_URL"])
audit = AuditLog(sink=sink)

Export Formats

Plain Dictionary Export

from datetime import datetime, timezone, timedelta

now = datetime.now(timezone.utc)
one_hour_ago = now - timedelta(hours=1)

data = audit.export(start_time=one_hour_ago, end_time=now)
print(data["entries"])    # list of entry dicts
print(data["metadata"])   # chain metadata including Merkle root

CloudEvents Envelope

Audit entries can be exported as CloudEvents v1.0 envelopes for routing to CNCF-compatible event infrastructure:
events = audit.export_cloudevents(start_time=one_hour_ago)
for ce in events:
    print(ce["type"])    # e.g., "ai.agentmesh.tool.invoked"
    print(ce["source"])  # agent DID
    print(ce["data"])    # serialized entry content
CloudEvents type mapping:
Event TypeCloudEvents Type
tool_invocationai.agentmesh.tool.invoked
tool_blockedai.agentmesh.tool.blocked
policy_evaluationai.agentmesh.policy.evaluation
identity_verificationai.agentmesh.identity.verified
data_accessai.agentmesh.data.accessed
delegationai.agentmesh.delegation.created
CloudEvents extensions for chain integrity:
ExtensionDescription
agentmeshentryhashCryptographic hash of the entry
agentmeshprevioushashHash chain link (previous entry hash)
traceidOTel trace correlation
sessionidSession correlation

Compliance Mapping

AGT maps governance controls to four compliance frameworks out of the box:

OWASP ASI 2026

The agt verify CLI checks all 10 OWASP Agentic Security Issues. Outputs a human-readable summary, JSON report, or Shields.io badge.

SOC 2

SOC2-CC6.1 (Access Control) and SOC2-CC7.2 (System Monitoring) are satisfied by AGT’s identity verification, policy logging, anomaly detection, and tamper-evident audit trail.

NIST AI RMF

Risk management, transparency, and monitoring requirements map to AGT’s trust scoring, Decision BOM, and compliance engine.

EU AI Act / GDPR

EUAI-ART9 (Risk Management), EUAI-ART13 (Transparency), GDPR-ART5 (Data Principles), and GDPR-ART22 (Automated Decisions) are addressed by the compliance engine.

Verifying OWASP ASI Coverage

# Human-readable summary
agt verify

# Machine-readable JSON for CI/CD
agt verify --json > asi_report.json

# Shields.io badge for your README
agt verify --badge
OWASP ASI 2026 Governance Verification
=======================================
✅ ASI-01  Prompt Injection         PolicyInterceptor
✅ ASI-02  Insecure Tool Use        ToolAliasRegistry
✅ ASI-03  Excessive Agency          GovernancePolicy
✅ ASI-04  Unauthorized Escalation   EscalationPolicy
✅ ASI-05  Trust Boundary Violation  CardRegistry
✅ ASI-06  Insufficient Logging      AuditChain
✅ ASI-07  Insecure Identity         AgentIdentity
✅ ASI-08  Policy Bypass             PolicyConflictResolver
✅ ASI-09  Supply Chain Integrity    IntegrityVerifier
✅ ASI-10  Behavioral Anomaly        ComplianceEngine

Coverage: 10/10 (100%)

Programmatic Compliance Verification

from agent_compliance.verify import GovernanceVerifier
from agent_compliance.integrity import IntegrityVerifier

# OWASP ASI coverage
verifier = GovernanceVerifier()
attestation = verifier.verify()

print(f"Passed:   {attestation.passed}")
print(f"Coverage: {attestation.coverage_pct()}%")
print(f"Hash:     {attestation.attestation_hash}")
print(attestation.summary())

# Supply chain integrity — SHA-256 file hashes + critical function bytecode hashes
integrity = IntegrityVerifier(manifest_path="integrity.json")
report = integrity.verify()
print(report.summary())

Generating a Compliance Report

import json
from datetime import datetime, timezone, timedelta
from pathlib import Path
from agentmesh.governance.audit import AuditLog
from agent_compliance.verify import GovernanceVerifier

def generate_compliance_report(audit: AuditLog, days: int = 30) -> dict:
    now = datetime.now(timezone.utc)
    start = now - timedelta(days=days)

    export = audit.export(start_time=start, end_time=now)
    entries = export["entries"]

    chain_valid, chain_error = audit.verify_integrity()
    attestation = GovernanceVerifier().verify()

    report = {
        "report_generated": now.isoformat(),
        "period_start": start.isoformat(),
        "period_end": now.isoformat(),
        "audit_trail": {
            "total_entries": len(entries),
            "chain_integrity_valid": chain_valid,
            "chain_integrity_error": chain_error,
            "merkle_root": audit._chain.get_root_hash(),
        },
        "owasp_asi_2026": {
            "passed": attestation.passed,
            "controls_passed": attestation.controls_passed,
            "controls_total": attestation.controls_total,
            "coverage_pct": attestation.coverage_pct(),
            "attestation_hash": attestation.attestation_hash,
        },
    }

    Path("compliance_report.json").write_text(
        json.dumps(report, indent=2, default=str), encoding="utf-8"
    )
    return report

CI/CD Compliance Gate

# .github/workflows/compliance.yml
name: Governance Compliance

on:
  push:
    branches: [main]
  pull_request:

jobs:
  compliance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Install governance packages
        run: pip install agentmesh-platform agent-governance-toolkit

      - name: Generate integrity manifest
        run: agt integrity --generate integrity.json

      - name: Verify OWASP ASI 2026 coverage
        run: agt verify --json > asi_report.json

      - name: Verify supply-chain integrity
        run: agt integrity --manifest integrity.json --json > integrity_report.json

      - name: Upload compliance artifacts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: compliance-reports
          path: |
            asi_report.json
            integrity_report.json
            integrity.json
agt verify exits with code 1 if any control is missing, so the pipeline step fails automatically when governance coverage drops.

Querying the Audit Trail

from datetime import datetime, timezone, timedelta

now = datetime.now(timezone.utc)
yesterday = now - timedelta(days=1)

# Find all denied tool calls in the last 24 hours
denied = audit.query(
    event_type="tool_blocked",
    outcome="denied",
    start_time=yesterday,
    limit=200,
)
print(f"Blocked {len(denied)} tool calls in the last 24h")

# Investigate a specific agent
agent = "did:web:support-bot.example.com"
violations = audit.query(agent_did=agent, event_type="policy_violation")
alerts = audit.query(agent_did=agent, event_type="rogue_detection")

# Single-entry lookup
entry = audit.get_entry(entry_id="some-uuid-here")

# Convenience shortcuts
agent_entries = audit.get_entries_for_agent(agent, limit=200)
all_violations = audit.get_entries_by_type("policy_violation", limit=50)

Build docs developers (and LLMs) love