Skip to content

Tutorial 22 โ€” Go module (agentmesh)

Build governance-aware AI agents in Go. The agentmesh module provides Ed25519 cryptographic identity, trust scoring, declarative policy evaluation, and hash-chain audit logging โ€” all in a single go get.

Target runtime: Go 1.21+ Module: github.com/microsoft/agent-governance-toolkit/agent-governance-golang Package: agentmesh


What you'll learn

Section Topic
Quick Start Evaluate a policy in 5 lines of Go
AgentMeshClient Unified governance pipeline โ€” identity + trust + policy + audit
PolicyEngine Declarative rules, YAML policies, rate limiting, approval
TrustManager Trust scoring with decay, tiers, and file persistence
AuditLogger Hash-chain audit logging and verification
AgentIdentity Ed25519 key pairs, DIDs, signing, JSON serialisation
Loading Policies from YAML File-based policy configuration
Full Governance Pipeline End-to-end example
Cross-Reference Equivalent Python and TypeScript tutorials
Next Steps Where to go from here

Prerequisites


Installation

go get github.com/microsoft/agent-governance-toolkit/agent-governance-golang

The module has a single external dependency โ€” gopkg.in/yaml.v3 for YAML policy parsing.

# Verify the install
go list -m github.com/microsoft/agent-governance-toolkit/agent-governance-golang

Quick Start

Five lines to create a governed agent:

package main

import (
    "fmt"
    agentmesh "github.com/microsoft/agent-governance-toolkit/agent-governance-golang"
)

func main() {
    client, err := agentmesh.NewClient("my-agent")
    if err != nil {
        panic(err)
    }

    result, _ := client.ExecuteWithGovernance("data.read", nil)
    fmt.Println("Allowed:", result.Allowed)     // true
    fmt.Println("Decision:", result.Decision)    // allow
}

When no policy rules are provided, the default decision is deny โ€” secure by default.

Or configure at creation with functional options:

client, err := agentmesh.NewClient("my-agent",
    agentmesh.WithCapabilities([]string{"data.read", "data.write"}),
    agentmesh.WithPolicyRules([]agentmesh.PolicyRule{
        {Action: "data.read",  Effect: agentmesh.Allow},
        {Action: "data.write", Effect: agentmesh.Allow},
        {Action: "*",          Effect: agentmesh.Deny},
    }),
)

AgentMeshClient

AgentMeshClient is the recommended entry point. It wires together identity, trust, policy, and audit into a single governance-aware pipeline.

Creating a Client

// Default client โ€” generates identity, no policy rules (deny-all)
client, err := agentmesh.NewClient("analyst-001")

// Client with functional options
client, err := agentmesh.NewClient("analyst-001",
    agentmesh.WithCapabilities([]string{"data.read", "search"}),
    agentmesh.WithTrustConfig(agentmesh.TrustConfig{
        InitialScore:  0.8,
        DecayRate:     0.01,
        RewardFactor:  1.0,
        PenaltyFactor: 1.5,
        TierThresholds: agentmesh.TierThresholds{High: 0.8, Medium: 0.5},
    }),
    agentmesh.WithPolicyRules([]agentmesh.PolicyRule{
        {Action: "data.read", Effect: agentmesh.Allow},
        {Action: "*",         Effect: agentmesh.Deny},
    }),
)

Functional Options

Option Description
WithCapabilities([]string) Set capabilities on the generated identity
WithTrustConfig(TrustConfig) Override default trust configuration
WithPolicyRules([]PolicyRule) Set initial policy rules

Accessing Components

// Identity
fmt.Println("DID:", client.Identity.DID)
fmt.Println("Capabilities:", client.Identity.Capabilities)

// Trust
score := client.Trust.GetTrustScore(client.Identity.DID)
fmt.Println("Trust:", score.Overall, "Tier:", score.Tier)

// Audit
fmt.Println("Chain valid:", client.Audit.Verify())

The Governance Pipeline

ExecuteWithGovernance runs the full pipeline: evaluate โ†’ log โ†’ trust update.

result, err := client.ExecuteWithGovernance("data.read", nil)

fmt.Println("Allowed:", result.Allowed)
fmt.Println("Decision:", result.Decision)
fmt.Println("Trust:", result.TrustScore.Overall)
fmt.Println("Audit hash:", result.AuditEntry.Hash)

When the decision is Allow, trust increases. When it's Deny, trust decreases. The audit entry is always appended to the chain.


PolicyEngine

The PolicyEngine evaluates actions against a set of rules. Rules are evaluated in order; first match wins. The default decision when no rule matches is Deny.

ยง3.1 Policy Rules

rules := []agentmesh.PolicyRule{
    {Action: "data.read",   Effect: agentmesh.Allow},
    {Action: "data.write",  Effect: agentmesh.Allow},
    {Action: "deploy.*",    Effect: agentmesh.Review},
    {Action: "shell.*",     Effect: agentmesh.Deny},
    {Action: "*",           Effect: agentmesh.Deny},  // catch-all
}

engine := agentmesh.NewPolicyEngine(rules)

fmt.Println(engine.Evaluate("data.read", nil))   // allow
fmt.Println(engine.Evaluate("shell.exec", nil))   // deny
fmt.Println(engine.Evaluate("deploy.prod", nil))  // review
fmt.Println(engine.Evaluate("unknown", nil))       // deny (catch-all)

ยง3.2 Decision Types

Decision Constant Description
Allow agentmesh.Allow Action is permitted
Deny agentmesh.Deny Action is blocked
Review agentmesh.Review Action requires human review
Rate Limit agentmesh.RateLimit Action is rate-limited
Requires Approval agentmesh.RequiresApproval Action needs explicit approval

ยง3.3 Wildcard Patterns

The engine supports glob-style action matching:

Pattern Matches Does Not Match
* Everything โ€”
data.* data.read, data.write shell.exec
shell.* shell.exec, shell.ls data.read
data.read data.read (exact) data.write

ยง3.4 Conditional Rules

Rules can include conditions matched against a context map:

rules := []agentmesh.PolicyRule{
    {
        Action:     "deploy.*",
        Effect:     agentmesh.Deny,
        Conditions: map[string]interface{}{"environment": "production"},
    },
    {
        Action: "deploy.*",
        Effect: agentmesh.Allow,
    },
}

engine := agentmesh.NewPolicyEngine(rules)

// Production deploys are denied
prodCtx := map[string]interface{}{"environment": "production"}
fmt.Println(engine.Evaluate("deploy.app", prodCtx))  // deny

// Staging deploys are allowed (conditions don't match first rule)
stagingCtx := map[string]interface{}{"environment": "staging"}
fmt.Println(engine.Evaluate("deploy.app", stagingCtx))  // allow

The engine supports $and, $or, $not, and comparison operators ($gt, $gte, $lt, $lte, $ne, $in) in conditions.

ยง3.5 Rate Limiting

Rules with MaxCalls and Window enable per-action rate limiting:

rules := []agentmesh.PolicyRule{
    {
        Action:   "api.call",
        Effect:   agentmesh.Allow,
        MaxCalls: 5,
        Window:   "1m",  // 5 calls per minute
    },
}

engine := agentmesh.NewPolicyEngine(rules)

for i := 0; i < 5; i++ {
    fmt.Println(engine.Evaluate("api.call", nil))  // allow
}
fmt.Println(engine.Evaluate("api.call", nil))  // rate_limit

ยง3.6 Approval Requirements

rules := []agentmesh.PolicyRule{
    {
        Action:       "deploy.production",
        Effect:       agentmesh.Allow,
        MinApprovals: 2,
        Approvers:    []string{"lead", "sre"},
    },
}

engine := agentmesh.NewPolicyEngine(rules)
fmt.Println(engine.Evaluate("deploy.production", nil))  // requires_approval

Loading Policies from YAML

Store policies in version-controlled YAML files:

# policies/governance.yaml
rules:
  - action: "data.read"
    effect: allow
  - action: "data.write"
    effect: allow
    conditions:
      role: admin
  - action: "shell.*"
    effect: deny
  - action: "deploy.*"
    effect: review
  - action: "*"
    effect: deny
engine := agentmesh.NewPolicyEngine(nil)
err := engine.LoadFromYAML("policies/governance.yaml")
if err != nil {
    log.Fatalf("failed to load policy: %v", err)
}

fmt.Println(engine.Evaluate("data.read", nil))  // allow

Rules loaded from YAML are appended to any existing rules.


TrustManager

The TrustManager tracks per-agent trust scores on a 0.0โ€“1.0 scale with configurable tiers, decay, and file persistence.

ยง5.1 Trust Tiers

Tier Score Range Description
low 0.0โ€“0.49 Untrusted or new agent
medium 0.5โ€“0.79 Provisional trust
high 0.8โ€“1.0 Fully trusted

ยง5.2 Basic Usage

tm := agentmesh.NewTrustManager(agentmesh.DefaultTrustConfig())

// New agent starts at 0.5 (medium tier)
score := tm.GetTrustScore("agent-x")
fmt.Println(score.Overall)  // 0.5
fmt.Println(score.Tier)     // medium

// Record successes โ€” trust increases
tm.RecordSuccess("agent-x", 0.05)
tm.RecordSuccess("agent-x", 0.05)
score = tm.GetTrustScore("agent-x")
fmt.Println(score.Overall)  // ~0.59

// Record failure โ€” trust decreases (asymmetric: penalty factor = 1.5ร—)
tm.RecordFailure("agent-x", 0.1)
score = tm.GetTrustScore("agent-x")
fmt.Println(score.Overall, score.Tier)

ยง5.3 Custom Configuration

cfg := agentmesh.TrustConfig{
    InitialScore:  0.8,
    DecayRate:     0.02,
    RewardFactor:  1.0,
    PenaltyFactor: 2.0,
    TierThresholds: agentmesh.TierThresholds{
        High:   0.8,
        Medium: 0.5,
    },
    MinInteractions: 5,
}

tm := agentmesh.NewTrustManager(cfg)
score := tm.GetTrustScore("high-trust-agent")
fmt.Println(score.Overall)  // 0.8
fmt.Println(score.Tier)     // high

ยง5.4 Peer Verification

Verify a peer agent's identity and trust score in one call:

peer, _ := agentmesh.GenerateIdentity("peer-agent", nil)

result, err := tm.VerifyPeer("peer-agent", peer)
fmt.Println("Verified:", result.Verified)
fmt.Println("Score:", result.Score.Overall)

ยง5.5 File Persistence

Enable persistence to survive process restarts:

cfg := agentmesh.TrustConfig{
    PersistPath: "trust-state.json",
    // ... other config ...
}
tm := agentmesh.NewTrustManager(cfg)

// Scores are automatically saved after each update
tm.RecordSuccess("agent-x", 0.05)
// trust-state.json now contains the serialised score state

// On next startup, scores are loaded from disk automatically
tm2 := agentmesh.NewTrustManager(cfg)
score := tm2.GetTrustScore("agent-x")
fmt.Println(score.Overall)  // restored score

AuditLogger

The AuditLogger provides an append-only, hash-chain-linked audit trail. Each entry's SHA-256 hash incorporates the previous entry's hash, creating a tamper-evident chain.

ยง6.1 Logging Events

logger := agentmesh.NewAuditLogger()

entry := logger.Log("agent-001", "data.read", agentmesh.Allow)
fmt.Println("Hash:", entry.Hash)
fmt.Println("Prev:", entry.PreviousHash)  // empty for genesis entry

ยง6.2 Hash-Chain Integrity

logger := agentmesh.NewAuditLogger()

logger.Log("agent-1", "data.read",   agentmesh.Allow)
logger.Log("agent-1", "data.write",  agentmesh.Deny)
logger.Log("agent-2", "report.send", agentmesh.Allow)

// Verify the entire chain
fmt.Println(logger.Verify())  // true

How the chain works:

  Entry 0            Entry 1            Entry 2
  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”       โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  โ”‚ hash: A  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ prev: A  โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ–ถโ”‚ prev: B  โ”‚
  โ”‚ prev: "" โ”‚       โ”‚ hash: B  โ”‚       โ”‚ hash: C  โ”‚
  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜       โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

  hash = SHA-256(timestamp | agentID | action | decision | previousHash)

ยง6.3 Retention Limits

Set MaxEntries to limit memory usage in long-running services:

logger := agentmesh.NewAuditLogger()
logger.MaxEntries = 1000  // keep last 1000 entries

// Old entries are evicted when the limit is exceeded
for i := 0; i < 1500; i++ {
    logger.Log("agent", fmt.Sprintf("action-%d", i), agentmesh.Allow)
}
// Chain still verifies (eviction is chain-aware)
fmt.Println(logger.Verify())  // true

ยง6.4 Filtering and Querying

filter := agentmesh.AuditFilter{
    AgentID: "agent-1",
}
entries := logger.GetEntries(filter)
fmt.Println("Agent-1 entries:", len(entries))

// Filter by decision
deny := agentmesh.Deny
filter = agentmesh.AuditFilter{
    Decision: &deny,
}
denied := logger.GetEntries(filter)
fmt.Println("Denied entries:", len(denied))

ยง6.5 Exporting the Audit Trail

jsonStr, err := logger.ExportJSON()
if err != nil {
    log.Fatal(err)
}
fmt.Println(jsonStr)

AgentIdentity

The AgentIdentity provides Ed25519-based cryptographic identity with DID identifiers and data signing.

ยง7.1 Generating an Identity

identity, err := agentmesh.GenerateIdentity(
    "researcher-agent",
    []string{"data.read", "search"},
)
if err != nil {
    log.Fatal(err)
}

fmt.Println("DID:", identity.DID)                // did:agentmesh:researcher-agent
fmt.Println("Capabilities:", identity.Capabilities)
fmt.Println("Public key:", len(identity.PublicKey), "bytes")  // 32 bytes

ยง7.2 Signing and Verifying

data := []byte("important message")

// Sign
signature, err := identity.Sign(data)
if err != nil {
    log.Fatal(err)
}
fmt.Println("Signature:", len(signature), "bytes")  // 64 bytes

// Verify
fmt.Println("Valid:", identity.Verify(data, signature))  // true

// Tampered data fails
fmt.Println("Tampered:", identity.Verify([]byte("wrong"), signature))  // false

ยง7.3 JSON Serialisation

Export the public portion of an identity for sharing:

jsonBytes, err := identity.ToJSON()
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(jsonBytes))
// {"did":"did:agentmesh:researcher-agent","public_key":"...","capabilities":["data.read","search"]}

// Reconstruct from JSON (public key only)
imported, err := agentmesh.FromJSON(jsonBytes)
fmt.Println("Imported DID:", imported.DID)
fmt.Println("Can verify:", imported.Verify(data, signature))  // true

Full Governance Pipeline

End-to-end example combining all subsystems:

package main

import (
    "fmt"
    "log"

    agentmesh "github.com/microsoft/agent-governance-toolkit/agent-governance-golang"
)

func main() {
    // 1. Create a governed client
    client, err := agentmesh.NewClient("research-agent",
        agentmesh.WithCapabilities([]string{"data.read", "search.web"}),
        agentmesh.WithTrustConfig(agentmesh.TrustConfig{
            InitialScore:  0.5,
            DecayRate:     0.01,
            RewardFactor:  1.0,
            PenaltyFactor: 1.5,
            TierThresholds: agentmesh.TierThresholds{High: 0.8, Medium: 0.5},
        }),
        agentmesh.WithPolicyRules([]agentmesh.PolicyRule{
            {Action: "data.read",  Effect: agentmesh.Allow},
            {Action: "search.*",   Effect: agentmesh.Allow},
            {Action: "data.write", Effect: agentmesh.Review},
            {Action: "*",          Effect: agentmesh.Deny},
        }),
    )
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("Agent DID:", client.Identity.DID)

    // 2. Execute governed actions
    actions := []string{"data.read", "search.web", "data.write", "shell.exec"}
    for _, action := range actions {
        result, _ := client.ExecuteWithGovernance(action, nil)
        status := "โœ… allowed"
        if !result.Allowed {
            status = "โŒ denied"
        }
        fmt.Printf("  %s โ†’ %s (trust: %.2f, tier: %s)\n",
            action, status, result.TrustScore.Overall, result.TrustScore.Tier)
    }

    // 3. Verify audit chain
    fmt.Println("\nAudit chain valid:", client.Audit.Verify())

    // 4. Export audit trail
    jsonStr, _ := client.Audit.ExportJSON()
    fmt.Println("Audit JSON:", jsonStr[:80], "...")
}

Expected output:

Agent DID: did:agentmesh:research-agent
  data.read  โ†’ โœ… allowed (trust: 0.54, tier: medium)
  search.web โ†’ โœ… allowed (trust: 0.59, tier: medium)
  data.write โ†’ โŒ denied  (trust: 0.44, tier: low)
  shell.exec โ†’ โŒ denied  (trust: 0.28, tier: low)

Audit chain valid: true
Audit JSON: [{"timestamp":"2025-07-15T10:30:00Z","agent_id":"did:agentmesh:resear ...

Cross-Reference

Go module feature Python Equivalent Tutorial
PolicyEngine agent_os.policy Tutorial 01 โ€” Policy Engine
TrustManager agent_os.trust Tutorial 02 โ€” Trust & Identity
AuditLogger agent_os.audit Tutorial 04 โ€” Audit & Compliance
AgentIdentity agent_os.identity Tutorial 02 โ€” Trust & Identity
AgentMeshClient AgentMeshClient Tutorial 20 โ€” TypeScript package

Note: The Go module uses a 0.0โ€“1.0 trust scale with three tiers, while the Rust crate uses 0โ€“1000 with five tiers. Both use the same governance concepts and YAML policy format.


Source Files

Component Location
Client + options agent-governance-golang/client.go
Type definitions agent-governance-golang/types.go
PolicyEngine agent-governance-golang/policy.go
TrustManager agent-governance-golang/trust.go
AuditLogger agent-governance-golang/audit.go
AgentIdentity agent-governance-golang/identity.go
Conflict resolution agent-governance-golang/conflict.go
Metrics agent-governance-golang/metrics.go
Tests agent-governance-golang/*_test.go

Next Steps

  • Run the tests to see the module in action:
    cd agent-governance-golang
    go test ./...
    
  • Load YAML policies from the repository's policies/ directory
  • Enable trust persistence with PersistPath to retain scores across restarts
  • Verify audit chains in your CI/CD pipeline โ€” call Verify() as a post-deployment check
  • Explore the Rust crate tutorial (Tutorial 21) for the Rust equivalent
  • Read the Python tutorials (01โ€“04) for detailed governance concepts