Skip to content
AgentField
Governance

Audit & Observability

Execution notes, correlation IDs, DAG visualization, Prometheus metrics, and structured logging

Tamper-proof audit trails for every execution

Five audit layers -- from developer notes to tamper-proof cryptographic trails -- built into every agent, every execution, every workflow.

Logs alone are not enough for agent systems. You need to know what ran, why it ran, how it branched, what it touched, and how to prove the record was not tampered with.

AgentField ships enterprise-grade observability without bolting anything on: (1) structured execution notes with tags and risk scoring, (2) correlation IDs that trace a request across every agent it touches, (3) DAG visualization of the full multi-agent call graph, (4) Prometheus metrics for queue depth, step latency, retries, and backpressure, and (5) DID-signed verifiable credentials for tamper-evident audit trails.

Minimal code can produce a much richer audit surface than ordinary application logging:

{
  "workflow_id": "wf_d4e5f6",
  "execution_id": "exec_a1b2c3",
  "target": "reviewer.review_contract",
  "notes": ["Reviewing contract #42", "HIGH RISK: score=0.91"],
  "children": [
    { "target": "policy.check_clause", "status": "completed" }
  ]
}

What just happened

The example produced more than logs: notes for human context, correlation IDs for traceability, a DAG for workflow structure, metrics for operations, and signed artifacts for proof. That is the audit story to keep visible: one execution yields multiple layers of evidence, not just one text stream.

{
  "notes": "human-readable context",
  "correlation_ids": "execution_and_workflow_scope",
  "dag": "call_graph",
  "metrics": "operational_signals",
  "credentials": "tamper_evident_proof"
}
from pydantic import BaseModel

class ContractReview(BaseModel):
    risk_score: float
    summary: str

@app.reasoner()
async def review_contract(contract: dict, execution_context=None) -> dict:
    ctx = execution_context

    # Layer 1: Structured notes — tagged for filtering, streamable via SSE
    app.note(f"Reviewing contract #{contract['id']}", ["compliance", "intake"])

    result = await app.ai(
        system="Review this contract for risk.",
        user=str(contract),
        schema=ContractReview,
    )

    # Layer 1 continued: Risk-scored notes for alerting pipelines
    if result.risk_score > 0.8:
        app.note(
            f"HIGH RISK: contract #{contract['id']} score={result.risk_score}",
            ["alert", "risk", "compliance"],
        )

    # Layer 2: Correlation IDs propagate automatically across every cross-agent call
    # This execution carries: execution_id, workflow_id, session_id, actor_id
    # → Every sub-agent call inherits the same workflow_id for end-to-end tracing

    app.note(f"Contract #{contract['id']} review complete", ["compliance", "complete"])
    return result.model_dump()

# Layers 3-5 require zero application code:
# → GET /api/ui/v1/workflows/{wf_id}/dag       — full call graph with depth + timing
# → GET /metrics                                — Prometheus: queue_depth, step_duration, retries
# → VCs signed by agent DIDs                    — tamper-evident proof of what happened
import { z } from 'zod';

const ContractReview = z.object({
  riskScore: z.number(),
  summary: z.string(),
});

agent.reasoner('reviewContract', async (ctx) => {
  // Layer 1: Structured notes — tagged, filterable, streamable via SSE
  ctx.note(`Reviewing contract #${ctx.input.contract.id}`, ['compliance', 'intake']);

  const result = await ctx.ai(
    `Review this contract for risk: ${JSON.stringify(ctx.input.contract)}`,
    { schema: ContractReview },
  );

  // Risk-scored notes feed alerting pipelines
  if (result.riskScore > 0.8) {
    ctx.note(`HIGH RISK: #${ctx.input.contract.id} score=${result.riskScore}`, ['alert', 'risk']);
  }

  // Layer 2: Correlation IDs (executionId, workflowId, sessionId, actorId)
  // propagate automatically across every cross-agent call
  ctx.note(`Contract #${ctx.input.contract.id} complete`, ['compliance', 'complete']);
  return result;
});

// Layers 3-5 require zero application code — DAG, Prometheus, VCs all built-in
a.RegisterReasoner("review_contract", func(ctx context.Context, input map[string]any) (any, error) {
    // Layer 1: Structured notes — fire-and-forget helper from the SDK
    a.Note(ctx, "Reviewing contract", "compliance", "intake")

    // Layer 2: Correlation IDs propagate automatically via context
    // Layers 3-5: DAG, Prometheus, VCs — zero application code required
    return input, nil
})
# Layer 1: Query notes by tag — find every risk alert across all executions
curl "http://localhost:8080/api/v1/executions/exec_a1b2c3/notes?tags=alert,risk"

# Layer 2: Stream notes in real-time (SSE — perfect for live dashboards)
curl -N http://localhost:8080/api/ui/v1/workflows/wf_d4e5f6/notes/events

# Layer 3: Full workflow DAG — every agent call, depth, timing, status
curl http://localhost:8080/api/ui/v1/workflows/wf_d4e5f6/dag
# → { "total_nodes": 5, "max_depth": 3, "dag": { "children": [...] }, "timeline": [...] }

# Layer 4: Prometheus metrics — queue depth, step latency, retries, backpressure
curl http://localhost:8080/metrics
# → agentfield_step_duration_seconds{status="succeeded"} ...
# → agentfield_gateway_queue_depth ...
# → agentfield_step_retries_total{agent="reviewer"} ...

# Layer 5: Tamper-evident trails via DID-signed VCs (see Identity & Credentials docs)